diff --git a/.editorconfig b/.editorconfig index 0e6c17e7674..8cf0bd8d62a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,14 @@ root = true +[*] +charset = utf-8 + [*.{cpp,hpp,c,h,java,cc,hh,m,mm,S,md,properties,gmk,m4,ac}] trim_trailing_whitespace = true [Makefile] trim_trailing_whitespace = true + +[src/hotspot/**.{cpp,hpp,h}] +indent_style = space +indent_size = 2 diff --git a/.gitattributes b/.gitattributes index ebb586628c3..5a18aa21d98 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,5 @@ * -text +* encoding=utf-8 *.java diff=java *.c diff=cpp *.h diff=cpp diff --git a/.github/actions/get-bundles/action.yml b/.github/actions/get-bundles/action.yml index aaec9a6d19f..270d15159a0 100644 --- a/.github/actions/get-bundles/action.yml +++ b/.github/actions/get-bundles/action.yml @@ -32,10 +32,16 @@ inputs: debug-suffix: description: 'File name suffix denoting debug level, possibly empty' required: false + static-suffix: + description: 'Static bundle file name suffix' + required: false outputs: jdk-path: description: 'Path to the installed JDK bundle' value: ${{ steps.path-name.outputs.jdk }} + static-jdk-path: + description: 'Path to the installed static JDK bundle' + value: ${{ steps.path-name.outputs.static_jdk }} symbols-path: description: 'Path to the installed symbols bundle' value: ${{ steps.path-name.outputs.symbols }} @@ -61,6 +67,15 @@ runs: path: bundles if: steps.download-bundles.outcome == 'failure' + - name: 'Download static bundles artifact' + id: download-static-bundles + uses: actions/download-artifact@v4 + with: + name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }} + path: bundles + continue-on-error: true + if: ${{ inputs.static-suffix == '-static' }} + - name: 'Unpack bundles' run: | if [[ -e bundles/jdk-${{ inputs.platform }}${{ inputs.debug-suffix }}.zip ]]; then @@ -75,6 +90,20 @@ runs: tar -xf bundles/jdk-${{ inputs.platform }}${{ inputs.debug-suffix }}.tar.gz -C bundles/jdk fi + if [[ '${{ inputs.static-suffix }}' == '-static' ]]; then + if [[ -e bundles/jdk-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}.zip ]]; then + echo 'Unpacking static jdk bundle...' + mkdir -p bundles/static-jdk + unzip -q bundles/jdk-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}.zip -d bundles/static-jdk + fi + + if [[ -e bundles/jdk-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}.tar.gz ]]; then + echo 'Unpacking static jdk bundle...' + mkdir -p bundles/static-jdk + tar -xf bundles/jdk-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}.tar.gz -C bundles/static-jdk + fi + fi + if [[ -e bundles/symbols-${{ inputs.platform }}${{ inputs.debug-suffix }}.tar.gz ]]; then echo 'Unpacking symbols bundle...' mkdir -p bundles/symbols @@ -106,4 +135,12 @@ runs: echo "jdk=$jdk_dir" >> $GITHUB_OUTPUT echo "symbols=$symbols_dir" >> $GITHUB_OUTPUT echo "tests=$tests_dir" >> $GITHUB_OUTPUT + + if [[ '${{ inputs.static-suffix }}' == '-static' ]]; then + static_jdk_dir="$GITHUB_WORKSPACE/$(dirname $(find bundles/static-jdk -name bin -type d))" + if [[ '${{ runner.os }}' == 'Windows' ]]; then + static_jdk_dir="$(cygpath $static_jdk_dir)" + fi + echo "static_jdk=$static_jdk_dir" >> $GITHUB_OUTPUT + fi shell: bash diff --git a/.github/actions/upload-bundles/action.yml b/.github/actions/upload-bundles/action.yml index 30f4ac03c1e..dfa994baac0 100644 --- a/.github/actions/upload-bundles/action.yml +++ b/.github/actions/upload-bundles/action.yml @@ -35,6 +35,9 @@ inputs: bundle-suffix: description: 'Bundle name suffix, possibly empty' required: false + static-suffix: + description: 'Static JDK bundle name suffix, possibly empty' + required: false runs: using: composite @@ -46,6 +49,8 @@ runs: # Rename bundles to consistent names jdk_bundle_zip="$(ls build/*/bundles/jdk-*_bin${{ inputs.debug-suffix }}.zip 2> /dev/null || true)" jdk_bundle_tar_gz="$(ls build/*/bundles/jdk-*_bin${{ inputs.debug-suffix }}.tar.gz 2> /dev/null || true)" + static_jdk_bundle_zip="$(ls build/*/bundles/static-jdk-*_bin${{ inputs.debug-suffix }}.zip 2> /dev/null || true)" + static_jdk_bundle_tar_gz="$(ls build/*/bundles/static-jdk-*_bin${{ inputs.debug-suffix }}.tar.gz 2> /dev/null || true)" symbols_bundle="$(ls build/*/bundles/jdk-*_bin${{ inputs.debug-suffix }}-symbols.tar.gz 2> /dev/null || true)" tests_bundle="$(ls build/*/bundles/jdk-*_bin-tests${{ inputs.debug-suffix }}.tar.gz 2> /dev/null || true)" static_libs_bundle="$(ls build/*/bundles/jdk-*_bin-static-libs${{ inputs.debug-suffix }}.tar.gz 2> /dev/null || true)" @@ -58,6 +63,12 @@ runs: if [[ "$jdk_bundle_tar_gz" != "" ]]; then mv "$jdk_bundle_tar_gz" "bundles/jdk-${{ inputs.platform }}${{ inputs.debug-suffix }}.tar.gz" fi + if [[ "$static_jdk_bundle_zip" != "" ]]; then + mv "$static_jdk_bundle_zip" "bundles/jdk-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}.zip" + fi + if [[ "$static_jdk_bundle_tar_gz" != "" ]]; then + mv "$static_jdk_bundle_tar_gz" "bundles/jdk-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}.tar.gz" + fi if [[ "$symbols_bundle" != "" ]]; then mv "$symbols_bundle" "bundles/symbols-${{ inputs.platform }}${{ inputs.debug-suffix }}.tar.gz" fi @@ -68,7 +79,7 @@ runs: mv "$static_libs_bundle" "bundles/static-libs-${{ inputs.platform }}${{ inputs.debug-suffix }}.tar.gz" fi - if [[ "$jdk_bundle_zip$jdk_bundle_tar_gz$symbols_bundle$tests_bundle$static_libs_bundle" != "" ]]; then + if [[ "$jdk_bundle_zip$jdk_bundle_tar_gz$static_jdk_bundle_zip$static_jdk_bundle_tar_gz$symbols_bundle$tests_bundle$static_libs_bundle" != "" ]]; then echo 'bundles-found=true' >> $GITHUB_OUTPUT else echo 'bundles-found=false' >> $GITHUB_OUTPUT @@ -78,7 +89,7 @@ runs: - name: 'Upload bundles artifact' uses: actions/upload-artifact@v4 with: - name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.bundle-suffix }} + name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }}${{ inputs.static-suffix }}${{ inputs.bundle-suffix }} path: bundles retention-days: 1 if: steps.bundles.outputs.bundles-found == 'true' diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 101668b2bd5..9c991eed419 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -64,6 +64,9 @@ on: bundle-suffix: required: false type: string + static-suffix: + required: false + type: string jobs: build-linux: @@ -143,3 +146,4 @@ jobs: platform: ${{ inputs.platform }} debug-suffix: "${{ matrix.debug-level == 'debug' && '-debug' || '' }}" bundle-suffix: ${{ inputs.bundle-suffix }} + static-suffix: ${{ inputs.static-suffix }} diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index d02ef91ad86..9bb43a8b83c 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -63,7 +63,7 @@ env: jobs: build-windows: name: build - runs-on: windows-2019 + runs-on: windows-2025 defaults: run: shell: bash @@ -102,7 +102,7 @@ jobs: id: toolchain-check run: | set +e - '/c/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/vc/auxiliary/build/vcvars64.bat' -vcvars_ver=${{ inputs.msvc-toolset-version }} + '/c/Program Files/Microsoft Visual Studio/2022/Enterprise/vc/auxiliary/build/vcvars64.bat' -vcvars_ver=${{ inputs.msvc-toolset-version }} if [ $? -eq 0 ]; then echo "Toolchain is already installed" echo "toolchain-installed=true" >> $GITHUB_OUTPUT @@ -115,7 +115,7 @@ jobs: run: | # Run Visual Studio Installer '/c/Program Files (x86)/Microsoft Visual Studio/Installer/vs_installer.exe' \ - modify --quiet --installPath 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise' \ + modify --quiet --installPath 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise' \ --add Microsoft.VisualStudio.Component.VC.${{ inputs.msvc-toolset-version }}.${{ inputs.msvc-toolset-architecture }} if: steps.toolchain-check.outputs.toolchain-installed != 'true' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8dce1d214dc..0e64ad78625 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -231,16 +231,14 @@ jobs: uses: ./.github/workflows/build-linux.yml with: platform: linux-x64 - make-target: 'static-jdk-image' + make-target: 'static-jdk-bundles' # There are issues with fastdebug static build in GHA due to space limit. # Only do release build for now. debug-levels: '[ "release" ]' gcc-major-version: '10' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} - # It currently doesn't produce any bundles, but probably will do in - # the future. - bundle-suffix: "-static" + static-suffix: "-static" if: needs.prepare.outputs.linux-x64 == 'true' build-linux-x64-static-libs: @@ -312,7 +310,7 @@ jobs: uses: ./.github/workflows/build-windows.yml with: platform: windows-x64 - msvc-toolset-version: '14.29' + msvc-toolset-version: '14.43' msvc-toolset-architecture: 'x86.x64' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} @@ -324,7 +322,7 @@ jobs: uses: ./.github/workflows/build-windows.yml with: platform: windows-aarch64 - msvc-toolset-version: '14.29' + msvc-toolset-version: '14.43' msvc-toolset-architecture: 'arm64' make-target: 'hotspot' extra-conf-options: '--openjdk-target=aarch64-unknown-cygwin' @@ -361,6 +359,19 @@ jobs: platform: linux-x64 bootjdk-platform: linux-x64 runs-on: ubuntu-22.04 + debug-suffix: -debug + + test-linux-x64-static: + name: linux-x64-static + needs: + - build-linux-x64 + - build-linux-x64-static + uses: ./.github/workflows/test.yml + with: + platform: linux-x64 + bootjdk-platform: linux-x64 + runs-on: ubuntu-22.04 + static-suffix: "-static" test-macos-aarch64: name: macos-aarch64 @@ -372,6 +383,7 @@ jobs: bootjdk-platform: macos-aarch64 runs-on: macos-14 xcode-toolset-version: '15.4' + debug-suffix: -debug test-windows-x64: name: windows-x64 @@ -381,4 +393,5 @@ jobs: with: platform: windows-x64 bootjdk-platform: windows-x64 - runs-on: windows-2019 + runs-on: windows-2025 + debug-suffix: -debug diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 99aaf9650a0..665ae224372 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -40,6 +40,12 @@ on: xcode-toolset-version: required: false type: string + debug-suffix: + required: false + type: string + static-suffix: + required: false + type: string env: # These are needed to make the MSYS2 bash work properly @@ -86,35 +92,35 @@ jobs: - test-name: 'hs/tier1 common' test-suite: 'test/hotspot/jtreg/:tier1_common' - debug-suffix: -debug + debug-suffix: ${{ inputs.debug-suffix }} - test-name: 'hs/tier1 compiler part 1' test-suite: 'test/hotspot/jtreg/:tier1_compiler_1' - debug-suffix: -debug + debug-suffix: ${{ inputs.debug-suffix }} - test-name: 'hs/tier1 compiler part 2' test-suite: 'test/hotspot/jtreg/:tier1_compiler_2' - debug-suffix: -debug + debug-suffix: ${{ inputs.debug-suffix }} - test-name: 'hs/tier1 compiler part 3' test-suite: 'test/hotspot/jtreg/:tier1_compiler_3' - debug-suffix: -debug + debug-suffix: ${{ inputs.debug-suffix }} - test-name: 'hs/tier1 gc' test-suite: 'test/hotspot/jtreg/:tier1_gc' - debug-suffix: -debug + debug-suffix: ${{ inputs.debug-suffix }} - test-name: 'hs/tier1 runtime' test-suite: 'test/hotspot/jtreg/:tier1_runtime' - debug-suffix: -debug + debug-suffix: ${{ inputs.debug-suffix }} - test-name: 'hs/tier1 serviceability' test-suite: 'test/hotspot/jtreg/:tier1_serviceability' - debug-suffix: -debug + debug-suffix: ${{ inputs.debug-suffix }} - test-name: 'lib-test/tier1' test-suite: 'test/lib-test/:tier1' - debug-suffix: -debug + debug-suffix: ${{ inputs.debug-suffix }} steps: - name: 'Checkout the JDK source' @@ -140,6 +146,7 @@ jobs: with: platform: ${{ inputs.platform }} debug-suffix: ${{ matrix.debug-suffix }} + static-suffix: ${{ inputs.static-suffix }} - name: 'Install dependencies' run: | @@ -160,6 +167,21 @@ jobs: else echo "value=$PATH" >> $GITHUB_OUTPUT fi + if [[ '${{ inputs.static-suffix }}' == '-static' ]]; then + echo "static-hotspot-problemlist-path=`pwd`/test/hotspot/jtreg/ProblemList-StaticJdk.txt" >> $GITHUB_OUTPUT + echo "static-jdk-problemlist-path=`pwd`/test/jdk/ProblemList-StaticJdk.txt" >> $GITHUB_OUTPUT + echo "static-langtools-problemlist-path=`pwd`/test/langtools/ProblemList-StaticJdk.txt" >> $GITHUB_OUTPUT + echo "static-lib-test-problemlist-path=`pwd`/test/lib-test/ProblemList-StaticJdk.txt" >> $GITHUB_OUTPUT + fi + + - name: 'Set Extra Options' + id: extra-options + run: | + if [[ '${{ inputs.static-suffix }}' == '-static' ]]; then + echo "test-jdk=JDK_UNDER_TEST=${{ steps.bundles.outputs.static-jdk-path }}" >> $GITHUB_OUTPUT + echo "compile-jdk=JDK_FOR_COMPILE=${{ steps.bundles.outputs.jdk-path }}" >> $GITHUB_OUTPUT + echo "extra-problem-lists=EXTRA_PROBLEM_LISTS=${{ steps.path.outputs.static-hotspot-problemlist-path }}%20${{ steps.path.outputs.static-jdk-problemlist-path }}%20${{ steps.path.outputs.static-langtools-problemlist-path }}%20${{ steps.path.outputs.static-lib-test-problemlist-path }}" >> $GITHUB_OUTPUT + fi - name: 'Run tests' id: run-tests @@ -171,7 +193,9 @@ jobs: JDK_IMAGE_DIR=${{ steps.bundles.outputs.jdk-path }} SYMBOLS_IMAGE_DIR=${{ steps.bundles.outputs.symbols-path }} TEST_IMAGE_DIR=${{ steps.bundles.outputs.tests-path }} - JTREG='JAVA_OPTIONS=-XX:-CreateCoredumpOnCrash;VERBOSE=fail,error,time;KEYWORDS=!headful' + ${{ steps.extra-options.outputs.test-jdk }} + ${{ steps.extra-options.outputs.compile-jdk }} + JTREG='JAVA_OPTIONS=-XX:-CreateCoredumpOnCrash;VERBOSE=fail,error,time;KEYWORDS=!headful;${{ steps.extra-options.outputs.extra-problem-lists }}' && bash ./.github/scripts/gen-test-summary.sh "$GITHUB_STEP_SUMMARY" "$GITHUB_OUTPUT" env: PATH: ${{ steps.path.outputs.value }} @@ -204,7 +228,7 @@ jobs: echo '::warning ::Missing test-support directory' fi - artifact_name="results-${{ inputs.platform }}-$(echo ${{ matrix.test-name }} | tr '/ ' '__')" + artifact_name="results-${{ inputs.platform }}-$(echo ${{ matrix.test-name }}${{ inputs.static-suffix }} | tr '/ ' '__')" echo "artifact-name=$artifact_name" >> $GITHUB_OUTPUT if: always() diff --git a/.gitignore b/.gitignore index 2d82e0d943c..9145a9fa67b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ NashornProfile.txt /.gdbinit /.lldbinit **/core.[0-9]* +*.rej +*.orig diff --git a/.jcheck/conf b/.jcheck/conf index 6ab5c2d64c2..60881e74d2a 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,7 +1,7 @@ [general] project=jdk jbs=JDK -version=25 +version=26 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists,copyright diff --git a/doc/building.html b/doc/building.html index 1e6f99e97c9..da8465bc532 100644 --- a/doc/building.html +++ b/doc/building.html @@ -282,9 +282,34 @@

Special Considerations

having slow disk access will significantly increase build times. If you need to use a network share for the source code, see below for suggestions on how to keep the build artifacts on a local disk.

-
  • On Windows, if using Cygwin, extra care -must be taken to make sure the environment is consistent. It is -recommended that you follow this procedure:

    +
  • UTF-8 support is needed to compile the JDK. On Unix systems, this +typically means that the C.UTF-8 or +en_US.UTF-8 locale needs to be available. For Windows +users, please see the section on Locale +Requirements below.

  • +
  • On Windows, extra care must be taken to have a smooth building +experience:

    +
  • - -

    Failure to follow this procedure might result in hard-to-debug build -problems.

    +

    Build Hardware Requirements

    The JDK is a massive project, and require machines ranging from @@ -376,7 +402,7 @@

    Operating System macOS -macOS 13.x (Ventura) +macOS 14.x Windows @@ -513,8 +539,8 @@

    macOS

    a continuously updated machine running macOS. See the section on Apple Xcode on some strategies to deal with this.

    -

    It is recommended that you use at least macOS 13 (Ventura) and Xcode -14, but earlier versions may also work.

    +

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

    The standard macOS environment contains the basic tooling needed to build, but for external libraries a package manager is recommended. The JDK uses homebrew in the examples, but @@ -590,11 +616,11 @@

    Native Compiler macOS -Apple Xcode 14.3.1 (using clang 14.0.3) +Apple Xcode 15.4 (using clang 15.0.0) Windows -Microsoft Visual Studio 2022 version 17.6.5 +Microsoft Visual Studio 2022 version 17.13.2 diff --git a/doc/building.md b/doc/building.md index 18e030baa9e..1a9fe6b2e78 100644 --- a/doc/building.md +++ b/doc/building.md @@ -83,19 +83,44 @@ on where and how to check out the source code. for the source code, see below for suggestions on how to keep the build artifacts on a local disk. -* On Windows, if using [Cygwin](#cygwin), extra care must be taken to make sure - the environment is consistent. It is recommended that you follow this - procedure: - - * Create the directory that is going to contain the top directory of the JDK - clone by using the `mkdir` command in the Cygwin bash shell. That is, do - *not* create it using Windows Explorer. This will ensure that it will have - proper Cygwin attributes, and that it's children will inherit those - attributes. - - * Do not put the JDK clone in a path under your Cygwin home directory. This - is especially important if your user name contains spaces and/or mixed - upper and lower case letters. +* UTF-8 support is needed to compile the JDK. On Unix systems, this typically + means that the `C.UTF-8` or `en_US.UTF-8` locale needs to be available. For + Windows users, please see the section on [Locale + Requirements](#locale-requirements) below. + +* On Windows, extra care must be taken to have a smooth building experience: + + * Make sure that all relevant paths have short names. Short names are used by + the build system to create space-free alternative paths. Short name + creation is enabled per volume. The default setting can be checked with the + command: `fsutil 8dot3name query`. If short name creation was turned off + when a directory was created, it will not have a short name. Whether a + short name exists can be checked by running `dir /X` in the containing + directory (in cmd.exe). If a short path is present you should see something + like 'ASDF~1' being displayed in one of the columns of the ouput. If a + directory is missing a short name, the safest way to get one is to enable + short names for that particular volume with `fsutil 8dot3name set : 0` (note that you need to run as administrator for this), and then + re-create the particular directory. A short name should be generated + automatically then. Another option is to manually assign a short name to + the directory using `fsutil file setShortName `. + + * If using [Cygwin](#cygwin), you must make sure the file permissions and + attributes between Windows and Cygwin are consistent. It is recommended + that you follow this procedure: + + * Create the directory that is going to contain the top directory of the + JDK clone by using the `mkdir` command in the Cygwin bash shell. That is, + do *not* create it using Windows Explorer. This will ensure that it will + have proper Cygwin attributes, and that it's children will inherit those + attributes. + + * Do not put the JDK clone in a path under your Cygwin home directory. This + is especially important if your user name contains spaces and/or mixed + upper and lower case letters. + + Failure to follow these procedures might result in hard-to-debug build + problems. * You need to install a git client. You have two choices, Cygwin git or Git for Windows. Unfortunately there are pros and cons with each choice. @@ -113,9 +138,6 @@ on where and how to check out the source code. make sure you set `core.autocrlf` to `false` (this is asked during installation). - Failure to follow this procedure might result in hard-to-debug build - problems. - ## Build Hardware Requirements The JDK is a massive project, and require machines ranging from decent to @@ -175,7 +197,7 @@ time of writing. | ----------------- | ---------------------------------- | | Linux/x64 | Oracle Enterprise Linux 6.4 / 8.x | | Linux/aarch64 | Oracle Enterprise Linux 7.6 / 8.x | -| macOS | macOS 13.x (Ventura) | +| macOS | macOS 14.x | | Windows | Windows Server 2016 | The double version numbers for Linux are due to the hybrid model used at @@ -327,7 +349,7 @@ difficult for a project such as the JDK to keep pace with a continuously updated machine running macOS. See the section on [Apple Xcode](#apple-xcode) on some strategies to deal with this. -It is recommended that you use at least macOS 13 (Ventura) and Xcode 14, but +It is recommended that you use at least macOS 14 and Xcode 15.4, but earlier versions may also work. The standard macOS environment contains the basic tooling needed to build, but @@ -390,11 +412,11 @@ possible to compile the JDK with both older and newer versions, but the closer you stay to this list, the more likely you are to compile successfully without issues. -| Operating system | Toolchain version | -| ------------------ | ------------------------------------------- | -| Linux | gcc 14.2.0 | -| macOS | Apple Xcode 14.3.1 (using clang 14.0.3) | -| Windows | Microsoft Visual Studio 2022 version 17.6.5 | +| Operating system | Toolchain version | +| ------------------ | -------------------------------------------- | +| Linux | gcc 14.2.0 | +| macOS | Apple Xcode 15.4 (using clang 15.0.0) | +| Windows | Microsoft Visual Studio 2022 version 17.13.2 | All compilers are expected to be able to handle the C11 language standard for C, and C++14 for C++. diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index 7e7f4de3629..d4c06fbd6bd 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -32,11 +32,12 @@

    HotSpot Coding Style

    • Introduction
    • Structure and Formatting @@ -99,6 +100,21 @@

      Introduction

      existing HotSpot code, making it easier to read and maintain. Failure to follow these guidelines may lead to discussion during code reviews, if not outright rejection of a change.

      +

      Changing this Document

      +

      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.

      Why Care About Style?

      Some programmers seem to have lexers and even C preprocessors installed directly behind their eyeballs. The rest of us require code @@ -124,7 +140,7 @@

      Why Care About Style?

      reformatting the whole thing. Also consider separating changes that make extensive stylistic updates from those which make functional changes.

      -

      Counterexamples and Updates

      +

      Counterexamples

      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 @@ -137,20 +153,6 @@

      Counterexamples and Updates

      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. 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

        diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index 0a135b2074c..f4348bea51d 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -8,6 +8,24 @@ HotSpot code, making it easier to read and maintain. Failure to follow these guidelines may lead to discussion during code reviews, if not outright rejection of a change. +### Changing this Document + +Proposed changes should be discussed on the +[HotSpot Developers](mailto:hotspot-dev@openjdk.org) 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](https://www.rfc-editor.org/rfc/rfc7282.html) of +the [HotSpot Group](https://openjdk.org/census#hotspot) 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. + ### Why Care About Style? Some programmers seem to have lexers and even C preprocessors @@ -38,7 +56,7 @@ reformatting the whole thing. Also consider separating changes that make extensive stylistic updates from those which make functional changes. -### Counterexamples and Updates +### Counterexamples Many of the guidelines mentioned here have (sometimes widespread) counterexamples in the HotSpot code base. Finding a counterexample is @@ -54,22 +72,6 @@ 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](mailto:hotspot-dev@openjdk.org) 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](https://www.rfc-editor.org/rfc/rfc7282.html) of -the [HotSpot Group](https://openjdk.org/census#hotspot) 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 diff --git a/doc/hotspot-unit-tests.html b/doc/hotspot-unit-tests.html index fcd4a93f8e4..b3700abb3ac 100644 --- a/doc/hotspot-unit-tests.html +++ b/doc/hotspot-unit-tests.html @@ -189,7 +189,7 @@

        Nearness

        Prefer having checks inside test code.

        Not only does having test logic outside, e.g. verification method, depending on asserts in product code contradict with several items above -but also decreases test’s readability and stability. It is much easier +but also decreases test's readability and stability. It is much easier to understand that a test is testing when all testing logic is located inside a test or nearby in shared test libraries. As a rule of thumb, the closer a check to a test, the better.

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

        Several checks

        Prefer EXPECT over ASSERT if possible.

        This is related to the informativeness property of tests, information for other checks can help to better -localize a defect’s root-cause. One should use ASSERT if it +localize a defect's root-cause. One should use ASSERT if it is impossible to continue test execution or if it does not make much sense. Later in the text, EXPECT forms will be used to refer to both ASSERT/EXPECT.

        @@ -235,7 +235,7 @@

        Floating-point comparison

        eps.

        C string comparison

        Use string special macros for C strings comparisons.

        -

        EXPECT_EQ just compares pointers’ values, which is +

        EXPECT_EQ just compares pointers' values, which is hardly what one wants comparing C strings. GoogleTest provides EXPECT_STREQ and EXPECT_STRNE macros to compare C string contents. There are also case-insensitive versions @@ -293,7 +293,7 @@

        Test group names

        This naming scheme helps to find tests, filter them and simplifies test failure analysis. For example, class Foo - test group Foo, compiler logging subsystem - test group -CompilerLogging, G1 GC — test group G1GC, and +CompilerLogging, G1 GC - test group G1GC, and so forth.

        Filename

        A test file must have test_ prefix and .cpp @@ -345,7 +345,7 @@

        Fixture classes

        Friend classes

        All test purpose friends should have either Test or Testable suffix.

        -

        It greatly simplifies understanding of friendship’s purpose and +

        It greatly simplifies understanding of friendship's purpose and allows statically check that private members are not exposed unexpectedly. Having FooTest as a friend of Foo without any comments will be understood as a necessary @@ -435,7 +435,7 @@

        Test-specific flags

        Flag restoring

        Restore changed flags.

        It is quite common for tests to configure JVM in a certain way -changing flags’ values. GoogleTest provides two ways to set up +changing flags' values. GoogleTest provides two ways to set up environment before a test and restore it afterward: using either constructor and destructor or SetUp and TearDown functions. Both ways require to use a test fixture @@ -444,7 +444,7 @@

        Flag restoring

        be used in such cases to restore/set values.

        Caveats:

          -
        • Changing a flag’s value could break the invariants between flags' +

        • Changing a flag's value could break the invariants between flags' values and hence could lead to unexpected/unsupported JVM state.

        • FLAG_SET_* macros can change more than one flag (in diff --git a/doc/starting-next-release.html b/doc/starting-next-release.html new file mode 100644 index 00000000000..421229f9fbc --- /dev/null +++ b/doc/starting-next-release.html @@ -0,0 +1,127 @@ + + + + + + + Explanation of start of release changes + + + + + +

          +

          Explanation of start of release changes

          +
          + +

          Overview

          +

          The start of release changes, the changes that turn JDK N +into JDK (N+1), are primarily small updates to various files +along with new files to store symbol information to allow +javac --release N ... to run on JDK (N+1).

          +

          The updates include changes to files holding meta-data about the +release, files under the src directory for API and tooling +updates, and incidental updates under the test +directory.

          +

          Details and file updates

          +

          As a matter of policy, there are a number of semantically distinct +concepts which get incremented separately at the start of a new +release:

          +
            +
          • Feature value of Runtime.version()
          • +
          • Highest source version modeled by +javax.lang.model.SourceVersion
          • +
          • Highest class file format major version recognized by the +platform
          • +
          • Highest +-source/-target/--release +argument recognized by javac and related tools
          • +
          +

          The expected file updates are listed below. Additional files may need +to be updated for a particular release.

          +

          Meta-data files

          +
            +
          • jcheck/conf: update meta-data used by +jcheck and the Skara tooling
          • +
          • make/conf/version-numbers.conf: update to meta-data +used in the build
          • +
          +

          src files

          +
            +
          • src/hotspot/share/classfile/classFileParser.cpp: add a +#define for the new version
          • +
          • src/java.base/share/classes/java/lang/classfile/ClassFile.java: +add a constant for the new class file format version
          • +
          • src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java: +add an enum constant for the new class file format +version
          • +
          • src/java.compiler/share/classes/javax/lang/model/SourceVersion.java: +add an enum constant for the new source version
          • +
          • src/java.compiler/share/classes/javax/lang/model/util/* +visitors: Update @SupportedSourceVersion annotations to +latest value. Note this update is done in lieu of introducing another +set of visitors for each Java SE release.
          • +
          • src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java: +add an enum constant for the new source version internal to +javac
          • +
          • src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java: +add an enum constant for the new class file format version +internal to javac
          • +
          • src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java: +add an enum constant for the new target version internal to +javac
          • +
          • src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java +update printing processor to support the new source version
          • +
          • The symbol information for --release is stored as new +text files in the src/jdk.compiler/share/data/symbols +directory, one file per module. The README file in that directory +contains directions on how to create the files.
          • +
          +

          test files

          +
            +
          • test/langtools/tools/javac/api/TestGetSourceVersions.java: +add new SourceVersion constant to test matrix.
          • +
          • test/langtools/tools/javac/classfiles/ClassVersionChecker.java: +add new enum constant for the new class file version
          • +
          • test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java +update annotation processor extended by javac tests to +cover the new source version
          • +
          • test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out +and +test/langtools/tools/javac/preview/classReaderTest/Client.preview.out: +update expected messages for preview errors and warnings
          • +
          + + diff --git a/doc/starting-next-release.md b/doc/starting-next-release.md new file mode 100644 index 00000000000..10bc364a3e4 --- /dev/null +++ b/doc/starting-next-release.md @@ -0,0 +1,68 @@ +% Explanation of start of release changes + +## Overview + +The start of release changes, the changes that turn JDK _N_ into JDK +(_N_+1), are primarily small updates to various files along with new files to +store symbol information to allow `javac --release N ...` to run on +JDK (_N_+1). + +The updates include changes to files holding meta-data about the +release, files under the `src` directory for API and tooling updates, +and incidental updates under the `test` directory. + +## Details and file updates + +As a matter of policy, there are a number of semantically distinct +concepts which get incremented separately at the start of a new +release: + +* Feature value of `Runtime.version()` +* Highest source version modeled by `javax.lang.model.SourceVersion` +* Highest class file format major version recognized by the platform +* Highest `-source`/`-target`/`--release` argument recognized by + `javac` and related tools + +The expected file updates are listed below. Additional files may need +to be updated for a particular release. + +### Meta-data files + +* `jcheck/conf`: update meta-data used by `jcheck` and the Skara tooling +* `make/conf/version-numbers.conf`: update to meta-data used in the build + +### `src` files + +* `src/hotspot/share/classfile/classFileParser.cpp`: add a `#define` + for the new version +* `src/java.base/share/classes/java/lang/classfile/ClassFile.java`: + add a constant for the new class file format version +* `src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java`: + add an `enum` constant for the new class file format version +* `src/java.compiler/share/classes/javax/lang/model/SourceVersion.java`: + add an `enum` constant for the new source version +* `src/java.compiler/share/classes/javax/lang/model/util/*` visitors: Update + `@SupportedSourceVersion` annotations to latest value. Note this update + is done in lieu of introducing another set of visitors for each Java + SE release. +* `src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java`: + add an `enum` constant for the new source version internal to `javac` +* `src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java`: + add an `enum` constant for the new class file format version internal to `javac` +* `src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java`: + add an `enum` constant for the new target version internal to `javac` +* `src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java` + update printing processor to support the new source version +* The symbol information for `--release` is stored as new text files in the + `src/jdk.compiler/share/data/symbols` directory, one file per + module. The README file in that directory contains directions on how + to create the files. + +### `test` files + +* `test/langtools/tools/javac/api/TestGetSourceVersions.java`: add new `SourceVersion` constant to test matrix. +* `test/langtools/tools/javac/classfiles/ClassVersionChecker.java`: add new enum constant for the new class file version +* `test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java` + update annotation processor extended by `javac` tests to cover the new source version +* `test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out` and `test/langtools/tools/javac/preview/classReaderTest/Client.preview.out`: update expected messages for preview errors and warnings + diff --git a/doc/testing.html b/doc/testing.html index 6285fab1682..b9d1f4ed22f 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -72,6 +72,11 @@

          Testing the JDK

        • Non-US locale
        • PKCS11 Tests
        • +
        +
      • ### Testing Ahead-of-time +Optimizations +
        • Testing with alternative security providers
        • @@ -411,6 +416,13 @@

          JCOV

          special target jcov-test instead of test, e.g. make jcov-test TEST=jdk_lang. This will make sure the JCov image is built, and that JCov reporting is enabled.

          +

          To include JCov coverage for just a subset of all modules, you can +use the --with-jcov-modules arguments to +configure, e.g. +--with-jcov-modules=jdk.compiler,java.desktop.

          +

          For more fine-grained control, you can pass arbitrary filters to JCov +using --with-jcov-filters, and you can specify a specific +JDK to instrument using --with-jcov-input-jdk.

          The JCov report is stored in build/$BUILD/test-results/jcov-output/report.

          Please note that running with JCov reporting can be very memory @@ -589,6 +601,37 @@

          PKCS11 Tests

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

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

          +

          ### Testing Ahead-of-time +Optimizations

          +

          One way to improve test coverage of ahead-of-time (AOT) optimizations +in the JDK is to run existing jtreg test cases in a special "AOT_JDK" +mode. Example:

          +
          $ make test JTREG="AOT_JDK=onestep" \
          +    TEST=open/test/hotspot/jtreg/runtime/invokedynamic
          +

          In this testing mode, we first perform an AOT training run (see +https://openjdk.org/jeps/483) of a special test program (test/setup_aot/TestSetupAOT.java) +that accesses about 5,0000 classes in the JDK core libraries. +Optimization artifacts for these classes (such as pre-linked lambda +expressions, execution profiles, and pre-generated native code) are +stored into an AOT cache file, which will be used by all the JVMs +launched by the selected jtreg test cases.

          +

          When the jtreg tests call into the core libraries classes that are in +the AOT cache, we will be able to test the AOT optimizations that were +used on those classes.

          +

          Please note that not all existing jtreg test cases can be executed +with the AOT_JDK mode. See test/hotspot/jtreg/ProblemList-AotJdk.txt +and test/jdk/ProblemList-AotJdk.txt.

          +

          Also, test cases that were written specifically to test AOT, such as +the tests under test/hotspot/jtreg/runtime/cds, +cannot be executed with the AOT_JDK mode.

          +

          Valid values for AOT_JDK are onestep and +twostep. These control how the AOT cache is generated. See +https://openjdk.org/jeps/514 for details. All other values are +ignored.

          Testing with alternative security providers

          Some security tests use a hardcoded provider for diff --git a/doc/testing.md b/doc/testing.md index 351690c5e60..bb56c05c295 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -345,6 +345,14 @@ The simplest way to run tests with JCov coverage report is to use the special target `jcov-test` instead of `test`, e.g. `make jcov-test TEST=jdk_lang`. This will make sure the JCov image is built, and that JCov reporting is enabled. +To include JCov coverage for just a subset of all modules, you can use the +`--with-jcov-modules` arguments to `configure`, e.g. +`--with-jcov-modules=jdk.compiler,java.desktop`. + +For more fine-grained control, you can pass arbitrary filters to JCov using +`--with-jcov-filters`, and you can specify a specific JDK to instrument +using `--with-jcov-input-jdk`. + The JCov report is stored in `build/$BUILD/test-results/jcov-output/report`. Please note that running with JCov reporting can be very memory intensive. @@ -603,6 +611,43 @@ $ make test TEST="jtreg:sun/security/pkcs11/Secmod/AddTrustedCert.java" \ For more notes about the PKCS11 tests, please refer to test/jdk/sun/security/pkcs11/README. +### Testing Ahead-of-time Optimizations +------------------------------------------------------------------------------- +One way to improve test coverage of ahead-of-time (AOT) optimizations in +the JDK is to run existing jtreg test cases in a special "AOT_JDK" mode. +Example: + +``` +$ make test JTREG="AOT_JDK=onestep" \ + TEST=open/test/hotspot/jtreg/runtime/invokedynamic +``` + +In this testing mode, we first perform an AOT training run +(see https://openjdk.org/jeps/483) of a special test program +([test/setup_aot/TestSetupAOT.java](../test/setup_aot/TestSetupAOT.java)) +that accesses about 5,0000 classes in the JDK core libraries. +Optimization artifacts for these classes (such as pre-linked +lambda expressions, execution profiles, and pre-generated native code) +are stored into an AOT cache file, which will be used by all the JVMs +launched by the selected jtreg test cases. + +When the jtreg tests call into the core libraries classes that are in +the AOT cache, we will be able to test the AOT optimizations that were +used on those classes. + +Please note that not all existing jtreg test cases can be executed with +the AOT_JDK mode. See +[test/hotspot/jtreg/ProblemList-AotJdk.txt](../test/hotspot/jtreg/ProblemList-AotJdk.txt) +and [test/jdk/ProblemList-AotJdk.txt](../test/jdk/ProblemList-AotJdk.txt). + +Also, test cases that were written specifically to test AOT, such as the tests +under [test/hotspot/jtreg/runtime/cds](../test/hotspot/jtreg/runtime/cds/), +cannot be executed with the AOT_JDK mode. + +Valid values for `AOT_JDK` are `onestep` and `twostep`. These control how +the AOT cache is generated. See https://openjdk.org/jeps/514 for details. +All other values are ignored. + ### Testing with alternative security providers Some security tests use a hardcoded provider for `KeyFactory`, `Cipher`, diff --git a/make/Bundles.gmk b/make/Bundles.gmk index 8962b596278..ba8ec0c864b 100644 --- a/make/Bundles.gmk +++ b/make/Bundles.gmk @@ -174,9 +174,11 @@ else JRE_IMAGE_HOMEDIR := $(JRE_IMAGE_DIR) JDK_BUNDLE_SUBDIR := jdk-$(VERSION_NUMBER) JRE_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER) + STATIC_JDK_BUNDLE_SUBDIR := static-jdk-$(VERSION_NUMBER) ifneq ($(DEBUG_LEVEL), release) JDK_BUNDLE_SUBDIR := $(JDK_BUNDLE_SUBDIR)/$(DEBUG_LEVEL) JRE_BUNDLE_SUBDIR := $(JRE_BUNDLE_SUBDIR)/$(DEBUG_LEVEL) + STATIC_JDK_BUNDLE_SUBDIR := $(STATIC_JDK_BUNDLE_SUBDIR)/$(DEBUG_LEVEL) endif # In certain situations, the JDK_IMAGE_DIR points to an image without the # the symbols and demos. If so, the symobls and demos can be found in a @@ -500,6 +502,21 @@ ifneq ($(filter static-libs-graal-bundles, $(MAKECMDGOALS)), ) STATIC_LIBS_GRAAL_TARGETS += $(BUILD_STATIC_LIBS_GRAAL_BUNDLE) endif +################################################################################# + +ifneq ($(filter static-jdk-bundles, $(MAKECMDGOALS)), ) + STATIC_JDK_BUNDLE_FILES := $(call FindFiles, $(STATIC_JDK_IMAGE_DIR)) + + $(eval $(call SetupBundleFile, BUILD_STATIC_JDK_BUNDLE, \ + BUNDLE_NAME := $(STATIC_JDK_BUNDLE_NAME), \ + FILES := $(STATIC_JDK_BUNDLE_FILES), \ + BASE_DIRS := $(STATIC_JDK_IMAGE_DIR), \ + SUBDIR := $(STATIC_JDK_BUNDLE_SUBDIR), \ + )) + + STATIC_JDK_TARGETS += $(BUILD_STATIC_JDK_BUNDLE) +endif + ################################################################################ product-bundles: $(PRODUCT_TARGETS) @@ -510,11 +527,12 @@ docs-javase-bundles: $(DOCS_JAVASE_TARGETS) docs-reference-bundles: $(DOCS_REFERENCE_TARGETS) static-libs-bundles: $(STATIC_LIBS_TARGETS) static-libs-graal-bundles: $(STATIC_LIBS_GRAAL_TARGETS) +static-jdk-bundles: $(STATIC_JDK_TARGETS) jcov-bundles: $(JCOV_TARGETS) .PHONY: product-bundles test-bundles \ docs-jdk-bundles docs-javase-bundles docs-reference-bundles \ - static-libs-bundles static-libs-graal-bundles jcov-bundles + static-libs-bundles static-libs-graal-bundles static-jdk-bundles jcov-bundles ################################################################################ diff --git a/make/CompileInterimLangtools.gmk b/make/CompileInterimLangtools.gmk index c869ea160c7..c7d1c3796f6 100644 --- a/make/CompileInterimLangtools.gmk +++ b/make/CompileInterimLangtools.gmk @@ -95,14 +95,16 @@ define SetupInterimModule SRC := $(BUILDTOOLS_OUTPUTDIR)/gensrc/$1.interim \ $$(wildcard $(SUPPORT_OUTPUTDIR)/gensrc/$1) \ $(TOPDIR)/src/$1/share/classes, \ - EXCLUDES := sun javax/tools/snippet-files, \ + EXCLUDES := sun, \ EXCLUDE_FILES := $(TOPDIR)/src/$1/share/classes/module-info.java \ $(TOPDIR)/src/$1/share/classes/javax/tools/ToolProvider.java \ $(TOPDIR)/src/$1/share/classes/com/sun/tools/javac/launcher/Main.java \ + $(TOPDIR)/src/$1/share/classes/com/sun/tools/javac/launcher/MemoryClassLoader.java \ $(TOPDIR)/src/$1/share/classes/com/sun/tools/javac/launcher/MemoryContext.java \ $(TOPDIR)/src/$1/share/classes/com/sun/tools/javac/launcher/MemoryModuleFinder.java \ $(TOPDIR)/src/$1/share/classes/com/sun/tools/javac/launcher/SourceLauncher.java \ Standard.java, \ + EXCLUDE_PATTERNS := -files, \ EXTRA_FILES := $(BUILDTOOLS_OUTPUTDIR)/gensrc/$1.interim/module-info.java \ $($1.interim_EXTRA_FILES), \ COPY := .gif .png .xml .css .svg .js .js.template .txt .woff .woff2 javax.tools.JavaCompilerTool, \ diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index b4a193dfade..1e26fb2b529 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -113,6 +113,7 @@ $(eval $(call SetupJavaCompilation, $(MODULE), \ DISABLED_WARNINGS := $(DISABLED_WARNINGS_java), \ EXCLUDES := $(EXCLUDES), \ EXCLUDE_FILES := $(EXCLUDE_FILES), \ + EXCLUDE_PATTERNS := -files, \ KEEP_ALL_TRANSLATIONS := $(KEEP_ALL_TRANSLATIONS), \ JAVAC_FLAGS := \ $(DOCLINT) \ diff --git a/make/Coverage.gmk b/make/Coverage.gmk index 2fd4e4ec6d4..a375c343185 100644 --- a/make/Coverage.gmk +++ b/make/Coverage.gmk @@ -34,21 +34,28 @@ else JCOV_INPUT_IMAGE_DIR := $(JDK_IMAGE_DIR) endif +JCOV_SUPPORT_DIR := $(SUPPORT_OUTPUTDIR)/jcov + #moving instrumented jdk image in and out of jcov_temp because of CODETOOLS-7902299 -JCOV_TEMP := $(SUPPORT_OUTPUTDIR)/jcov_temp +JCOV_TEMP := $(JCOV_SUPPORT_DIR)/temp + +ifneq ($(JCOV_MODULES), ) + JCOV_MODULES_FILTER := $(foreach m, $(JCOV_MODULES), -include_module $m) +endif $(JCOV_IMAGE_DIR)/release: $(JCOV_INPUT_IMAGE_DIR)/release $(call LogWarn, Creating instrumented jdk image with JCov) $(call MakeDir, $(JCOV_TEMP) $(IMAGES_OUTPUTDIR)) $(RM) -r $(JCOV_IMAGE_DIR) $(JCOV_TEMP)/* $(CP) -r $(JCOV_INPUT_IMAGE_DIR) $(JCOV_TEMP)/$(JCOV_IMAGE_SUBDIR) - $(JAVA) -Xmx3g -jar $(JCOV_HOME)/lib/jcov.jar JREInstr \ + $(call ExecuteWithLog, $(JCOV_SUPPORT_DIR)/run-jcov, \ + $(JAVA) -Xmx3g -jar $(JCOV_HOME)/lib/jcov.jar JREInstr \ -t $(JCOV_TEMP)/$(JCOV_IMAGE_SUBDIR)/template.xml \ -rt $(JCOV_HOME)/lib/jcov_network_saver.jar \ -exclude 'java.lang.Object' \ -exclude jdk.test.Main -exclude '**\$Proxy*' \ - $(JCOV_FILTERS) \ - $(JCOV_TEMP)/$(JCOV_IMAGE_SUBDIR) + $(JCOV_MODULES_FILTER) $(JCOV_FILTERS) \ + $(JCOV_TEMP)/$(JCOV_IMAGE_SUBDIR)) $(MV) $(JCOV_TEMP)/$(JCOV_IMAGE_SUBDIR) $(JCOV_IMAGE_DIR) $(RMDIR) $(JCOV_TEMP) diff --git a/make/Docs.gmk b/make/Docs.gmk index 60c029ce8f9..1fcc8575d2c 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -79,8 +79,6 @@ JAVADOC_TAGS := \ -tag see \ -taglet build.tools.taglet.ExtLink \ -taglet build.tools.taglet.Incubating \ - -taglet build.tools.taglet.PreviewNote \ - --preview-note-tag previewNote \ -tagletpath $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ $(CUSTOM_JAVADOC_TAGS) \ # @@ -96,14 +94,14 @@ JAVADOC_DISABLED_DOCLINT_PACKAGES := org.w3c.* javax.smartcardio # The initial set of options for javadoc JAVADOC_OPTIONS := -use -keywords -notimestamp \ - -serialwarn -encoding ISO-8859-1 -docencoding UTF-8 -breakiterator \ + -serialwarn -encoding utf-8 -docencoding utf-8 -breakiterator \ -splitIndex --system none -javafx --expand-requires transitive \ --override-methods=summary # The reference options must stay stable to allow for comparisons across the # development cycle. REFERENCE_OPTIONS := -XDignore.symbol.file=true -use -keywords -notimestamp \ - -serialwarn -encoding ISO-8859-1 -breakiterator -splitIndex --system none \ + -serialwarn -encoding utf-8 -breakiterator -splitIndex --system none \ -html5 -javafx --expand-requires transitive # Should we add DRAFT stamps to the generated javadoc? @@ -262,7 +260,7 @@ define create_overview_file $$($1_OVERVIEW): $$($1_OVERVIEW_VARDEPS_FILE) $$(call LogInfo, Creating overview.html for $1) $$(call MakeDir, $$(@D)) - $$(ECHO) -n '$$($1_OVERVIEW_TEXT)' > $$@ + $$(PRINTF) "%s" '$$($1_OVERVIEW_TEXT)' > $$@ endef ################################################################################ @@ -542,7 +540,9 @@ $(eval $(call SetupApiDocsGeneration, REFERENCE_API, \ # Format: space-delimited list of names, including at most one '%' as a # wildcard. Spec source files match if their filename or any enclosing folder # name matches one of the items in SPEC_FILTER. -SPEC_FILTER := % +ifeq ($(SPEC_FILTER), ) + SPEC_FILTER := % +endif ApplySpecFilter = \ $(strip $(foreach file, $(1), \ diff --git a/make/GenerateLinkOptData.gmk b/make/GenerateLinkOptData.gmk index 5fc745ba223..6f6e1f29b4c 100644 --- a/make/GenerateLinkOptData.gmk +++ b/make/GenerateLinkOptData.gmk @@ -76,10 +76,14 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXECUTABLE_SUFFIX) $(CLASSLIST $(call LogInfo, Generating $(patsubst $(OUTPUTDIR)/%, %, $(JLI_TRACE_FILE))) $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw \ $(CLASSLIST_FILE_VM_OPTS) \ + -Xlog:aot=off \ + -Xlog:cds=off \ -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \ build.tools.classlist.HelloClasslist $(LOG_DEBUG) $(GREP) -v HelloClasslist $@.raw > $@.interim $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -Xshare:dump \ + -Xlog:aot=off \ + -Xlog:cds=off \ -XX:SharedClassListFile=$@.interim -XX:SharedArchiveFile=$@.jsa \ -Xmx128M -Xms128M $(LOG_INFO) $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.raw.2 \ @@ -87,6 +91,8 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXECUTABLE_SUFFIX) $(CLASSLIST -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \ $(CLASSLIST_FILE_VM_OPTS) \ --module-path $(SUPPORT_OUTPUTDIR)/classlist.jar \ + -Xlog:aot=off \ + -Xlog:cds=off \ -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \ build.tools.classlist.HelloClasslist \ 2> $(LINK_OPT_DIR)/stderr > $(JLI_TRACE_FILE) \ @@ -100,6 +106,8 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXECUTABLE_SUFFIX) $(CLASSLIST $(GREP) -v HelloClasslist $@.raw.2 > $@.raw.3 $(GREP) -v @cp $@.raw.3 > $@.raw.4 $(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java \ + -Xlog:aot=off \ + -Xlog:cds=off \ -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \ build.tools.classlist.SortClasslist $@.raw.4 > $@ diff --git a/make/Images.gmk b/make/Images.gmk index 3f2b34bc9c6..22e3e43cb1f 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -162,7 +162,7 @@ define CreateCDSArchive endif ifeq ($(DEBUG_CDS_ARCHIVE), true) - $1_$2_CDS_DUMP_FLAGS += -Xlog:cds+map*=trace:file=$$(JDK_IMAGE_DIR)/$$($1_$2_CDS_ARCHIVE).cdsmap:none:filesize=0 + $1_$2_CDS_DUMP_FLAGS += -Xlog:aot+map*=trace:file=$$(JDK_IMAGE_DIR)/$$($1_$2_CDS_ARCHIVE).cdsmap:none:filesize=0 endif $$(eval $$(call SetupExecute, $1_$2_gen_cds_archive_jdk, \ diff --git a/make/Init.gmk b/make/Init.gmk index 5dd1a71dd9a..38959323628 100644 --- a/make/Init.gmk +++ b/make/Init.gmk @@ -37,10 +37,6 @@ include MakeFileStart.gmk include $(TOPDIR)/make/InitSupport.gmk include LogUtils.gmk -# Force early generation of module-deps.gmk -GENERATE_MODULE_DEPS_FILE := true -include Modules.gmk - # Inclusion of this pseudo-target will cause make to execute this file # serially, regardless of -j. .NOTPARALLEL: @@ -114,7 +110,18 @@ reconfigure: CUSTOM_CONFIG_DIR="$(CUSTOM_CONFIG_DIR)" \ $(RECONFIGURE_COMMAND) ) -.PHONY: print-modules print-targets print-tests print-configuration reconfigure +# Create files that are needed to run most targets in Main.gmk +create-make-helpers: + ( cd $(TOPDIR) && \ + $(MAKE) $(MAKE_ARGS) -j 1 -f make/GenerateFindTests.gmk \ + $(USER_MAKE_VARS) ) + ( cd $(TOPDIR) && \ + $(MAKE) $(MAKE_ARGS) -j 1 -f make/Main.gmk $(USER_MAKE_VARS) \ + UPDATE_MODULE_DEPS=true NO_RECIPES=true \ + create-main-targets-include ) + +.PHONY: print-modules print-targets print-tests print-configuration \ + reconfigure create-make-helpers ############################################################################## # The main target. This will delegate all other targets into Main.gmk. @@ -134,7 +141,7 @@ TARGET_DESCRIPTION := target$(if $(word 2, $(MAIN_TARGETS)),s) \ # variables are explicitly propagated using $(USER_MAKE_VARS). main: MAKEOVERRIDES := -main: $(INIT_TARGETS) +main: $(INIT_TARGETS) create-make-helpers ifneq ($(SEQUENTIAL_TARGETS)$(PARALLEL_TARGETS), ) $(call RotateLogFiles) $(ECHO) "Building $(TARGET_DESCRIPTION)" $(BUILD_LOG_PIPE_SIMPLE) @@ -144,6 +151,9 @@ main: $(INIT_TARGETS) ( cd $(TOPDIR) && \ $(MAKE) $(MAKE_ARGS) -j 1 -f make/Main.gmk $(USER_MAKE_VARS) \ $(SEQUENTIAL_TARGETS) ) + # We might have cleaned away essential files, recreate them. + ( cd $(TOPDIR) && \ + $(MAKE) $(MAKE_ARGS) -j 1 -f make/Init.gmk create-make-helpers ) endif ifneq ($(PARALLEL_TARGETS), ) $(call PrepareFailureLogs) diff --git a/make/Main.gmk b/make/Main.gmk index eda3b79265a..d0568509a4e 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -42,6 +42,12 @@ include MakeFileStart.gmk include $(TOPDIR)/make/MainSupport.gmk include FindTests.gmk + +ifeq ($(UPDATE_MODULE_DEPS), true) + # Update module-deps.gmk if requested. This is read in Modules.gmk. + GENERATE_MODULE_DEPS_FILE := true +endif + include Modules.gmk # Are we requested to ignore dependencies? @@ -411,12 +417,14 @@ $(eval $(call SetupTarget, create-source-revision-tracker, \ )) BOOTCYCLE_TARGET := product-images +BOOTCYCLE_SPEC := $(dir $(SPEC))bootcycle-spec.gmk + bootcycle-images: ifneq ($(COMPILE_TYPE), cross) $(call LogWarn, Boot cycle build step 2: Building a new JDK image using previously built image) $(call MakeDir, $(OUTPUTDIR)/bootcycle-build) +$(MAKE) $(MAKE_ARGS) -f $(TOPDIR)/make/Init.gmk PARALLEL_TARGETS=$(BOOTCYCLE_TARGET) \ - LOG_PREFIX="[bootcycle] " JOBS= SPEC=$(dir $(SPEC))bootcycle-spec.gmk main + LOG_PREFIX="[bootcycle] " JOBS= SPEC=$(BOOTCYCLE_SPEC) main else $(call LogWarn, Boot cycle build disabled when cross compiling) endif @@ -875,6 +883,12 @@ $(eval $(call SetupTarget, static-libs-graal-bundles, \ DEPS := static-libs-graal-image, \ )) +$(eval $(call SetupTarget, static-jdk-bundles, \ + MAKEFILE := Bundles, \ + TARGET := static-jdk-bundles, \ + DEPS := static-jdk-image, \ +)) + ifeq ($(JCOV_ENABLED), true) $(eval $(call SetupTarget, jcov-bundles, \ MAKEFILE := Bundles, \ diff --git a/make/MainSupport.gmk b/make/MainSupport.gmk index ae4858c35af..d8dc894c1e9 100644 --- a/make/MainSupport.gmk +++ b/make/MainSupport.gmk @@ -57,7 +57,7 @@ define SetupTargetBody endef define CleanDocs - @$(ECHO) -n "Cleaning docs ..." + @$(PRINTF) "Cleaning docs ..." @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/docs $(RM) -r $(SUPPORT_OUTPUTDIR)/javadoc @@ -67,28 +67,28 @@ endef # Cleans the dir given as $1 define CleanDir - @$(ECHO) -n "Cleaning $(strip $1) build artifacts ..." + @$(PRINTF) "Cleaning %s build artifacts ..." "$(strip $1)" @$(ECHO) "" $(LOG_DEBUG) ($(CD) $(OUTPUTDIR) && $(RM) -r $1) @$(ECHO) " done" endef define CleanSupportDir - @$(ECHO) -n "Cleaning$(strip $1) build artifacts ..." + @$(PRINTF) "Cleaning %s build artifacts ..." "$(strip $1)" @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/$(strip $1) @$(ECHO) " done" endef define CleanMakeSupportDir - @$(ECHO) -n "Cleaning $(strip $1) make support artifacts ..." + @$(PRINTF) "Cleaning %s make support artifacts ..." "$(strip $1)" @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(MAKESUPPORT_OUTPUTDIR)/$(strip $1) @$(ECHO) " done" endef define CleanTest - @$(ECHO) -n "Cleaning test $(strip $1) ..." + @$(PRINTF) "Cleaning test %s ..." "$(strip $1)" @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/test/$(strip $(subst -,/,$1)) # Remove as much of the test directory structure as is empty @@ -97,25 +97,25 @@ define CleanTest endef define Clean-gensrc - @$(ECHO) -n "Cleaning gensrc $(if $1,for $(strip $1) )..." + @$(PRINTF) "Cleaning gensrc %s..." "$(if $1,for $(strip $1) )" @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/gensrc/$(strip $1) @$(ECHO) " done" endef define Clean-java - @$(ECHO) -n "Cleaning java $(if $1,for $(strip $1) )..." + @$(PRINTF) "Cleaning java %s..." "$(if $1,for $(strip $1) )" @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(JDK_OUTPUTDIR)/modules/$(strip $1) $(RM) -r $(SUPPORT_OUTPUTDIR)/special_classes/$(strip $1) $(ECHO) " done" - $(ECHO) -n "Cleaning headers $(if $1,for $(strip $1) )..." + $(PRINTF) "Cleaning headers %s..." "$(if $1,for $(strip $1) )" $(RM) -r $(SUPPORT_OUTPUTDIR)/headers/$(strip $1) @$(ECHO) " done" endef define Clean-native - @$(ECHO) -n "Cleaning native $(if $1,for $(strip $1) )..." + @$(PRINTF) "Cleaning native %s..." "$(if $1,for $(strip $1) )" @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/native/$(strip $1) $(RM) -r $(SUPPORT_OUTPUTDIR)/modules_libs/$(strip $1) @@ -124,7 +124,7 @@ define Clean-native endef define Clean-include - @$(ECHO) -n "Cleaning include $(if $1,for $(strip $1) )..." + @$(PRINTF) "Cleaning include %s..." "$(if $1,for $(strip $1) )" @$(ECHO) "" $(LOG_DEBUG) $(RM) -r $(SUPPORT_OUTPUTDIR)/modules_include/$(strip $1) @$(ECHO) " done" diff --git a/make/PreInit.gmk b/make/PreInit.gmk index a01971e845d..3df44308dd9 100644 --- a/make/PreInit.gmk +++ b/make/PreInit.gmk @@ -50,7 +50,8 @@ include $(TOPDIR)/make/Global.gmk # Targets provided by Init.gmk. ALL_INIT_TARGETS := print-modules print-targets print-configuration \ - print-tests reconfigure pre-compare-build post-compare-build + print-tests reconfigure pre-compare-build post-compare-build \ + create-make-helpers # CALLED_TARGETS is the list of targets that the user provided, # or "default" if unspecified. @@ -161,19 +162,19 @@ ifneq ($(SKIP_SPEC), true) ( cd $(TOPDIR) && \ $(foreach spec, $(SPECS), \ $(MAKE) $(MAKE_INIT_ARGS) -j 1 -f $(TOPDIR)/make/Init.gmk \ - SPEC=$(spec) $(MAKE_INIT_MAIN_TARGET_ARGS) \ - main && \ + SPEC=$(spec) TOPDIR_ALT=$(TOPDIR) \ + $(MAKE_INIT_MAIN_TARGET_ARGS) main && \ $(if $(and $(COMPARE_BUILD), $(PARALLEL_TARGETS)), \ $(MAKE) $(MAKE_INIT_ARGS) -f $(TOPDIR)/make/Init.gmk \ - SPEC=$(spec) \ + SPEC=$(spec) TOPDIR_ALT=$(TOPDIR) \ COMPARE_BUILD="$(COMPARE_BUILD)" \ pre-compare-build && \ $(MAKE) $(MAKE_INIT_ARGS) -j 1 -f $(TOPDIR)/make/Init.gmk \ - SPEC=$(spec) $(MAKE_INIT_MAIN_TARGET_ARGS) \ + SPEC=$(spec) TOPDIR_ALT=$(TOPDIR) \ COMPARE_BUILD="$(COMPARE_BUILD):NODRYRUN=true" \ - main && \ + $(MAKE_INIT_MAIN_TARGET_ARGS) main && \ $(MAKE) $(MAKE_INIT_ARGS) -f $(TOPDIR)/make/Init.gmk \ - SPEC=$(spec) \ + SPEC=$(spec) TOPDIR_ALT=$(TOPDIR) \ COMPARE_BUILD="$(COMPARE_BUILD):NODRYRUN=true" \ post-compare-build && \ ) \ diff --git a/make/PreInitSupport.gmk b/make/PreInitSupport.gmk index 668363d8725..660e1214b5b 100644 --- a/make/PreInitSupport.gmk +++ b/make/PreInitSupport.gmk @@ -250,13 +250,14 @@ endef # Param 1: FORCE = force generation of main-targets.gmk or LAZY = do not force. # Param 2: The SPEC file to use. define DefineMainTargets + SPEC_FILE := $(strip $2) # We will start by making sure the main-targets.gmk file is removed, if # make has not been restarted. By the -include, we will trigger the # rule for generating the file (which is never there since we removed it), # thus generating it fresh, and make will restart, incrementing the restart # count. - main_targets_file := $$(dir $(strip $2))make-support/main-targets.gmk + main_targets_file := $$(dir $$(SPEC_FILE))make-support/main-targets.gmk ifeq ($$(MAKE_RESTARTS), ) # Only do this if make has not been restarted, and if we do not force it. @@ -267,11 +268,12 @@ define DefineMainTargets $$(main_targets_file): @( cd $$(TOPDIR) && \ - $$(MAKE) $$(MAKE_LOG_FLAGS) -r -R -f $$(TOPDIR)/make/GenerateFindTests.gmk \ - -I $$(TOPDIR)/make/common SPEC=$(strip $2) ) + $$(MAKE) $$(MAKE_LOG_FLAGS) -s -r -R -f $$(TOPDIR)/make/GenerateFindTests.gmk \ + -I $$(TOPDIR)/make/common SPEC=$$(SPEC_FILE) TOPDIR_ALT=$$(TOPDIR)) @( cd $$(TOPDIR) && \ - $$(MAKE) $$(MAKE_LOG_FLAGS) -r -R -f $$(TOPDIR)/make/Main.gmk \ - -I $$(TOPDIR)/make/common SPEC=$(strip $2) NO_RECIPES=true \ + $$(MAKE) $$(MAKE_LOG_FLAGS) -s -r -R -f $$(TOPDIR)/make/Main.gmk \ + -I $$(TOPDIR)/make/common SPEC=$$(SPEC_FILE) TOPDIR_ALT=$$(TOPDIR) \ + UPDATE_MODULE_DEPS=true NO_RECIPES=true \ $$(MAKE_LOG_VARS) \ create-main-targets-include ) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 80c1ff99b2e..60ae1bd4763 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -115,6 +115,7 @@ JTREG_COV_OPTIONS := ifeq ($(TEST_OPTS_JCOV), true) JCOV_OUTPUT_DIR := $(TEST_RESULTS_DIR)/jcov-output + JCOV_SUPPORT_DIR := $(TEST_SUPPORT_DIR)/jcov-support JCOV_GRABBER_LOG := $(JCOV_OUTPUT_DIR)/grabber.log JCOV_RESULT_FILE := $(JCOV_OUTPUT_DIR)/result.xml JCOV_REPORT := $(JCOV_OUTPUT_DIR)/report @@ -582,6 +583,8 @@ define SetMicroValue else ifneq ($3, ) $1_$2 := $3 + else + $1_$2 := endif endif endef @@ -708,6 +711,8 @@ define SetJtregValue else ifneq ($3, ) $1_$2 := $3 + else + $1_$2 := endif endif endif @@ -720,6 +725,7 @@ endef # Parameter 1 is the name of the rule. # # Remaining parameters are named arguments. +# TRAINING The AOT training mode: onestep or twostep # VM_OPTIONS List of JVM arguments to use when creating AOT cache # # After calling this, the following variables are defined @@ -748,23 +754,39 @@ define SetupAOTBody $$($1_AOT_JDK_CACHE): $$(JDK_IMAGE_DIR)/release $$(call MakeDir, $$($1_AOT_JDK_OUTPUT_DIR)) - $$(call LogWarn, AOT: Create cache configuration) \ - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ - cd $$($1_AOT_JDK_OUTPUT_DIR); \ - $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ - $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ - -Xlog:class+load,cds,cds+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error \ - -XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \ - TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ - )) - - $$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) - $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ - $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ - $$($1_VM_OPTIONS) -Xlog:cds,cds+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error \ - -XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \ - -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ - )) + ifeq ($$($1_TRAINING), onestep) + + $$(call LogWarn, AOT: Create AOT cache $$($1_AOT_JDK_CACHE) in one step with flags: $$($1_VM_OPTIONS)) \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + cd $$($1_AOT_JDK_OUTPUT_DIR); \ + $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ + $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ + -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ + -XX:AOTMode=record -XX:AOTCacheOutput=$$($1_AOT_JDK_CACHE) \ + TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ + )) + + else + + $$(call LogWarn, AOT: Create cache configuration) \ + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + cd $$($1_AOT_JDK_OUTPUT_DIR); \ + $(JAR) --extract --file $(TEST_IMAGE_DIR)/setup_aot/TestSetupAOT.jar; \ + $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java $$($1_VM_OPTIONS) \ + -Xlog:class+load,aot,aot+class=debug:file=$$($1_AOT_JDK_CONF).log -Xlog:cds*=error -Xlog:aot*=error \ + -XX:AOTMode=record -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) \ + TestSetupAOT $$($1_AOT_JDK_OUTPUT_DIR) > $$($1_AOT_JDK_LOG) \ + )) + + $$(call LogWarn, AOT: Generate AOT cache $$($1_AOT_JDK_CACHE) with flags: $$($1_VM_OPTIONS)) + $$(call ExecuteWithLog, $$($1_AOT_JDK_OUTPUT_DIR), ( \ + $$(FIXPATH) $(JDK_UNDER_TEST)/bin/java \ + $$($1_VM_OPTIONS) -Xlog:aot,aot+class=debug:file=$$($1_AOT_JDK_CACHE).log -Xlog:cds*=error -Xlog:aot*=error \ + -XX:ExtraSharedClassListFile=$(JDK_UNDER_TEST)/lib/classlist \ + -XX:AOTMode=create -XX:AOTConfiguration=$$($1_AOT_JDK_CONF) -XX:AOTCache=$$($1_AOT_JDK_CACHE) \ + )) + + endif $1_AOT_TARGETS += $$($1_AOT_JDK_CACHE) @@ -830,7 +852,7 @@ define SetupRunJtregTestBody JTREG_RETRY_COUNT ?= 0 JTREG_REPEAT_COUNT ?= 0 JTREG_REPORT ?= files - JTREG_AOT_JDK ?= false + JTREG_AOT_JDK ?= none ifneq ($$(JTREG_RETRY_COUNT), 0) ifneq ($$(JTREG_REPEAT_COUNT), 0) @@ -840,6 +862,12 @@ define SetupRunJtregTestBody endif endif + ifeq ($$(JTREG_RUN_PROBLEM_LISTS), true) + JTREG_PROBLEM_LIST_PREFIX := -match: + else + JTREG_PROBLEM_LIST_PREFIX := -exclude: + endif + ifneq ($$(JTREG_TEST_THREAD_FACTORY), ) $1_JTREG_BASIC_OPTIONS += -testThreadFactoryPath:$$(JTREG_TEST_THREAD_FACTORY_JAR) $1_JTREG_BASIC_OPTIONS += -testThreadFactory:$$(JTREG_TEST_THREAD_FACTORY) @@ -868,7 +896,7 @@ define SetupRunJtregTestBody # version of the JDK. $1_JTREG_BASIC_OPTIONS += -$$($1_JTREG_TEST_MODE) \ -verbose:$$(JTREG_VERBOSE) -retain:$$(JTREG_RETAIN) \ - -concurrency:$$($1_JTREG_JOBS) -timeoutFactor:$$(JTREG_TIMEOUT_FACTOR) \ + -concurrency:$$($1_JTREG_JOBS) \ -vmoption:-XX:MaxRAMPercentage=$$($1_JTREG_MAX_RAM_PERCENTAGE) \ -vmoption:-Dtest.boot.jdk="$$(BOOT_JDK)" \ -vmoption:-Djava.io.tmpdir="$$($1_TEST_TMP_DIR)" @@ -901,12 +929,6 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += -nativepath:$$($1_JTREG_NATIVEPATH) endif - ifeq ($$(JTREG_RUN_PROBLEM_LISTS), true) - JTREG_PROBLEM_LIST_PREFIX := -match: - else - JTREG_PROBLEM_LIST_PREFIX := -exclude: - endif - ifneq ($$($1_JTREG_PROBLEM_LIST), ) $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$($1_JTREG_PROBLEM_LIST)) endif @@ -929,6 +951,11 @@ define SetupRunJtregTestBody JTREG_AUTO_PROBLEM_LISTS += ProblemList-shenandoah.txt endif + ifneq ($$(findstring --enable-preview, $$(JTREG_ALL_OPTIONS)), ) + JTREG_AUTO_PROBLEM_LISTS += ProblemList-enable-preview.txt + endif + + ifneq ($$(JTREG_EXTRA_PROBLEM_LISTS), ) # Accept both absolute paths as well as relative to the current test root. $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ @@ -965,12 +992,12 @@ define SetupRunJtregTestBody endif endif - ifeq ($$(JTREG_AOT_JDK), true) + ifneq ($$(filter $$(JTREG_AOT_JDK), onestep twostep), ) $$(call LogWarn, Add AOT target for $1) - $$(eval $$(call SetupAOT, $1, VM_OPTIONS := $$(JTREG_ALL_OPTIONS) )) - + $$(eval $$(call SetupAOT, $1, \ + TRAINING := $$(JTREG_AOT_JDK), \ + VM_OPTIONS := $$(JTREG_ALL_OPTIONS) )) $$(call LogWarn, AOT_JDK_CACHE=$$($1_AOT_JDK_CACHE)) - $1_JTREG_BASIC_OPTIONS += -vmoption:-XX:AOTCache="$$($1_AOT_JDK_CACHE)" endif @@ -988,6 +1015,7 @@ define SetupRunJtregTestBody endif JTREG_TIMEOUT_FACTOR ?= $$(JTREG_AUTO_TIMEOUT_FACTOR) + $1_JTREG_BASIC_OPTIONS += -timeoutFactor:$$(JTREG_TIMEOUT_FACTOR) clean-outputdirs-$1: $$(call LogWarn, Clean up dirs for $1) @@ -1338,12 +1366,14 @@ TARGETS += run-all-tests pre-run-test post-run-test run-test-report run-test ifeq ($(TEST_OPTS_JCOV), true) + JCOV_VM_OPTS := -Xmx4g -Djdk.xml.totalEntitySizeLimit=0 -Djdk.xml.maxGeneralEntitySizeLimit=0 + jcov-do-start-grabber: $(call MakeDir, $(JCOV_OUTPUT_DIR)) if $(JAVA) -jar $(JCOV_HOME)/lib/jcov.jar GrabberManager -status 1>/dev/null 2>&1 ; then \ $(JAVA) -jar $(JCOV_HOME)/lib/jcov.jar GrabberManager -stop -stoptimeout 3600 ; \ fi - $(JAVA) -Xmx4g -jar $(JCOV_HOME)/lib/jcov.jar Grabber -v -t \ + $(JAVA) $(JCOV_VM_OPTS) -jar $(JCOV_HOME)/lib/jcov.jar Grabber -v -t \ $(JCOV_IMAGE_DIR)/template.xml -o $(JCOV_RESULT_FILE) \ 1>$(JCOV_GRABBER_LOG) 2>&1 & @@ -1356,6 +1386,10 @@ ifeq ($(TEST_OPTS_JCOV), true) $(JAVA) -jar $(JCOV_HOME)/lib/jcov.jar GrabberManager -stop -stoptimeout 3600 JCOV_REPORT_TITLE := JDK code coverage report
          + ifneq ($(JCOV_MODULES), ) + JCOV_MODULES_FILTER := $(foreach m, $(JCOV_MODULES), -include_module $m) + JCOV_REPORT_TITLE += Included modules: $(JCOV_MODULES)
          + endif ifneq ($(JCOV_FILTERS), ) JCOV_REPORT_TITLE += Code filters: $(JCOV_FILTERS)
          endif @@ -1363,11 +1397,12 @@ ifeq ($(TEST_OPTS_JCOV), true) jcov-gen-report: jcov-stop-grabber $(call LogWarn, Generating JCov report ...) - $(JAVA) -Xmx4g -jar $(JCOV_HOME)/lib/jcov.jar RepGen -sourcepath \ + $(call ExecuteWithLog, $(JCOV_SUPPORT_DIR)/run-jcov-repgen, \ + $(JAVA) $(JCOV_VM_OPTS) -jar $(JCOV_HOME)/lib/jcov.jar RepGen -sourcepath \ `$(ECHO) $(TOPDIR)/src/*/share/classes/ | $(TR) ' ' ':'` -fmt html \ - $(JCOV_FILTERS) \ + $(JCOV_MODULES_FILTER) $(JCOV_FILTERS) \ -mainReportTitle "$(JCOV_REPORT_TITLE)" \ - -o $(JCOV_REPORT) $(JCOV_RESULT_FILE) + -o $(JCOV_REPORT) $(JCOV_RESULT_FILE)) TARGETS += jcov-do-start-grabber jcov-start-grabber jcov-stop-grabber \ jcov-gen-report @@ -1387,7 +1422,7 @@ ifeq ($(TEST_OPTS_JCOV), true) jcov-gen-diffcoverage: jcov-stop-grabber $(call LogWarn, Generating diff coverage with changeset $(TEST_OPTS_JCOV_DIFF_CHANGESET) ... ) $(DIFF_COMMAND) - $(JAVA) -Xmx4g -jar $(JCOV_HOME)/lib/jcov.jar \ + $(JAVA) $(JCOV_VM_OPTS) -jar $(JCOV_HOME)/lib/jcov.jar \ DiffCoverage -replaceDiff "src/.*/classes/:" -all \ $(JCOV_RESULT_FILE) $(JCOV_SOURCE_DIFF) > \ $(JCOV_DIFF_COVERAGE_REPORT) diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk index ba9731789b0..f5fe1d33830 100644 --- a/make/RunTestsPrebuilt.gmk +++ b/make/RunTestsPrebuilt.gmk @@ -217,9 +217,9 @@ else ifeq ($(OPENJDK_TARGET_OS), macosx) else ifeq ($(OPENJDK_TARGET_OS), windows) NUM_CORES := $(NUMBER_OF_PROCESSORS) MEMORY_SIZE := $(shell \ - $(EXPR) `wmic computersystem get totalphysicalmemory -value \ - | $(GREP) = | $(SED) 's/\\r//g' \ - | $(CUT) -d "=" -f 2-` / 1024 / 1024 \ + $(EXPR) `powershell -Command \ + "(Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory" \ + | $(SED) 's/\\r//g' ` / 1024 / 1024 \ ) endif ifeq ($(NUM_CORES), ) diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4 index 6daba35547b..2d3e071dd52 100644 --- a/make/autoconf/basic.m4 +++ b/make/autoconf/basic.m4 @@ -134,17 +134,33 @@ AC_DEFUN_ONCE([BASIC_SETUP_BUILD_ENV], ) AC_SUBST(BUILD_ENV) + AC_MSG_CHECKING([for locale to use]) if test "x$LOCALE" != x; then # Check if we actually have C.UTF-8; if so, use it if $LOCALE -a | $GREP -q -E "^C\.(utf8|UTF-8)$"; then LOCALE_USED=C.UTF-8 + AC_MSG_RESULT([C.UTF-8 (recommended)]) + elif $LOCALE -a | $GREP -q -E "^en_US\.(utf8|UTF-8)$"; then + LOCALE_USED=en_US.UTF-8 + AC_MSG_RESULT([en_US.UTF-8 (acceptable fallback)]) else - AC_MSG_WARN([C.UTF-8 locale not found, using C locale]) - LOCALE_USED=C + # As a fallback, check if users locale is UTF-8. USER_LOCALE was saved + # by the wrapper configure script before autconf messed up LC_ALL. + if $ECHO $USER_LOCALE | $GREP -q -E "\.(utf8|UTF-8)$"; then + LOCALE_USED=$USER_LOCALE + AC_MSG_RESULT([$USER_LOCALE (untested fallback)]) + AC_MSG_WARN([Could not find C.UTF-8 or en_US.UTF-8 locale. This is not supported, and the build might fail unexpectedly.]) + else + AC_MSG_RESULT([no UTF-8 locale found]) + AC_MSG_WARN([No UTF-8 locale found. This is not supported. Proceeding with the C locale, but the build might fail unexpectedly.]) + LOCALE_USED=C + fi + AC_MSG_NOTICE([The recommended locale is C.UTF-8, but en_US.UTF-8 is also accepted.]) fi else - AC_MSG_WARN([locale command not not found, using C locale]) - LOCALE_USED=C + LOCALE_USED=C.UTF-8 + AC_MSG_RESULT([C.UTF-8 (default)]) + AC_MSG_WARN([locale command not not found, using C.UTF-8 locale]) fi export LC_ALL=$LOCALE_USED @@ -399,11 +415,21 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR], [ CONF_NAME=${with_conf_name} ]) # Test from where we are running configure, in or outside of src root. + if test "x$OPENJDK_BUILD_OS" = xwindows || test "x$OPENJDK_BUILD_OS" = "xmacosx"; then + # These systems have case insensitive paths, so convert them to lower case. + [ cmp_configure_start_dir=`$ECHO $CONFIGURE_START_DIR | $TR '[:upper:]' '[:lower:]'` ] + [ cmp_topdir=`$ECHO $TOPDIR | $TR '[:upper:]' '[:lower:]'` ] + [ cmp_custom_root=`$ECHO $CUSTOM_ROOT | $TR '[:upper:]' '[:lower:]'` ] + else + cmp_configure_start_dir="$CONFIGURE_START_DIR" + cmp_topdir="$TOPDIR" + cmp_custom_root="$CUSTOM_ROOT" + fi AC_MSG_CHECKING([where to store configuration]) - if test "x$CONFIGURE_START_DIR" = "x$TOPDIR" \ - || test "x$CONFIGURE_START_DIR" = "x$CUSTOM_ROOT" \ - || test "x$CONFIGURE_START_DIR" = "x$TOPDIR/make/autoconf" \ - || test "x$CONFIGURE_START_DIR" = "x$TOPDIR/make" ; then + if test "x$cmp_configure_start_dir" = "x$cmp_topdir" \ + || test "x$cmp_configure_start_dir" = "x$cmp_custom_root" \ + || test "x$cmp_configure_start_dir" = "x$cmp_topdir/make/autoconf" \ + || test "x$cmp_configure_start_dir" = "x$cmp_topdir/make" ; then # We are running configure from the src root. # Create a default ./build/target-variant-debuglevel output root. if test "x${CONF_NAME}" = x; then @@ -424,7 +450,12 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR], # If configuration is situated in normal build directory, just use the build # directory name as configuration name, otherwise use the complete path. if test "x${CONF_NAME}" = x; then - CONF_NAME=`$ECHO $CONFIGURE_START_DIR | $SED -e "s!^${TOPDIR}/build/!!"` + [ if [[ "$cmp_configure_start_dir" =~ ^${cmp_topdir}/build/[^/]+$ || + "$cmp_configure_start_dir" =~ ^${cmp_custom_root}/build/[^/]+$ ]]; then ] + CONF_NAME="${CONFIGURE_START_DIR##*/}" + else + CONF_NAME="$CONFIGURE_START_DIR" + fi fi OUTPUTDIR="$CONFIGURE_START_DIR" AC_MSG_RESULT([in current directory]) diff --git a/make/autoconf/basic_windows.m4 b/make/autoconf/basic_windows.m4 index fb6fc526bfa..dac6ec15db6 100644 --- a/make/autoconf/basic_windows.m4 +++ b/make/autoconf/basic_windows.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -159,7 +159,7 @@ AC_DEFUN([BASIC_SETUP_PATHS_WINDOWS], else WINENV_PREFIX_ARG="$WINENV_PREFIX" fi - FIXPATH_ARGS="-e $PATHTOOL -p $WINENV_PREFIX_ARG -r ${WINENV_ROOT//\\/\\\\} -t $WINENV_TEMP_DIR -c $CMD -q" + FIXPATH_ARGS="-e $PATHTOOL -p $WINENV_PREFIX_ARG -r ${WINENV_ROOT//\\/\\\\} -t $WINENV_TEMP_DIR -c $CMD" FIXPATH_BASE="$BASH $FIXPATH_DIR/fixpath.sh $FIXPATH_ARGS" FIXPATH="$FIXPATH_BASE exec" @@ -215,7 +215,7 @@ AC_DEFUN([BASIC_WINDOWS_FINALIZE_FIXPATH], if test "x$OPENJDK_BUILD_OS" = xwindows; then FIXPATH_CMDLINE=". $TOPDIR/make/scripts/fixpath.sh -e $PATHTOOL \ -p $WINENV_PREFIX_ARG -r ${WINENV_ROOT//\\/\\\\} -t $WINENV_TEMP_DIR \ - -c $CMD -q" + -c $CMD" $ECHO > $OUTPUTDIR/fixpath '#!/bin/bash' $ECHO >> $OUTPUTDIR/fixpath export PATH='"[$]PATH:'$PATH'"' $ECHO >> $OUTPUTDIR/fixpath $FIXPATH_CMDLINE '"[$]@"' diff --git a/make/autoconf/boot-jdk.m4 b/make/autoconf/boot-jdk.m4 index d39e6e75a94..feb16c7d179 100644 --- a/make/autoconf/boot-jdk.m4 +++ b/make/autoconf/boot-jdk.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -180,11 +180,13 @@ AC_DEFUN([BOOTJDK_CHECK_JAVA_HOME], # Test: Is there a java or javac in the PATH, which is a symlink to the JDK? AC_DEFUN([BOOTJDK_CHECK_JAVA_IN_PATH_IS_SYMLINK], [ - UTIL_LOOKUP_PROGS(JAVAC_CHECK, javac, , NOFIXPATH) - UTIL_LOOKUP_PROGS(JAVA_CHECK, java, , NOFIXPATH) - BINARY="$JAVAC_CHECK" - if test "x$JAVAC_CHECK" = x; then - BINARY="$JAVA_CHECK" + UTIL_LOOKUP_PROGS(JAVAC_CHECK, javac) + UTIL_GET_EXECUTABLE(JAVAC_CHECK) # Will setup JAVAC_CHECK_EXECUTABLE + UTIL_LOOKUP_PROGS(JAVA_CHECK, java) + UTIL_GET_EXECUTABLE(JAVA_CHECK) # Will setup JAVA_CHECK_EXECUTABLE + BINARY="$JAVAC_CHECK_EXECUTABLE" + if test "x$JAVAC_CHECK_EXECUTABLE" = x; then + BINARY="$JAVA_CHECK_EXECUTABLE" fi if test "x$BINARY" != x; then # So there is a java(c) binary, it might be part of a JDK. diff --git a/make/autoconf/build-performance.m4 b/make/autoconf/build-performance.m4 index 4414ea0d93c..10e86e75199 100644 --- a/make/autoconf/build-performance.m4 +++ b/make/autoconf/build-performance.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,8 @@ AC_DEFUN([BPERF_CHECK_MEMORY_SIZE], FOUND_MEM=yes elif test "x$OPENJDK_BUILD_OS" = xwindows; then # Windows, but without cygwin - MEMORY_SIZE=`wmic computersystem get totalphysicalmemory -value | grep = | cut -d "=" -f 2-` + MEMORY_SIZE=`powershell -Command \ + "(Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory" | $SED 's/\\r//g' ` MEMORY_SIZE=`expr $MEMORY_SIZE / 1024 / 1024` FOUND_MEM=yes fi diff --git a/make/autoconf/configure b/make/autoconf/configure index 6fa0aacfbc9..443a37bae77 100644 --- a/make/autoconf/configure +++ b/make/autoconf/configure @@ -49,7 +49,9 @@ fi export CONFIG_SHELL=$BASH export _as_can_reexec=no -# Make sure all shell commands are executed with the C locale +# Save user's current locale, but make sure all future shell commands are +# executed with the C locale +export USER_LOCALE=$LC_ALL export LC_ALL=C if test "x$CUSTOM_CONFIG_DIR" != x; then diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index bafedddf04f..e80d9a98957 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -573,12 +573,20 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], TOOLCHAIN_CFLAGS_JDK="$TOOLCHAIN_CFLAGS_JDK -fvisibility=hidden -fstack-protector" elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then - # The -utf-8 option sets source and execution character sets to UTF-8 to enable correct - # compilation of all source files regardless of the active code page on Windows. - TOOLCHAIN_CFLAGS_JVM="-nologo -MD -Zc:preprocessor -Zc:inline -Zc:throwingNew -permissive- -utf-8 -MP" - TOOLCHAIN_CFLAGS_JDK="-nologo -MD -Zc:preprocessor -Zc:inline -Zc:throwingNew -permissive- -utf-8 -Zc:wchar_t-" + TOOLCHAIN_CFLAGS_JVM="-nologo -MD -Zc:preprocessor -Zc:inline -Zc:throwingNew -permissive- -MP" + TOOLCHAIN_CFLAGS_JDK="-nologo -MD -Zc:preprocessor -Zc:inline -Zc:throwingNew -permissive- -Zc:wchar_t-" fi + # Set character encoding in source + if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then + CHARSET_CFLAGS="-finput-charset=utf-8" + elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then + # The -utf-8 option sets both source and execution character sets + CHARSET_CFLAGS="-utf-8 -validate-charset" + fi + TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM $CHARSET_CFLAGS" + TOOLCHAIN_CFLAGS_JDK="$TOOLCHAIN_CFLAGS_JDK $CHARSET_CFLAGS" + # CFLAGS C language level for JDK sources (hotspot only uses C++) if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then LANGSTD_CFLAGS="-std=c11" @@ -724,8 +732,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP], $1_CFLAGS_CPU_JVM="-mno-multiple -mno-string" if test "x$FLAGS_CPU" = xppc64; then # -mminimal-toc fixes `relocation truncated to fit' error for gcc 4.1. - # Use ppc64 instructions, but schedule for power5 - $1_CFLAGS_CPU="-mcpu=powerpc64 -mtune=power5" + $1_CFLAGS_CPU="-mcpu=power8 -mtune=power8" $1_CFLAGS_CPU_JVM="${$1_CFLAGS_CPU_JVM} -mminimal-toc" elif test "x$FLAGS_CPU" = xppc64le; then # Little endian machine uses ELFv2 ABI. diff --git a/make/autoconf/help.m4 b/make/autoconf/help.m4 index 93796d27f06..d8c0b2ffaef 100644 --- a/make/autoconf/help.m4 +++ b/make/autoconf/help.m4 @@ -292,12 +292,12 @@ AC_DEFUN_ONCE([HELP_PRINT_SUMMARY_AND_WARNINGS], $ECHO "* Debug level: $DEBUG_LEVEL" $ECHO "* HS debug level: $HOTSPOT_DEBUG_LEVEL" $ECHO "* JVM variants: $JVM_VARIANTS" - $ECHO -n "* JVM features: " + $PRINTF "* JVM features: " for variant in $JVM_VARIANTS; do features_var_name=JVM_FEATURES_$variant JVM_FEATURES_FOR_VARIANT=${!features_var_name} - $ECHO -n "$variant: '$JVM_FEATURES_FOR_VARIANT' " + $PRINTF "%s: \'%s\' " "$variant" "$JVM_FEATURES_FOR_VARIANT" done $ECHO "" diff --git a/make/autoconf/jdk-options.m4 b/make/autoconf/jdk-options.m4 index 79e44dd4ad1..289ed935fdf 100644 --- a/make/autoconf/jdk-options.m4 +++ b/make/autoconf/jdk-options.m4 @@ -405,10 +405,19 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_CODE_COVERAGE], JCOV_FILTERS="$with_jcov_filters" fi fi + + UTIL_ARG_WITH(NAME: jcov-modules, TYPE: string, + DEFAULT: [], RESULT: JCOV_MODULES_COMMMA_SEPARATED, + DESC: [which modules to include in jcov (comma-separated)], + OPTIONAL: true) + + # Replace "," with " ". + JCOV_MODULES=${JCOV_MODULES_COMMMA_SEPARATED//,/ } AC_SUBST(JCOV_ENABLED) AC_SUBST(JCOV_HOME) AC_SUBST(JCOV_INPUT_JDK) AC_SUBST(JCOV_FILTERS) + AC_SUBST(JCOV_MODULES) ]) ################################################################################ @@ -520,8 +529,21 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER], # Silence them for now. UBSAN_CHECKS="-fsanitize=undefined -fsanitize=float-divide-by-zero -fno-sanitize=shift-base -fno-sanitize=alignment \ $ADDITIONAL_UBSAN_CHECKS" - UBSAN_CFLAGS="$UBSAN_CHECKS -Wno-stringop-truncation -Wno-format-overflow -Wno-array-bounds -Wno-stringop-overflow -fno-omit-frame-pointer -DUNDEFINED_BEHAVIOR_SANITIZER" + UBSAN_CFLAGS="$UBSAN_CHECKS -Wno-array-bounds -fno-omit-frame-pointer -DUNDEFINED_BEHAVIOR_SANITIZER" + if test "x$TOOLCHAIN_TYPE" = "xgcc"; then + UBSAN_CFLAGS="$UBSAN_CFLAGS -Wno-format-overflow -Wno-stringop-overflow -Wno-stringop-truncation" + fi UBSAN_LDFLAGS="$UBSAN_CHECKS" + # On AIX, the llvm_symbolizer is not found out of the box, so we have to provide the + # full qualified llvm_symbolizer path in the __ubsan_default_options() function in + # make/data/ubsan/ubsan_default_options.c. To get it there we compile our sources + # with an additional define LLVM_SYMBOLIZER, which we set here. + # To calculate the correct llvm_symbolizer path we can use the location of the compiler, because + # their relation is fixed. + if test "x$TOOLCHAIN_TYPE" = "xclang" && test "x$OPENJDK_TARGET_OS" = "xaix"; then + UBSAN_CFLAGS="$UBSAN_CFLAGS -fno-sanitize=function,vptr -DLLVM_SYMBOLIZER=$(dirname $(dirname $CC))/tools/ibm-llvm-symbolizer" + UBSAN_LDFLAGS="$UBSAN_LDFLAGS -fno-sanitize=function,vptr -Wl,-bbigtoc" + fi UTIL_ARG_ENABLE(NAME: ubsan, DEFAULT: false, RESULT: UBSAN_ENABLED, DESC: [enable UndefinedBehaviorSanitizer], CHECK_AVAILABLE: [ diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4 index d2a4fcbb191..9eb5ee5a046 100644 --- a/make/autoconf/lib-tests.m4 +++ b/make/autoconf/lib-tests.m4 @@ -28,7 +28,7 @@ ################################################################################ # Minimum supported versions -JTREG_MINIMUM_VERSION=7.5.1 +JTREG_MINIMUM_VERSION=7.5.2 GTEST_MINIMUM_VERSION=1.14.0 ################################################################################ diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index 907a60290ec..e720916d88a 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -454,6 +454,7 @@ JCOV_ENABLED := @JCOV_ENABLED@ JCOV_HOME := @JCOV_HOME@ JCOV_INPUT_JDK := @JCOV_INPUT_JDK@ JCOV_FILTERS := @JCOV_FILTERS@ +JCOV_MODULES := @JCOV_MODULES@ # AddressSanitizer ASAN_ENABLED := @ASAN_ENABLED@ @@ -846,10 +847,12 @@ SVE_CFLAGS := @SVE_CFLAGS@ JDK_IMAGE_SUBDIR := jdk JRE_IMAGE_SUBDIR := jre JCOV_IMAGE_SUBDIR := jdk-jcov +STATIC_JDK_IMAGE_SUBDIR := static-jdk # Colon left out to be able to override output dir for bootcycle-images JDK_IMAGE_DIR = $(IMAGES_OUTPUTDIR)/$(JDK_IMAGE_SUBDIR) JRE_IMAGE_DIR = $(IMAGES_OUTPUTDIR)/$(JRE_IMAGE_SUBDIR) +STATIC_JDK_IMAGE_DIR = $(IMAGES_OUTPUTDIR)/$(STATIC_JDK_IMAGE_SUBDIR) JCOV_IMAGE_DIR = $(IMAGES_OUTPUTDIR)/$(JCOV_IMAGE_SUBDIR) # Test image, as above @@ -929,6 +932,7 @@ DOCS_JAVASE_BUNDLE_NAME := javase-$(BASE_NAME)_doc-api-spec$(DEBUG_PART).tar.gz DOCS_REFERENCE_BUNDLE_NAME := jdk-reference-$(BASE_NAME)_doc-api-spec$(DEBUG_PART).tar.gz STATIC_LIBS_BUNDLE_NAME := jdk-$(BASE_NAME)_bin-static-libs$(DEBUG_PART).tar.gz STATIC_LIBS_GRAAL_BUNDLE_NAME := jdk-$(BASE_NAME)_bin-static-libs-graal$(DEBUG_PART).tar.gz +STATIC_JDK_BUNDLE_NAME := static-jdk-$(BASE_NAME)_bin$(DEBUG_PART).$(JDK_BUNDLE_EXTENSION) JCOV_BUNDLE_NAME := jdk-jcov-$(BASE_NAME)_bin$(DEBUG_PART).$(JDK_BUNDLE_EXTENSION) JDK_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(JDK_BUNDLE_NAME) @@ -939,6 +943,7 @@ TEST_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(TEST_BUNDLE_NAME) DOCS_JDK_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(DOCS_JDK_BUNDLE_NAME) DOCS_JAVASE_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(DOCS_JAVASE_BUNDLE_NAME) DOCS_REFERENCE_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(DOCS_REFERENCE_BUNDLE_NAME) +STATIC_JDK_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(STATIC_JDK_BUNDLE_NAME) JCOV_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(JCOV_BUNDLE_NAME) # This macro is called to allow inclusion of closed source counterparts. diff --git a/make/autoconf/util_paths.m4 b/make/autoconf/util_paths.m4 index 9e3e5472c9e..40864680aad 100644 --- a/make/autoconf/util_paths.m4 +++ b/make/autoconf/util_paths.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -58,21 +58,32 @@ AC_DEFUN([UTIL_PREPEND_TO_PATH], # 2) The path will be absolute, and it will be in unix-style (on # cygwin). # $1: The name of the variable to fix -# $2: if NOFAIL, errors will be silently ignored +# $2: if NOFAIL, if the path cannot be resolved then errors will not be +# reported and an empty path will be set AC_DEFUN([UTIL_FIXUP_PATH], [ # Only process if variable expands to non-empty path="[$]$1" if test "x$path" != x; then if test "x$OPENJDK_BUILD_OS" = "xwindows"; then - if test "x$2" = "xNOFAIL"; then - quiet_option="-q" + imported_path=`$FIXPATH_BASE -q import "$path"` + if test $? -ne 0 || test ! -e $imported_path; then + if test "x$2" != "xNOFAIL"; then + AC_MSG_NOTICE([The path of $1, which is given as "$path", can not be properly resolved.]) + AC_MSG_NOTICE([Please see the section "Special Considerations" in building.md.]) + AC_MSG_NOTICE([This is the error message given by fixpath:]) + # Rerun fixpath without -q to get an error message + $FIXPATH_BASE import "$path" + AC_MSG_ERROR([Cannot continue]) + else + imported_path="" + fi fi - imported_path=`$FIXPATH_BASE $quiet_option import "$path"` - $FIXPATH_BASE verify "$imported_path" + + $FIXPATH_BASE -q verify "$imported_path" if test $? -ne 0; then if test "x$2" != "xNOFAIL"; then - AC_MSG_ERROR([The path of $1, which resolves as "$path", could not be imported.]) + AC_MSG_ERROR([The path of $1, which resolves as "$path", could not be verified.]) else imported_path="" fi @@ -83,7 +94,7 @@ AC_DEFUN([UTIL_FIXUP_PATH], if test "x$imported_path_lower" != "x$orig_path_lower"; then $1="$imported_path" fi - else + else # non-Windows [ if [[ "$path" =~ " " ]]; then ] if test "x$2" != "xNOFAIL"; then AC_MSG_NOTICE([The path of $1, which resolves as "$path", is invalid.]) @@ -186,7 +197,6 @@ AC_DEFUN([UTIL_CHECK_WINENV_EXEC_TYPE], # it need to be in the PATH. # $1: The name of the variable to fix # $2: Where to look for the command (replaces $PATH) -# $3: set to NOFIXPATH to skip prefixing FIXPATH, even if needed on platform AC_DEFUN([UTIL_FIXUP_EXECUTABLE], [ input="[$]$1" @@ -233,15 +243,19 @@ AC_DEFUN([UTIL_FIXUP_EXECUTABLE], # This is a path with slashes, don't look at $PATH if test "x$OPENJDK_BUILD_OS" = "xwindows"; then # fixpath.sh import will do all heavy lifting for us - new_path=`$FIXPATH_BASE import "$path"` + new_path=`$FIXPATH_BASE -q import "$path"` - if test ! -e $new_path; then + if test $? -ne 0 || test ! -e $new_path; then # It failed, but maybe spaces were part of the path and not separating # the command and argument. Retry using that assumption. - new_path=`$FIXPATH_BASE import "$input"` - if test ! -e $new_path; then - AC_MSG_NOTICE([The command for $1, which resolves as "$input", can not be found.]) - AC_MSG_ERROR([Cannot locate $input]) + new_path=`$FIXPATH_BASE -q import "$input"` + if test $? -ne 0 || test ! -e $new_path; then + AC_MSG_NOTICE([The command for $1, which is given as "$input", can not be properly resolved.]) + AC_MSG_NOTICE([Please see the section "Special Considerations" in building.md.]) + AC_MSG_NOTICE([This is the error message given by fixpath:]) + # Rerun fixpath without -q to get an error message + $FIXPATH_BASE import "$input" + AC_MSG_ERROR([Cannot continue]) fi # It worked, clear all "arguments" arguments="" @@ -282,10 +296,6 @@ AC_DEFUN([UTIL_FIXUP_EXECUTABLE], fi fi - if test "x$3" = xNOFIXPATH; then - fixpath_prefix="" - fi - # Now join together the path and the arguments once again new_complete="$fixpath_prefix$new_path$arguments" $1="$new_complete" @@ -353,7 +363,15 @@ AC_DEFUN([UTIL_SETUP_TOOL], else # Otherwise we believe it is a complete path. Use it as it is. if test ! -x "$tool_command" && test ! -x "${tool_command}.exe"; then - AC_MSG_ERROR([User supplied tool $1="$tool_command" does not exist or is not executable]) + # Maybe the path had spaces in it; try again with the entire argument + if test ! -x "$tool_override" && test ! -x "${tool_override}.exe"; then + AC_MSG_ERROR([User supplied tool $1="$tool_override" does not exist or is not executable]) + else + # We successfully located the executable assuming the spaces were part of the path. + # We can't combine using paths with spaces and arguments, so assume tool_args is empty. + tool_command="$tool_override" + tool_args="" + fi fi if test ! -x "$tool_command"; then tool_command="${tool_command}.exe" @@ -379,7 +397,6 @@ AC_DEFUN([UTIL_SETUP_TOOL], # $1: variable to set # $2: executable name (or list of names) to look for # $3: [path] -# $4: set to NOFIXPATH to skip prefixing FIXPATH, even if needed on platform AC_DEFUN([UTIL_LOOKUP_PROGS], [ UTIL_SETUP_TOOL($1, [ @@ -421,10 +438,8 @@ AC_DEFUN([UTIL_LOOKUP_PROGS], # If we have FIXPATH enabled, strip all instances of it and prepend # a single one, to avoid double fixpath prefixing. - if test "x$4" != xNOFIXPATH; then - [ if [[ $FIXPATH != "" && $result =~ ^"$FIXPATH " ]]; then ] - result="\$FIXPATH ${result#"$FIXPATH "}" - fi + [ if [[ $FIXPATH != "" && $result =~ ^"$FIXPATH " ]]; then ] + result="\$FIXPATH ${result#"$FIXPATH "}" fi AC_MSG_RESULT([$result]) break 2; @@ -515,6 +530,24 @@ AC_DEFUN([UTIL_ADD_FIXPATH], fi ]) +################################################################################ +# Return a path to the executable binary from a command line, stripping away +# any FIXPATH prefix or arguments. The resulting value can be checked for +# existence using "test -e". The result is returned in a variable named +# "$1_EXECUTABLE". +# +# $1: variable describing the command to get the binary for +AC_DEFUN([UTIL_GET_EXECUTABLE], +[ + # Strip the FIXPATH prefix, if any + fixpath_stripped="[$]$1" + [ if [[ $FIXPATH != "" && $fixpath_stripped =~ ^"$FIXPATH " ]]; then ] + fixpath_stripped="${fixpath_stripped#"$FIXPATH "}" + fi + # Remove any arguments following the binary + $1_EXECUTABLE="${fixpath_stripped%% *}" +]) + ################################################################################ AC_DEFUN([UTIL_REMOVE_SYMBOLIC_LINKS], [ diff --git a/make/common/FindTests.gmk b/make/common/FindTests.gmk index 41cf08d9e48..517bb2973f4 100644 --- a/make/common/FindTests.gmk +++ b/make/common/FindTests.gmk @@ -59,14 +59,14 @@ ifeq ($(GENERATE_FIND_TESTS_FILE), true) $(call MakeTargetDir) ( $(foreach root, $(JTREG_TESTROOTS), \ $(ECHO) ""; \ - $(ECHO) -n "$(root)_JTREG_TEST_GROUPS := "; \ + $(PRINTF) "\n%s_JTREG_TEST_GROUPS := " "$(root)"; \ $(SED) -n -e 's/^\#.*//g' -e 's/\([^ ]*\)\w*=.*/\1/gp' \ $($(root)_JTREG_GROUP_FILES) \ | $(SORT) -u | $(TR) '\n' ' ' ; \ ) \ ) > $@ $(ECHO) "" >> $@ - $(ECHO) -n "MAKE_TEST_TARGETS := " >> $@ + $(PRINTF) "MAKE_TEST_TARGETS := " >> $@ $(MAKE) -s --no-print-directory $(MAKE_ARGS) \ SPEC=$(SPEC) -f $(TOPDIR)/test/make/TestMake.gmk print-targets \ TARGETS_FILE=$@ diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 70b3557baea..c5a74413de1 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -80,15 +80,13 @@ endef # # The sed expression does this: # 1. Add a backslash before any :, = or ! that do not have a backslash already. -# 2. Apply the file unicode2x.sed which does a whole bunch of \u00XX to \xXX -# conversions. -# 3. Delete all lines starting with #. -# 4. Delete empty lines. -# 5. Append lines ending with \ with the next line. -# 6. Remove leading and trailing white space. Note that tabs must be explicit +# 2. Delete all lines starting with #. +# 3. Delete empty lines. +# 4. Append lines ending with \ with the next line. +# 5. Remove leading and trailing white space. Note that tabs must be explicit # as sed on macosx does not understand '\t'. -# 7. Replace the first \= with just =. -# 8. Finally it's all sorted to create a stable output. +# 6. Replace the first \= with just =. +# 7. Finally it's all sorted to create a stable output. # # It is assumed that = is the character used for separating names and values. define add_file_to_clean @@ -108,7 +106,6 @@ define add_file_to_clean ( $(CAT) $$< && $(ECHO) "" ) \ | $(SED) -e 's/\([^\\]\):/\1\\:/g' -e 's/\([^\\]\)=/\1\\=/g' \ -e 's/\([^\\]\)!/\1\\!/g' -e 's/^[ ]*#.*/#/g' \ - | $(SED) -f "$$(TOPDIR)/make/common/support/unicode2x.sed" \ | $(SED) -e '/^#/d' -e '/^$$$$/d' \ -e :a -e '/\\$$$$/N; s/\\\n//; ta' \ -e 's/^[ ]*//;s/[ ]*$$$$//' \ @@ -155,6 +152,7 @@ endef # INCLUDE_FILES "com/sun/SolarisFoobar.java" means only compile this file! # EXCLUDE_FILES "com/sun/SolarisFoobar.java" means do not compile this particular file! # "SolarisFoobar.java" means do not compile SolarisFoobar, wherever it is found. +# EXCLUDE_PATTERNS Exclude files matching any of these substrings # EXTRA_FILES List of extra source files to include in compilation. Can be used to # specify files that need to be generated by other rules first. # HEADERS path to directory where all generated c-headers are written. @@ -265,10 +263,12 @@ define SetupJavaCompilationBody endif # Tell javac to do exactly as told and no more - PARANOIA_FLAGS := -implicit:none -Xprefer:source -XDignore.symbol.file=true -encoding ascii + PARANOIA_FLAGS := -implicit:none -Xprefer:source -XDignore.symbol.file=true $1_FLAGS += -g -Xlint:all $$($1_TARGET_RELEASE) $$(PARANOIA_FLAGS) $1_FLAGS += $$($1_JAVAC_FLAGS) + # Set character encoding in source + $1_FLAGS += -encoding utf-8 ifeq ($$(JAVA_WARNINGS_AS_ERRORS), true) $1_FLAGS += -Werror @@ -333,6 +333,20 @@ define SetupJavaCompilationBody $1_INCLUDE_PATTERN += $$(foreach i, $$($1_SRC), $$(addprefix $$i/, $$(addsuffix /%, $$($1_INCLUDES)))) endif + ifneq ($$($1_EXCLUDE_PATTERNS), ) + # We must not match the exclude pattern against the src roots, so first + # strip the src prefixes from the absolute file paths in SRCS. + $1_SRCS_WITHOUT_ROOTS := $$(foreach i, $$($1_SRC), \ + $$(patsubst $$i/%,%, $$(filter $$i/%, $$($1_SRCS)))) + $1_EXCLUDE_PATTERNS_WITHOUT_ROOTS := $$(call containing, \ + $$($1_EXCLUDE_PATTERNS), $$($1_SRCS_WITHOUT_ROOTS)) + # The add back all possible src prefixes; this will generate more paths + # than really exists, but it does not matter since we will use this as + # input to filter-out. + $1_EXCLUDE_PATTERN += $$(foreach i, $$($1_SRC), $$(addprefix $$i/, \ + $$($1_EXCLUDE_PATTERNS_WITHOUT_ROOTS))) + endif + # Apply include/exclude patterns to java sources ifneq ($$($1_EXCLUDE_PATTERN), ) $1_SRCS := $$(filter-out $$($1_EXCLUDE_PATTERN), $$($1_SRCS)) diff --git a/make/common/JdkNativeCompilation.gmk b/make/common/JdkNativeCompilation.gmk index 372ad39305c..0285669ffd8 100644 --- a/make/common/JdkNativeCompilation.gmk +++ b/make/common/JdkNativeCompilation.gmk @@ -227,6 +227,8 @@ endef GLOBAL_VERSION_INFO_RESOURCE := $(TOPDIR)/src/java.base/windows/native/common/version.rc +# \xA9 is the copyright symbol in ANSI encoding (Windows-1252), which rc.exe +# assumes the resource file is in. JDK_RCFLAGS=$(RCFLAGS) \ -D"JDK_VERSION_STRING=$(VERSION_STRING)" \ -D"JDK_COMPANY=$(JDK_RC_COMPANY_NAME)" \ diff --git a/make/common/MakeFileStart.gmk b/make/common/MakeFileStart.gmk index f1dd0abb792..f18c623d3e8 100644 --- a/make/common/MakeFileStart.gmk +++ b/make/common/MakeFileStart.gmk @@ -47,7 +47,7 @@ endif # We need spec.gmk to get $(TOPDIR) include $(SPEC) -THIS_MAKEFILE := $(patsubst make/%,%,$(patsubst $(TOPDIR)/%,%,$(THIS_MAKEFILE_PATH))) +THIS_MAKEFILE := $(patsubst make/%,%,$(patsubst $(TOPDIR_ALT)/make/%,%,$(patsubst $(TOPDIR)/%,%,$(THIS_MAKEFILE_PATH)))) ifeq ($(LOG_FLOW), true) $(info :Enter $(THIS_MAKEFILE)) diff --git a/make/common/MakeIncludeStart.gmk b/make/common/MakeIncludeStart.gmk index d09f027c1d3..3904633f9f2 100644 --- a/make/common/MakeIncludeStart.gmk +++ b/make/common/MakeIncludeStart.gmk @@ -29,7 +29,7 @@ # Get the next to last word (by prepending a padding element) THIS_INCLUDE_PATH := $(word $(words ${MAKEFILE_LIST}),padding ${MAKEFILE_LIST}) -THIS_INCLUDE := $(patsubst $(TOPDIR)/make/%,%,$(THIS_INCLUDE_PATH)) +THIS_INCLUDE := $(patsubst $(TOPDIR_ALT)/make/%,%,$(patsubst $(TOPDIR)/make/%,%,$(THIS_INCLUDE_PATH))) # Print an indented message, also counting the top-level makefile as a level ifneq ($(INCLUDE_GUARD_$(THIS_INCLUDE)), true) diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 663e9075cf8..725424d7618 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -180,7 +180,7 @@ ifeq ($(GENERATE_MODULE_DEPS_FILE), true) $(call MakeTargetDir) $(RM) $@ $(foreach m, $(MODULE_INFOS), \ - ( $(ECHO) -n "DEPS_$(call GetModuleNameFromModuleInfo, $m) := " && \ + ( $(PRINTF) "DEPS_%s := " "$(call GetModuleNameFromModuleInfo, $m)" && \ $(AWK) -v MODULE=$(call GetModuleNameFromModuleInfo, $m) ' \ BEGIN { if (MODULE != "java.base") printf(" java.base"); } \ /^ *requires/ { sub(/;/, ""); \ @@ -194,7 +194,7 @@ ifeq ($(GENERATE_MODULE_DEPS_FILE), true) gsub(/\r/, ""); \ printf(" %s", $$0) } \ END { printf("\n") }' $m && \ - $(ECHO) -n "TRANSITIVE_MODULES_$(call GetModuleNameFromModuleInfo, $m) := " && \ + $(PRINTF) "TRANSITIVE_MODULES_%s := " "$(call GetModuleNameFromModuleInfo, $m)" && \ $(AWK) -v MODULE=$(call GetModuleNameFromModuleInfo, $m) ' \ BEGIN { if (MODULE != "java.base") printf(" java.base"); } \ /^ *requires *transitive/ { \ diff --git a/make/common/native/Paths.gmk b/make/common/native/Paths.gmk index ee097b2e134..bdb8828eb32 100644 --- a/make/common/native/Paths.gmk +++ b/make/common/native/Paths.gmk @@ -128,10 +128,9 @@ define SetupSourceFiles # Extract the C/C++ files. ifneq ($$($1_EXCLUDE_PATTERNS), ) # We must not match the exclude pattern against the src root(s). - $1_SRCS_WITHOUT_ROOTS := $$($1_SRCS) - $$(foreach i, $$($1_SRC), $$(eval $1_SRCS_WITHOUT_ROOTS := $$(patsubst \ - $$i/%,%, $$($1_SRCS_WITHOUT_ROOTS)))) - $1_ALL_EXCLUDE_FILES := $$(call containing, $$($1_EXCLUDE_PATTERNS), \ + $1_SRCS_WITHOUT_ROOTS := $$(foreach i, $$($1_SRC), \ + $$(patsubst $$i/%,%, $$(filter $$i/%, $$($1_SRCS)))) + $1_ALL_EXCLUDE_FILES := $$(call containing, $$($1_EXCLUDE_PATTERNS), \ $$($1_SRCS_WITHOUT_ROOTS)) endif ifneq ($$($1_EXCLUDE_FILES), ) diff --git a/make/common/support/unicode2x.sed b/make/common/support/unicode2x.sed deleted file mode 100644 index 5188b97fe03..00000000000 --- a/make/common/support/unicode2x.sed +++ /dev/null @@ -1,100 +0,0 @@ -s/\\u0020/\x20/g -s/\\u003A/\x3A/g -s/\\u006B/\x6B/g -s/\\u0075/\x75/g -s/\\u00A0/\xA0/g -s/\\u00A3/\xA3/g -s/\\u00B0/\xB0/g -s/\\u00B7/\xB7/g -s/\\u00BA/\xBA/g -s/\\u00BF/\xBF/g -s/\\u00C0/\xC0/g -s/\\u00C1/\xC1/g -s/\\u00C2/\xC2/g -s/\\u00C4/\xC4/g -s/\\u00C5/\xC5/g -s/\\u00C8/\xC8/g -s/\\u00C9/\xC9/g -s/\\u00CA/\xCA/g -s/\\u00CD/\xCD/g -s/\\u00CE/\xCE/g -s/\\u00D3/\xD3/g -s/\\u00D4/\xD4/g -s/\\u00D6/\xD6/g -s/\\u00DA/\xDA/g -s/\\u00DC/\xDC/g -s/\\u00DD/\xDD/g -s/\\u00DF/\xDF/g -s/\\u00E0/\xE0/g -s/\\u00E1/\xE1/g -s/\\u00E2/\xE2/g -s/\\u00E3/\xE3/g -s/\\u00E4/\xE4/g -s/\\u00E5/\xE5/g -s/\\u00E6/\xE6/g -s/\\u00E7/\xE7/g -s/\\u00E8/\xE8/g -s/\\u00E9/\xE9/g -s/\\u00EA/\xEA/g -s/\\u00EB/\xEB/g -s/\\u00EC/\xEC/g -s/\\u00ED/\xED/g -s/\\u00EE/\xEE/g -s/\\u00EF/\xEF/g -s/\\u00F1/\xF1/g -s/\\u00F2/\xF2/g -s/\\u00F3/\xF3/g -s/\\u00F4/\xF4/g -s/\\u00F5/\xF5/g -s/\\u00F6/\xF6/g -s/\\u00F9/\xF9/g -s/\\u00FA/\xFA/g -s/\\u00FC/\xFC/g -s/\\u0020/\x20/g -s/\\u003f/\x3f/g -s/\\u006f/\x6f/g -s/\\u0075/\x75/g -s/\\u00a0/\xa0/g -s/\\u00a3/\xa3/g -s/\\u00b0/\xb0/g -s/\\u00ba/\xba/g -s/\\u00bf/\xbf/g -s/\\u00c1/\xc1/g -s/\\u00c4/\xc4/g -s/\\u00c5/\xc5/g -s/\\u00c8/\xc8/g -s/\\u00c9/\xc9/g -s/\\u00ca/\xca/g -s/\\u00cd/\xcd/g -s/\\u00d6/\xd6/g -s/\\u00dc/\xdc/g -s/\\u00dd/\xdd/g -s/\\u00df/\xdf/g -s/\\u00e0/\xe0/g -s/\\u00e1/\xe1/g -s/\\u00e2/\xe2/g -s/\\u00e3/\xe3/g -s/\\u00e4/\xe4/g -s/\\u00e5/\xe5/g -s/\\u00e7/\xe7/g -s/\\u00e8/\xe8/g -s/\\u00e9/\xe9/g -s/\\u00ea/\xea/g -s/\\u00eb/\xeb/g -s/\\u00ec/\xec/g -s/\\u00ed/\xed/g -s/\\u00ee/\xee/g -s/\\u00ef/\xef/g -s/\\u00f0/\xf0/g -s/\\u00f1/\xf1/g -s/\\u00f2/\xf2/g -s/\\u00f3/\xf3/g -s/\\u00f4/\xf4/g -s/\\u00f5/\xf5/g -s/\\u00f6/\xf6/g -s/\\u00f7/\xf7/g -s/\\u00f8/\xf8/g -s/\\u00f9/\xf9/g -s/\\u00fa/\xfa/g -s/\\u00fc/\xfc/g -s/\\u00ff/\xff/g diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index 27845ffbd7a..d2b6cd23128 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -26,7 +26,7 @@ # Versions and download locations for dependencies used by GitHub Actions (GHA) GTEST_VERSION=1.14.0 -JTREG_VERSION=7.5.1+1 +JTREG_VERSION=7.5.2+1 LINUX_X64_BOOT_JDK_EXT=tar.gz LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk24/1f9ff9062db4449d8ca828c504ffae90/36/GPL/openjdk-24_linux-x64_bin.tar.gz diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index aa4d846280e..91876878046 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -241,10 +241,10 @@ var getJibProfilesCommon = function (input, data) { // List of the main profile names used for iteration common.main_profile_names = [ - "linux-x64", "linux-x86", "macosx-x64", "macosx-aarch64", + "macosx-x64", "macosx-aarch64", "windows-x64", "windows-aarch64", - "linux-aarch64", "linux-arm32", "linux-ppc64le", "linux-s390x", - "linux-riscv64" + "linux-x64", "linux-aarch64", + "linux-arm32", "linux-ppc64le", "linux-s390x", "linux-riscv64" ]; // These are the base settings for all the main build profiles. @@ -254,7 +254,6 @@ var getJibProfilesCommon = function (input, data) { configure_args: concat( "--with-exclude-translations=es,fr,it,ko,pt_BR,sv,ca,tr,cs,sk,ja_JP_A,ja_JP_HA,ja_JP_HI,ja_JP_I,zh_TW,zh_HK", "--disable-jvm-feature-shenandoahgc", - "--disable-cds-archive-coh", versionArgs(input, common)) }; @@ -283,9 +282,6 @@ var getJibProfilesCommon = function (input, data) { labels: "open" }; - common.configure_args_64bit = ["--with-target-bits=64"]; - common.configure_args_32bit = ["--with-target-bits=32"]; - /** * Define common artifacts template for all main profiles * @param o - Object containing data for artifacts @@ -412,58 +408,34 @@ var getJibProfilesProfiles = function (input, common, data) { // Main SE profiles var profiles = { - - "linux-x64": { - target_os: "linux", - target_cpu: "x64", - dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc", "tidy"], - configure_args: concat( - (input.build_cpu == "x64" ? common.configure_args_64bit - : "--openjdk-target=x86_64-linux-gnu"), - "--with-zlib=system", "--disable-dtrace", - (isWsl(input) ? [ "--host=x86_64-unknown-linux-gnu", - "--build=x86_64-unknown-linux-gnu" ] : [])), - }, - - "linux-x86": { - target_os: "linux", - target_cpu: "x86", - build_cpu: "x64", - dependencies: ["devkit", "gtest", "libffi"], - configure_args: concat(common.configure_args_32bit, [ - "--with-jvm-variants=minimal,server", - "--with-zlib=system", - "--with-libffi=" + input.get("libffi", "home_path"), - "--enable-libffi-bundling", - "--enable-fallback-linker" - ]) - }, - "macosx-x64": { target_os: "macosx", target_cpu: "x64", dependencies: ["devkit", "gtest", "graphviz", "pandoc", "tidy"], - configure_args: concat(common.configure_args_64bit, "--with-zlib=system", + configure_args: [ + "--with-zlib=system", "--with-macosx-version-max=11.00.00", "--enable-compatible-cds-alignment", // Use system SetFile instead of the one in the devkit as the // devkit one may not work on Catalina. - "SETFILE=/usr/bin/SetFile"), + "SETFILE=/usr/bin/SetFile" + ], }, "macosx-aarch64": { target_os: "macosx", target_cpu: "aarch64", dependencies: ["devkit", "gtest", "graphviz", "pandoc", "tidy"], - configure_args: concat(common.configure_args_64bit, - "--with-macosx-version-max=11.00.00"), + configure_args: [ + "--with-macosx-version-max=11.00.00" + ], }, "windows-x64": { target_os: "windows", target_cpu: "x64", dependencies: ["devkit", "gtest", "pandoc"], - configure_args: concat(common.configure_args_64bit), + configure_args: [], }, "windows-aarch64": { @@ -475,7 +447,19 @@ var getJibProfilesProfiles = function (input, common, data) { ], }, - "linux-aarch64": { + "linux-x64": { + target_os: "linux", + target_cpu: "x64", + dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc", "tidy"], + configure_args: concat( + "--with-zlib=system", + "--disable-dtrace", + (cross_compiling ? [ "--openjdk-target=x86_64-linux-gnu" ] : []), + (isWsl(input) ? [ "--host=x86_64-unknown-linux-gnu", + "--build=x86_64-unknown-linux-gnu" ] : [])), + }, + + "linux-aarch64": { target_os: "linux", target_cpu: "aarch64", dependencies: ["devkit", "gtest", "build_devkit", "graphviz", "pandoc", "tidy"], @@ -492,8 +476,10 @@ var getJibProfilesProfiles = function (input, common, data) { build_cpu: "x64", dependencies: ["devkit", "gtest", "build_devkit"], configure_args: [ - "--openjdk-target=arm-linux-gnueabihf", "--with-freetype=bundled", - "--with-abi-profile=arm-vfp-hflt", "--disable-warnings-as-errors" + "--openjdk-target=arm-linux-gnueabihf", + "--with-freetype=bundled", + "--with-abi-profile=arm-vfp-hflt", + "--disable-warnings-as-errors" ], }, @@ -503,7 +489,8 @@ var getJibProfilesProfiles = function (input, common, data) { build_cpu: "x64", dependencies: ["devkit", "gtest", "build_devkit"], configure_args: [ - "--openjdk-target=ppc64le-linux-gnu", "--with-freetype=bundled", + "--openjdk-target=ppc64le-linux-gnu", + "--with-freetype=bundled", "--disable-warnings-as-errors" ], }, @@ -514,7 +501,8 @@ var getJibProfilesProfiles = function (input, common, data) { build_cpu: "x64", dependencies: ["devkit", "gtest", "build_devkit"], configure_args: [ - "--openjdk-target=s390x-linux-gnu", "--with-freetype=bundled", + "--openjdk-target=s390x-linux-gnu", + "--with-freetype=bundled", "--disable-warnings-as-errors" ], }, @@ -525,7 +513,8 @@ var getJibProfilesProfiles = function (input, common, data) { build_cpu: "x64", dependencies: ["devkit", "gtest", "build_devkit"], configure_args: [ - "--openjdk-target=riscv64-linux-gnu", "--with-freetype=bundled", + "--openjdk-target=riscv64-linux-gnu", + "--with-freetype=bundled", "--disable-warnings-as-errors" ], }, @@ -586,24 +575,24 @@ var getJibProfilesProfiles = function (input, common, data) { target_os: "linux", target_cpu: "x64", dependencies: ["devkit", "gtest", "libffi"], - configure_args: concat(common.configure_args_64bit, [ + configure_args: [ "--with-zlib=system", "--with-jvm-variants=zero", "--with-libffi=" + input.get("libffi", "home_path"), "--enable-libffi-bundling", - ]) + ] }, "linux-aarch64-zero": { target_os: "linux", target_cpu: "aarch64", dependencies: ["devkit", "gtest", "libffi"], - configure_args: concat(common.configure_args_64bit, [ + configure_args: [ "--with-zlib=system", "--with-jvm-variants=zero", "--with-libffi=" + input.get("libffi", "home_path"), "--enable-libffi-bundling" - ]) + ] }, "linux-x86-zero": { @@ -611,12 +600,13 @@ var getJibProfilesProfiles = function (input, common, data) { target_cpu: "x86", build_cpu: "x64", dependencies: ["devkit", "gtest", "libffi"], - configure_args: concat(common.configure_args_32bit, [ + configure_args: [ + "--with-target-bits=32", "--with-zlib=system", "--with-jvm-variants=zero", "--with-libffi=" + input.get("libffi", "home_path"), "--enable-libffi-bundling" - ]) + ] } } profiles = concatObjects(profiles, zeroProfiles); @@ -635,8 +625,10 @@ var getJibProfilesProfiles = function (input, common, data) { target_os: "linux", target_cpu: "x64", dependencies: ["devkit", "gtest"], - configure_args: concat(common.configure_args_64bit, - "--with-zlib=system", "--disable-precompiled-headers"), + configure_args: [ + "--with-zlib=system", + "--disable-precompiled-headers" + ], }, }; profiles = concatObjects(profiles, noPchProfiles); @@ -693,9 +685,6 @@ var getJibProfilesProfiles = function (input, common, data) { "linux-x64": { platform: "linux-x64", }, - "linux-x86": { - platform: "linux-x86", - }, "macosx-x64": { platform: "macos-x64", jdk_subdir: "jdk-" + data.version + ".jdk/Contents/Home", @@ -872,7 +861,8 @@ var getJibProfilesProfiles = function (input, common, data) { profiles[cmpBaselineName].configure_args = concat( profiles[cmpBaselineName].configure_args, "--with-hotspot-build-time=n/a", - "--disable-precompiled-headers"); + "--disable-precompiled-headers", + "--with-source-date=version"); // Do not inherit artifact definitions from base profile delete profiles[cmpBaselineName].artifacts; }); @@ -1089,8 +1079,8 @@ var getJibProfilesDependencies = function (input, common) { var devkit_platform_revisions = { linux_x64: "gcc14.2.0-OL6.4+1.0", - macosx: "Xcode14.3.1+1.0", - windows_x64: "VS2022-17.6.5+1.0", + macosx: "Xcode15.4+1.0", + windows_x64: "VS2022-17.13.2+1.0", linux_aarch64: "gcc14.2.0-OL7.6+1.0", linux_arm: "gcc8.2.0-Fedora27+1.0", linux_ppc64le: "gcc14.2.0-Fedora_41+1.0", @@ -1161,10 +1151,7 @@ var getJibProfilesDependencies = function (input, common) { organization: common.organization, ext: "tar.gz", module: "devkit-" + devkit_cross_prefix + devkit_platform, - revision: devkit_platform_revisions[devkit_platform], - environment: { - "DEVKIT_HOME": input.get("devkit", "home_path"), - } + revision: devkit_platform_revisions[devkit_platform] }, build_devkit: { @@ -1187,9 +1174,9 @@ var getJibProfilesDependencies = function (input, common) { jtreg: { server: "jpg", product: "jtreg", - version: "7.5.1", + version: "7.5.2", build_number: "1", - file: "bundles/jtreg-7.5.1+1.zip", + file: "bundles/jtreg-7.5.2+1.zip", environment_name: "JT_HOME", environment_path: input.get("jtreg", "home_path") + "/bin", configure_args: "--with-jtreg=" + input.get("jtreg", "home_path"), diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index ce9e32315a9..38d6e42dff9 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=25 +DEFAULT_VERSION_FEATURE=26 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=2025-09-16 -DEFAULT_VERSION_CLASSFILE_MAJOR=69 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" +DEFAULT_VERSION_DATE=2026-03-17 +DEFAULT_VERSION_CLASSFILE_MAJOR=70 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="24 25" -DEFAULT_JDK_SOURCE_TARGET_VERSION=25 +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="24 25 26" +DEFAULT_JDK_SOURCE_TARGET_VERSION=26 DEFAULT_PROMOTED_VERSION_PRE=ea diff --git a/make/data/ubsan/ubsan_default_options.c b/make/data/ubsan/ubsan_default_options.c index 011d1a675a9..05e4722e45a 100644 --- a/make/data/ubsan/ubsan_default_options.c +++ b/make/data/ubsan/ubsan_default_options.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,18 @@ #define ATTRIBUTE_USED #endif +// On AIX, the llvm_symbolizer is not found out of the box, so we have to provide the +// full qualified llvm_symbolizer path in the __ubsan_default_options() function. +// To get it here we compile our sources with an additional define LLVM_SYMBOLIZER +// containing the path, which we set in make/autoconf/jdk-options.m4. +#ifdef LLVM_SYMBOLIZER +#define _LLVM_SYMBOLIZER(X) ",external_symbolizer_path=" X_LLVM_SYMBOLIZER(X) +#define X_LLVM_SYMBOLIZER(X) #X +#else +#define LLVM_SYMBOLIZER +#define _LLVM_SYMBOLIZER(X) +#endif + // Override weak symbol exposed by UBSan to override default options. This is called by UBSan // extremely early during library loading, before main is called. We need to override the default // options because by default UBSan only prints a warning for each occurrence. We want jtreg tests @@ -50,5 +62,5 @@ // thread so it is easier to track down. You can override these options by setting the environment // variable UBSAN_OPTIONS. ATTRIBUTE_DEFAULT_VISIBILITY ATTRIBUTE_USED const char* __ubsan_default_options() { - return "halt_on_error=1,print_stacktrace=1"; + return "halt_on_error=1,print_stacktrace=1" _LLVM_SYMBOLIZER(LLVM_SYMBOLIZER); } diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index f4323f58638..1b9240df49c 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -39,6 +39,8 @@ # Fix this... # +uppercase = $(shell echo $1 | tr a-z A-Z) + $(info TARGET=$(TARGET)) $(info HOST=$(HOST)) $(info BUILD=$(BUILD)) @@ -91,99 +93,28 @@ endif ################################################################################ # Define external dependencies -# Latest that could be made to work. -GCC_VER := 14.2.0 -ifeq ($(GCC_VER), 14.2.0) - gcc_ver := gcc-14.2.0 - binutils_ver := binutils-2.43 - ccache_ver := ccache-4.10.2 - CCACHE_CMAKE_BASED := 1 - mpfr_ver := mpfr-4.2.1 - gmp_ver := gmp-6.3.0 - mpc_ver := mpc-1.3.1 - gdb_ver := gdb-15.2 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 13.2.0) - gcc_ver := gcc-13.2.0 - binutils_ver := binutils-2.41 - ccache_ver := ccache-3.7.12 - mpfr_ver := mpfr-4.2.0 - gmp_ver := gmp-6.3.0 - mpc_ver := mpc-1.3.1 - gdb_ver := gdb-13.2 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 11.3.0) - gcc_ver := gcc-11.3.0 - binutils_ver := binutils-2.39 - ccache_ver := ccache-3.7.12 - mpfr_ver := mpfr-4.1.1 - gmp_ver := gmp-6.2.1 - mpc_ver := mpc-1.2.1 - gdb_ver := gdb-11.2 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else 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 - mpfr_ver := mpfr-4.1.0 - gmp_ver := gmp-6.2.0 - mpc_ver := mpc-1.1.0 - gdb_ver := gdb-10.1 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 10.2.0) - gcc_ver := gcc-10.2.0 - binutils_ver := binutils-2.35 - ccache_ver := ccache-3.7.11 - mpfr_ver := mpfr-4.1.0 - gmp_ver := gmp-6.2.0 - mpc_ver := mpc-1.1.0 - gdb_ver := gdb-9.2 - REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 -else ifeq ($(GCC_VER), 9.2.0) - gcc_ver := gcc-9.2.0 - binutils_ver := binutils-2.34 - ccache_ver := ccache-3.7.3 - mpfr_ver := mpfr-3.1.5 - gmp_ver := gmp-6.1.2 - mpc_ver := mpc-1.0.3 - gdb_ver := gdb-8.3 -else ifeq ($(GCC_VER), 8.3.0) - gcc_ver := gcc-8.3.0 - binutils_ver := binutils-2.32 - ccache_ver := ccache-3.7.3 - mpfr_ver := mpfr-3.1.5 - gmp_ver := gmp-6.1.2 - mpc_ver := mpc-1.0.3 - gdb_ver := gdb-8.3 -else ifeq ($(GCC_VER), 7.3.0) - gcc_ver := gcc-7.3.0 - binutils_ver := binutils-2.30 - ccache_ver := ccache-3.3.6 - mpfr_ver := mpfr-3.1.5 - gmp_ver := gmp-6.1.2 - mpc_ver := mpc-1.0.3 - gdb_ver := gdb-8.1 -else ifeq ($(GCC_VER), 4.9.2) - gcc_ver := gcc-4.9.2 - binutils_ver := binutils-2.25 - ccache_ver := ccache-3.2.1 - mpfr_ver := mpfr-3.0.1 - gmp_ver := gmp-4.3.2 - mpc_ver := mpc-1.0.1 - gdb_ver := gdb-7.12.1 -else - $(error Unsupported GCC version) -endif +gcc_ver_only := 14.2.0 +binutils_ver_only := 2.43 +ccache_ver_only := 4.10.2 +CCACHE_CMAKE_BASED := 1 +mpfr_ver_only := 4.2.1 +gmp_ver_only := 6.3.0 +mpc_ver_only := 1.3.1 +gdb_ver_only := 15.2 + +dependencies := gcc binutils ccache mpfr gmp mpc gdb +$(foreach dep,$(dependencies),$(eval $(dep)_ver := $(dep)-$($(dep)_ver_only))) + +GCC := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz +BINUTILS := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz +CCACHE := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz +MPFR := https://www.mpfr.org/$(mpfr_ver)/$(mpfr_ver).tar.bz2 +GMP := http://ftp.gnu.org/pub/gnu/gmp/$(gmp_ver).tar.bz2 +MPC := http://ftp.gnu.org/pub/gnu/mpc/$(mpc_ver).tar.gz +GDB := http://ftp.gnu.org/gnu/gdb/$(gdb_ver).tar.xz + +REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 ifneq ($(REQUIRED_MIN_MAKE_MAJOR_VERSION),) MAKE_MAJOR_VERSION := $(word 1,$(subst ., ,$(MAKE_VERSION))) SUPPORTED_MAKE_VERSION := $(shell [ $(MAKE_MAJOR_VERSION) -ge $(REQUIRED_MIN_MAKE_MAJOR_VERSION) ] && echo true) @@ -192,17 +123,6 @@ ifneq ($(REQUIRED_MIN_MAKE_MAJOR_VERSION),) endif endif -ccache_ver_only := $(patsubst ccache-%,%,$(ccache_ver)) - - -GCC := http://ftp.gnu.org/pub/gnu/gcc/$(gcc_ver)/$(gcc_ver).tar.xz -BINUTILS := http://ftp.gnu.org/pub/gnu/binutils/$(binutils_ver).tar.gz -CCACHE := https://github.com/ccache/ccache/releases/download/v$(ccache_ver_only)/$(ccache_ver).tar.xz -MPFR := https://www.mpfr.org/${mpfr_ver}/${mpfr_ver}.tar.bz2 -GMP := http://ftp.gnu.org/pub/gnu/gmp/${gmp_ver}.tar.bz2 -MPC := http://ftp.gnu.org/pub/gnu/mpc/${mpc_ver}.tar.gz -GDB := http://ftp.gnu.org/gnu/gdb/${gdb_ver}.tar.xz - # RPMs used by all BASE_OS RPM_LIST := \ $(KERNEL_HEADERS_RPM) \ @@ -297,7 +217,7 @@ define Download endef # Download and unpack all source packages -$(foreach p,GCC BINUTILS CCACHE MPFR GMP MPC GDB,$(eval $(call Download,$(p)))) +$(foreach dep,$(dependencies),$(eval $(call Download,$(call uppercase,$(dep))))) ################################################################################ # Unpack RPMS @@ -374,7 +294,7 @@ endif ################################################################################ # Define marker files for each source package to be compiled -$(foreach t,binutils mpfr gmp mpc gcc ccache gdb,$(eval $(t) = $(TARGETDIR)/$($(t)_ver).done)) +$(foreach dep,$(dependencies),$(eval $(dep) = $(TARGETDIR)/$($(dep)_ver).done)) ################################################################################ @@ -721,12 +641,12 @@ ifeq ($(TARGET), $(HOST)) ln -s $(TARGET)-$* $@ missing-links := $(addprefix $(PREFIX)/bin/, \ - addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(GCC_VER) gprof ld ld.bfd \ + addr2line ar as c++ c++filt dwp elfedit g++ gcc gcc-$(gcc_ver_only) gprof ld ld.bfd \ ld.gold nm objcopy objdump ranlib readelf size strings strip) endif # Add link to work around "plugin needed to handle lto object" (JDK-8344272) -$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(GCC_VER)/liblto_plugin.so +$(PREFIX)/lib/bfd-plugins/liblto_plugin.so: $(PREFIX)/libexec/gcc/$(TARGET)/$(gcc_ver_only)/liblto_plugin.so @echo 'Creating missing $(@F) soft link' @mkdir -p $(@D) ln -s $$(realpath -s --relative-to=$(@D) $<) $@ diff --git a/make/devkit/createAutoconfBundle.sh b/make/devkit/createAutoconfBundle.sh index 7363b9cd8a7..ebe9c427f76 100644 --- a/make/devkit/createAutoconfBundle.sh +++ b/make/devkit/createAutoconfBundle.sh @@ -1,6 +1,6 @@ #!/bin/bash -e # -# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,10 +24,21 @@ # questions. # -# Create a bundle in the current directory, containing what's needed to run +# Create a bundle in OpenJDK build folder, containing what's needed to run # the 'autoconf' program by the OpenJDK build. To override TARGET_PLATFORM # just set the variable before running this script. +# This script fetches sources from network so make sure your proxy is setup appropriately. + +# colored print to highlight some of the logs +function print_log() +{ + Color_Cyan='\033[1;36m' # Cyan + Color_Off='\033[0m' # Reset color + printf "${Color_Cyan}> $1${Color_Off}\n" +} + + # Autoconf depends on m4, so download and build that first. AUTOCONF_VERSION=2.69 M4_VERSION=1.4.18 @@ -58,11 +69,12 @@ MODULE_NAME=autoconf-$TARGET_PLATFORM-$AUTOCONF_VERSION+$PACKAGE_VERSION BUNDLE_NAME=$MODULE_NAME.tar.gz SCRIPT_DIR="$(cd "$(dirname $0)" > /dev/null && pwd)" -OUTPUT_ROOT="${SCRIPT_DIR}/../../build/autoconf" +BASEDIR="$(cd "$SCRIPT_DIR/../.." > /dev/null && pwd)" +OUTPUT_ROOT="$BASEDIR/build/autoconf" -cd $OUTPUT_ROOT IMAGE_DIR=$OUTPUT_ROOT/$MODULE_NAME mkdir -p $IMAGE_DIR/usr +cd $OUTPUT_ROOT # Download and build m4 @@ -76,7 +88,7 @@ elif test "x$TARGET_PLATFORM" = xcygwin_x86; then cp /usr/bin/m4 $IMAGE_DIR/usr/bin elif test "x$TARGET_PLATFORM" = xlinux_x64; then M4_VERSION=1.4.13-5 - wget http://yum.oracle.com/repo/OracleLinux/OL6/latest/x86_64/getPackage/m4-$M4_VERSION.el6.x86_64.rpm + wget https://yum.oracle.com/repo/OracleLinux/OL6/latest/x86_64/getPackage/m4-$M4_VERSION.el6.x86_64.rpm cd $IMAGE_DIR rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.x86_64.rpm | cpio -d -i elif test "x$TARGET_PLATFORM" = xlinux_x86; then @@ -85,27 +97,38 @@ elif test "x$TARGET_PLATFORM" = xlinux_x86; then cd $IMAGE_DIR rpm2cpio $OUTPUT_ROOT/m4-$M4_VERSION.el6.i686.rpm | cpio -d -i else + print_log "m4: download" wget https://ftp.gnu.org/gnu/m4/m4-$M4_VERSION.tar.gz - tar xzf m4-$M4_VERSION.tar.gz + tar -xzf m4-$M4_VERSION.tar.gz cd m4-$M4_VERSION + print_log "m4: configure" ./configure --prefix=$IMAGE_DIR/usr CFLAGS="-w -Wno-everything" + print_log "m4: make" make + print_log "m4: make install" make install cd .. fi # Download and build autoconf +print_log "autoconf: download" wget https://ftp.gnu.org/gnu/autoconf/autoconf-$AUTOCONF_VERSION.tar.gz -tar xzf autoconf-$AUTOCONF_VERSION.tar.gz +tar -xzf autoconf-$AUTOCONF_VERSION.tar.gz cd autoconf-$AUTOCONF_VERSION +print_log "autoconf: configure" ./configure --prefix=$IMAGE_DIR/usr M4=$IMAGE_DIR/usr/bin/m4 +print_log "autoconf: make" make +print_log "autoconf: make install" make install cd .. +# The resulting scripts from installation folder use absolute paths to reference other files within installation folder +print_log "replace absolue paths from installation files with a relative ." perl -pi -e "s!$IMAGE_DIR/!./!" $IMAGE_DIR/usr/bin/auto* $IMAGE_DIR/usr/share/autoconf/autom4te.cfg +print_log "creating $IMAGE_DIR/autoconf wrapper script" cat > $IMAGE_DIR/autoconf << EOF #!/bin/bash # Get an absolute path to this script @@ -123,6 +146,9 @@ PREPEND_INCLUDE="--prepend-include \$this_script_dir/usr/share/autoconf" exec \$this_script_dir/usr/bin/autoconf \$PREPEND_INCLUDE "\$@" EOF + chmod +x $IMAGE_DIR/autoconf + +print_log "archiving $IMAGE_DIR directory as $OUTPUT_ROOT/$BUNDLE_NAME" cd $IMAGE_DIR tar -cvzf $OUTPUT_ROOT/$BUNDLE_NAME * diff --git a/make/devkit/createWindowsDevkit.sh b/make/devkit/createWindowsDevkit.sh index 0646cb68ef4..757fb157ad4 100644 --- a/make/devkit/createWindowsDevkit.sh +++ b/make/devkit/createWindowsDevkit.sh @@ -56,16 +56,22 @@ BUILD_DIR="${SCRIPT_DIR}/../../build/devkit" UNAME_SYSTEM=`uname -s` UNAME_RELEASE=`uname -r` +UNAME_OS=`uname -o` # Detect cygwin or WSL IS_CYGWIN=`echo $UNAME_SYSTEM | grep -i CYGWIN` IS_WSL=`echo $UNAME_RELEASE | grep Microsoft` +IS_MSYS=`echo $UNAME_OS | grep -i Msys` +MSYS2_ARG_CONV_EXCL="*" # make "cmd.exe /c" work for msys2 +CMD_EXE="cmd.exe /c" if test "x$IS_CYGWIN" != "x"; then BUILD_ENV="cygwin" +elif test "x$IS_MSYS" != "x"; then + BUILD_ENV="cygwin" elif test "x$IS_WSL" != "x"; then BUILD_ENV="wsl" else - echo "Unknown environment; only Cygwin and WSL are supported." + echo "Unknown environment; only Cygwin/MSYS2/WSL are supported." exit 1 fi @@ -76,7 +82,7 @@ elif test "x$BUILD_ENV" = "xwsl"; then fi # Work around the insanely named ProgramFiles(x86) env variable -PROGRAMFILES_X86="$($WINDOWS_PATH_TO_UNIX_PATH "$(cmd.exe /c set | sed -n 's/^ProgramFiles(x86)=//p' | tr -d '\r')")" +PROGRAMFILES_X86="$($WINDOWS_PATH_TO_UNIX_PATH "$(${CMD_EXE} set | sed -n 's/^ProgramFiles(x86)=//p' | tr -d '\r')")" PROGRAMFILES="$($WINDOWS_PATH_TO_UNIX_PATH "$PROGRAMFILES")" case $VS_VERSION in @@ -99,13 +105,15 @@ esac # Find Visual Studio installation dir -VSNNNCOMNTOOLS=`cmd.exe /c echo %VS${VS_VERSION_NUM_NODOT}COMNTOOLS% | tr -d '\r'` +VSNNNCOMNTOOLS=`${CMD_EXE} echo %VS${VS_VERSION_NUM_NODOT}COMNTOOLS% | tr -d '\r'` +VSNNNCOMNTOOLS="$($WINDOWS_PATH_TO_UNIX_PATH "$VSNNNCOMNTOOLS")" if [ -d "$VSNNNCOMNTOOLS" ]; then - VS_INSTALL_DIR="$($WINDOWS_PATH_TO_UNIX_PATH "$VSNNNCOMNTOOLS/../..")" + VS_INSTALL_DIR="$VSNNNCOMNTOOLS/../.." else VS_INSTALL_DIR="${MSVC_PROGRAMFILES_DIR}/Microsoft Visual Studio/$VS_VERSION" VS_INSTALL_DIR="$(ls -d "${VS_INSTALL_DIR}/"{Community,Professional,Enterprise} 2>/dev/null | head -n1)" fi +echo "VSNNNCOMNTOOLS: $VSNNNCOMNTOOLS" echo "VS_INSTALL_DIR: $VS_INSTALL_DIR" # Extract semantic version @@ -180,7 +188,11 @@ cp $DEVKIT_ROOT/VC/redist/arm64/$MSVCP_DLL $DEVKIT_ROOT/VC/bin/arm64 ################################################################################ # Copy SDK files -SDK_INSTALL_DIR="$PROGRAMFILES_X86/Windows Kits/$SDK_VERSION" +SDK_INSTALL_DIR=`${CMD_EXE} echo %WindowsSdkDir% | tr -d '\r'` +SDK_INSTALL_DIR="$($WINDOWS_PATH_TO_UNIX_PATH "$SDK_INSTALL_DIR")" +if [ ! -d "$SDK_INSTALL_DIR" ]; then + SDK_INSTALL_DIR="$PROGRAMFILES_X86/Windows Kits/$SDK_VERSION" +fi echo "SDK_INSTALL_DIR: $SDK_INSTALL_DIR" SDK_FULL_VERSION="$(ls "$SDK_INSTALL_DIR/bin" | sort -r -n | head -n1)" diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk index 0a897230f83..0fd1c752174 100644 --- a/make/hotspot/lib/JvmFeatures.gmk +++ b/make/hotspot/lib/JvmFeatures.gmk @@ -125,9 +125,11 @@ endif ifneq ($(call check-jvm-feature, cds), true) JVM_CFLAGS_FEATURES += -DINCLUDE_CDS=0 JVM_EXCLUDE_FILES += \ + aotCodeCache.cpp \ classLoaderDataShared.cpp \ classLoaderExt.cpp \ - systemDictionaryShared.cpp + systemDictionaryShared.cpp \ + trainingData.cpp JVM_EXCLUDE_PATTERNS += cds/ endif diff --git a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java index 1b930ca7527..fa1b33bb03e 100644 --- a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java +++ b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ public class HelloClasslist { private static final Logger LOGGER = Logger.getLogger("Hello"); + @SuppressWarnings("restricted") public static void main(String ... args) throws Throwable { FileSystems.getDefault(); @@ -141,6 +142,7 @@ public static void main(String ... args) throws Throwable { HelloClasslist.class.getMethod("staticMethod_V").invoke(null); var obj = HelloClasslist.class.getMethod("staticMethod_L_L", Object.class).invoke(null, instance); HelloClasslist.class.getField("field").get(instance); + MethodHandles.Lookup.ClassOption.class.getEnumConstants(); // A selection of trivial and relatively common MH operations invoke(MethodHandles.identity(double.class), 1.0); @@ -160,6 +162,9 @@ record B(int b) { } case B b -> b.b; default -> 17; }; + // record run-time methods + o.equals(new B(5)); + o.hashCode(); LOGGER.log(Level.FINE, "Value: " + value); // The Striped64$Cell is loaded rarely only when there's a contention among diff --git a/make/jdk/src/classes/build/tools/generatecharacter/GenerateCharacter.java b/make/jdk/src/classes/build/tools/generatecharacter/GenerateCharacter.java index 8d6a703f1c9..a2f37db72d9 100644 --- a/make/jdk/src/classes/build/tools/generatecharacter/GenerateCharacter.java +++ b/make/jdk/src/classes/build/tools/generatecharacter/GenerateCharacter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1190,7 +1190,7 @@ static void genTable(StringBuffer result, String name, if (Csyntax) result.append(" static "); else - result.append(" static final "); + result.append(" @Stable static final "); result.append(atype); result.append(" ").append(name).append("["); if (Csyntax) @@ -1347,7 +1347,7 @@ else if (bits == 64) { } static void genCaseMapTableDeclaration(StringBuffer result) { - result.append(" static final char[][][] charMap;\n"); + result.append(" @Stable static final char[][][] charMap;\n"); } static void genCaseMapTable(StringBuffer result, SpecialCaseMap[] specialCaseMaps){ diff --git a/make/jdk/src/classes/build/tools/pandocfilter/PandocFilter.java b/make/jdk/src/classes/build/tools/pandocfilter/PandocFilter.java index 64eeaaa36df..ebb49613e53 100644 --- a/make/jdk/src/classes/build/tools/pandocfilter/PandocFilter.java +++ b/make/jdk/src/classes/build/tools/pandocfilter/PandocFilter.java @@ -1,3 +1,26 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package build.tools.pandocfilter; import build.tools.pandocfilter.json.JSON; diff --git a/make/jdk/src/classes/build/tools/taglet/PreviewNote.java b/make/jdk/src/classes/build/tools/taglet/PreviewNote.java deleted file mode 100644 index ee3f9bea527..00000000000 --- a/make/jdk/src/classes/build/tools/taglet/PreviewNote.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.taglet; - -import java.util.EnumSet; -import java.util.List; -import java.util.Set; - - -import javax.lang.model.element.Element; -import javax.tools.Diagnostic; - - -import com.sun.source.doctree.DocTree; -import com.sun.source.doctree.UnknownInlineTagTree; -import jdk.javadoc.doclet.Doclet; -import jdk.javadoc.doclet.DocletEnvironment; -import jdk.javadoc.doclet.Reporter; -import jdk.javadoc.doclet.StandardDoclet; -import jdk.javadoc.doclet.Taglet; - -import static com.sun.source.doctree.DocTree.Kind.UNKNOWN_INLINE_TAG; - -/** - * An inline tag to insert a note formatted as preview note. - * The tag can be used as follows: - * - *

          - * {@previewNote jep-number [Preview note heading]}
          - * Preview note content
          - * {@previewNote}
          - * 
          - * - */ -public class PreviewNote implements Taglet { - - static final String TAG_NAME = "previewNote"; - Reporter reporter = null; - - @Override - public void init(DocletEnvironment env, Doclet doclet) { - if (doclet instanceof StandardDoclet stdoclet) { - reporter = stdoclet.getReporter(); - } - } - - /** - * Returns the set of locations in which the tag may be used. - */ - @Override - public Set getAllowedLocations() { - return EnumSet.allOf(Taglet.Location.class); - } - - @Override - public boolean isInlineTag() { - return true; - } - - @Override - public String getName() { - return TAG_NAME; - } - - @Override - public String toString(List tags, Element elem) { - - for (DocTree tag : tags) { - if (tag.getKind() == UNKNOWN_INLINE_TAG) { - UnknownInlineTagTree inlineTag = (UnknownInlineTagTree) tag; - String[] content = inlineTag.getContent().toString().trim().split("\\s+", 2); - if (!content[0].isBlank()) { - StringBuilder sb = new StringBuilder(""" -
          - """); - if (content.length == 2) { - sb.append(""" -
          - """) - .append(content[1]) - .append(""" -
          - """); - } - sb.append(""" -
          - """); - return sb.toString(); - } else { - return """ -
          -
          - """; - } - } - } - - if (reporter == null) { - throw new IllegalArgumentException("@" + TAG_NAME + " taglet content must be begin or end"); - } - reporter.print(Diagnostic.Kind.ERROR, "@" + TAG_NAME + " taglet content must be begin or end"); - return ""; - } -} diff --git a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java index db8924c79fb..fe5938ce0e3 100644 --- a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java +++ b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java @@ -46,6 +46,8 @@ import java.io.StringWriter; import java.io.Writer; import java.lang.classfile.*; +import java.lang.classfile.TypeAnnotation.TargetInfo; +import java.lang.classfile.TypeAnnotation.TypePathComponent; import java.lang.classfile.attribute.*; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantPoolBuilder; @@ -64,6 +66,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.BasicFileAttributes; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; import java.util.stream.Stream; import java.util.ArrayList; import java.util.Arrays; @@ -101,10 +106,7 @@ import com.sun.source.util.JavacTask; import com.sun.tools.javac.api.JavacTool; -import com.sun.tools.javac.jvm.Target; -import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Pair; import java.nio.file.DirectoryStream; import java.util.Optional; import java.util.function.Consumer; @@ -304,13 +306,18 @@ public void createSymbols(String ctDescriptionFileExtra, String ctDescriptionFil "Ljdk/internal/ValueBased;"; private static final String VALUE_BASED_ANNOTATION_INTERNAL = "Ljdk/internal/ValueBased+Annotation;"; + private static final String REQUIRES_IDENTITY_ANNOTATION = + "Ljdk/internal/RequiresIdentity;"; + private static final String REQUIRES_IDENTITY_ANNOTATION_INTERNAL = + "Ljdk/internal/RequiresIdentity+Annotation;"; public static final Set HARDCODED_ANNOTATIONS = new HashSet<>( List.of("Ljdk/Profile+Annotation;", "Lsun/Proprietary+Annotation;", PREVIEW_FEATURE_ANNOTATION_OLD, PREVIEW_FEATURE_ANNOTATION_NEW, VALUE_BASED_ANNOTATION, - RESTRICTED_ANNOTATION)); + RESTRICTED_ANNOTATION, + REQUIRES_IDENTITY_ANNOTATION)); private void stripNonExistentAnnotations(LoadDescriptions data) { Set allClasses = data.classes.name2Class.keySet(); @@ -339,10 +346,10 @@ private void stripNonExistentAnnotations(Set allClasses, List createAnnotations(List desc) { @@ -1021,6 +1034,12 @@ private Annotation createAnnotation(AnnotationDescription desc) { annotationType = VALUE_BASED_ANNOTATION_INTERNAL; } + if (REQUIRES_IDENTITY_ANNOTATION.equals(annotationType)) { + //the non-public RequiresIdentity annotation will not be available in ct.sym, + //replace with purely synthetic javac-internal annotation: + annotationType = REQUIRES_IDENTITY_ANNOTATION_INTERNAL; + } + if (RESTRICTED_ANNOTATION.equals(annotationType)) { //the non-public Restricted annotation will not be available in ct.sym, //replace with purely synthetic javac-internal annotation: @@ -1055,6 +1074,44 @@ private AnnotationValue createAttributeValue(Object value) { default -> throw new IllegalArgumentException(value.getClass().getName()); }; } + + private List createTypeAnnotations(List desc) { + return desc.stream().map(this::createTypeAnnotation).collect(Collectors.toList()); + } + + private TypeAnnotation createTypeAnnotation(TypeAnnotationDescription desc) { + Annotation baseAnn = createAnnotation(desc.annotation); + TargetInfo targetInfo = switch ((String) desc.targetInfo.get("targetType")) { + case "CLASS_TYPE_PARAMETER" -> //TODO: test! + TargetInfo.ofClassTypeParameter((int) desc.targetInfo.get("typeParameterIndex")); + case "METHOD_TYPE_PARAMETER" -> + TargetInfo.ofMethodTypeParameter((int) desc.targetInfo.get("typeParameterIndex")); + case "CLASS_EXTENDS" -> + TargetInfo.ofClassExtends((int) desc.targetInfo.get("supertypeIndex")); + case "CLASS_TYPE_PARAMETER_BOUND" -> + TargetInfo.ofClassTypeParameterBound((int) desc.targetInfo.get("typeParameterIndex"), + (int) desc.targetInfo.get("boundIndex")); + case "METHOD_TYPE_PARAMETER_BOUND" -> + TargetInfo.ofMethodTypeParameterBound((int) desc.targetInfo.get("typeParameterIndex"), + (int) desc.targetInfo.get("boundIndex")); + case "METHOD_RETURN" -> + TargetInfo.ofMethodReturn(); + case "METHOD_RECEIVER" -> + TargetInfo.ofMethodReceiver(); + case "METHOD_FORMAL_PARAMETER" -> + TargetInfo.ofMethodFormalParameter((int) desc.targetInfo.get("formalParameterIndex")); + case "THROWS" -> + TargetInfo.ofThrows((int) desc.targetInfo.get("throwsTargetIndex")); + case "FIELD" -> + TargetInfo.ofField(); + case String targetType -> + throw new IllegalStateException("Unsupported targetType: " + targetType); + }; + + List typePath = desc.typePath.stream().map(d -> TypePathComponent.of(TypePathComponent.Kind.valueOf(d.tag()), d.index())).toList(); + + return TypeAnnotation.of(targetInfo, typePath, baseAnn); + } // // @@ -2202,6 +2259,10 @@ private boolean readAttribute(FeatureDescription feature, Attribute attr) { chd.permittedSubclasses = a.permittedSubclasses().stream().map(ClassEntry::asInternalName).collect(Collectors.toList()); } case ModuleMainClassAttribute a -> ((ModuleHeaderDescription) feature).moduleMainClass = a.mainClass().asInternalName(); + case RuntimeInvisibleTypeAnnotationsAttribute a -> + feature.classTypeAnnotations = typeAnnotations2Descriptions(a.annotations()); + case RuntimeVisibleTypeAnnotationsAttribute a -> + feature.runtimeTypeAnnotations = typeAnnotations2Descriptions(a.annotations()); default -> throw new IllegalArgumentException("Unhandled attribute: " + attr.attributeName()); // Do nothing } @@ -2258,6 +2319,31 @@ private AnnotationDescription annotation2Description(java.lang.classfile.Annotat return new AnnotationDescription(annotationType, values); } + + private List typeAnnotations2Descriptions(List annos) { + return annos.stream().map(ta -> { + TypeAnnotationDescription desc = new TypeAnnotationDescription(); + desc.annotation = annotation2Description(ta.annotation()); + desc.targetInfo = new HashMap<>(); + desc.targetInfo.put("targetType", ta.targetInfo().targetType().name()); + switch (ta.targetInfo()) { + case TypeAnnotation.TypeParameterTarget tpt -> desc.targetInfo.put("typeParameterIndex", tpt.typeParameterIndex()); + case TypeAnnotation.SupertypeTarget st -> desc.targetInfo.put("supertypeIndex", st.supertypeIndex()); + case TypeAnnotation.TypeParameterBoundTarget tpbt -> { + desc.targetInfo.put("typeParameterIndex", tpbt.typeParameterIndex()); + desc.targetInfo.put("boundIndex", tpbt.boundIndex()); + } + case TypeAnnotation.EmptyTarget _ -> { + // nothing to write + } + case TypeAnnotation.FormalParameterTarget fpt -> desc.targetInfo.put("formalParameterIndex", fpt.formalParameterIndex()); + case TypeAnnotation.ThrowsTarget tt -> desc.targetInfo.put("throwsTargetIndex", tt.throwsTargetIndex()); + default -> throw new IllegalStateException(ta.targetInfo().targetType().name()); + } + desc.typePath = ta.targetPath().stream().map(tpc -> new TypeAnnotationDescription.TypePathComponentDesc(tpc.typePathKind().name(), tpc.typeArgumentIndex())).toList(); + return desc; + }).toList(); + } // protected boolean includeEffectiveAccess(ClassList classes, ClassDescription clazz) { @@ -2379,6 +2465,8 @@ static abstract class FeatureDescription { String versions = ""; List classAnnotations; List runtimeAnnotations; + List classTypeAnnotations; + List runtimeTypeAnnotations; protected void writeAttributes(Appendable output) throws IOException { if (flags != 0) @@ -2401,6 +2489,18 @@ protected void writeAttributes(Appendable output) throws IOException { output.append(quote(a.toString(), false)); } } + if (classTypeAnnotations != null && !classTypeAnnotations.isEmpty()) { + output.append(" classTypeAnnotations "); + for (TypeAnnotationDescription a : classTypeAnnotations) { + output.append(quote(a.toString(), false)); + } + } + if (runtimeTypeAnnotations != null && !runtimeTypeAnnotations.isEmpty()) { + output.append(" runtimeTypeAnnotations "); + for (TypeAnnotationDescription a : runtimeTypeAnnotations) { + output.append(quote(a.toString(), false)); + } + } } protected boolean shouldIgnore(String baselineVersion, String version) { @@ -2430,6 +2530,14 @@ protected void readAttributes(LineBasedReader reader) { if (inRuntimeAnnotations != null) { runtimeAnnotations = parseAnnotations(inRuntimeAnnotations, new int[1]); } + String inClassTypeAnnotations = reader.attributes.get("classTypeAnnotations"); + if (inClassTypeAnnotations != null) { + classTypeAnnotations = parseTypeAnnotations(inClassTypeAnnotations, new int[1]); + } + String inRuntimeTypeAnnotations = reader.attributes.get("runtimeTypeAnnotations"); + if (inRuntimeTypeAnnotations != null) { + runtimeTypeAnnotations = parseTypeAnnotations(inRuntimeTypeAnnotations, new int[1]); + } } public abstract boolean read(LineBasedReader reader) throws IOException; @@ -2442,6 +2550,8 @@ public int hashCode() { hash = 89 * hash + Objects.hashCode(this.signature); hash = 89 * hash + listHashCode(this.classAnnotations); hash = 89 * hash + listHashCode(this.runtimeAnnotations); + hash = 89 * hash + listHashCode(this.classTypeAnnotations); + hash = 89 * hash + listHashCode(this.runtimeTypeAnnotations); return hash; } @@ -2469,6 +2579,12 @@ public boolean equals(Object obj) { if (!listEquals(this.runtimeAnnotations, other.runtimeAnnotations)) { return false; } + if (!listEquals(this.classTypeAnnotations, other.classTypeAnnotations)) { + return false; + } + if (!listEquals(this.runtimeTypeAnnotations, other.runtimeTypeAnnotations)) { + return false; + } return true; } @@ -3273,6 +3389,8 @@ public int hashCode() { hash = 59 * hash + Objects.hashCode(this.descriptor); hash = 59 * hash + Objects.hashCode(this.thrownTypes); hash = 59 * hash + Objects.hashCode(this.annotationDefaultValue); + hash = 59 * hash + Objects.hashCode(this.classParameterAnnotations); + hash = 59 * hash + Objects.hashCode(this.runtimeParameterAnnotations); return hash; } @@ -3297,6 +3415,12 @@ public boolean equals(Object obj) { if (!Objects.equals(this.annotationDefaultValue, other.annotationDefaultValue)) { return false; } + if (!Objects.equals(this.classParameterAnnotations, other.classParameterAnnotations)) { + return false; + } + if (!Objects.equals(this.runtimeParameterAnnotations, other.runtimeParameterAnnotations)) { + return false; + } return true; } @@ -3624,6 +3748,40 @@ private static String dumpAnnotationValue(Object value) { } } + static final class TypeAnnotationDescription { + AnnotationDescription annotation; + Map targetInfo; + List typePath; + + public TypeAnnotationDescription() { + } + + public TypeAnnotationDescription(AnnotationDescription annotation, Map targetInfo, List typePath) { + this.annotation = annotation; + this.targetInfo = targetInfo; + this.typePath = typePath; + } + + @Override + public String toString() { + return annotation.toString() + "{" + targetInfo.entrySet().stream().map(e -> e.getKey() + "=" + quote(printValue(e.getValue()), false)).collect(Collectors.joining(",")) + "}" + + (!typePath.isEmpty() ? "[" + typePath.stream().map(desc -> desc.tag + ":" + desc.index).collect(Collectors.joining(",")) + "]" : ""); + } + + private String printValue(Object obj) { + if (obj instanceof String s) { + return "\"" + s + "\""; + } else if (obj instanceof Integer i) { + return "I" + String.valueOf(i); + } else { + throw new IllegalStateException("Unsupported value: " + obj.getClass()); + } + } + + //TODO: path + record TypePathComponentDesc(String tag, int index) {} + } + static final class EnumConstant { String type; String constant; @@ -3963,23 +4121,69 @@ public static List parseAnnotations(String encoded, int[] private static AnnotationDescription parseAnnotation(String value, int[] valuePointer) { String className = className(value, valuePointer); - Map attribute2Value = new HashMap<>(); + Map attribute2Value = Map.of(); if (valuePointer[0] < value.length() && value.charAt(valuePointer[0]) == '(') { - while (value.charAt(valuePointer[0]) != ')') { + attribute2Value = parseMap(value, valuePointer, ')'); + } + + return new AnnotationDescription(className, attribute2Value); + } + + private static Map parseMap(String value, int[] valuePointer, char endBracket) { + Map attribute2Value = new HashMap<>(); + + while (value.charAt(valuePointer[0]) != endBracket) { + int nameStart = ++valuePointer[0]; + + while (value.charAt(valuePointer[0]++) != '='); + + String name = value.substring(nameStart, valuePointer[0] - 1); + + attribute2Value.put(name, parseAnnotationValue(value, valuePointer)); + } + + valuePointer[0]++; + + return attribute2Value; + } + + public static List parseTypeAnnotations(String encoded, int[] pointer) { + List result = new ArrayList<>(); + + while (pointer[0] < encoded.length() && encoded.charAt(pointer[0]) == '@') { + pointer[0]++; + result.add(parseTypeAnnotation(encoded, pointer)); + } + + return result; + } + + private static TypeAnnotationDescription parseTypeAnnotation(String value, int[] valuePointer) { + AnnotationDescription ann = parseAnnotation(value, valuePointer); + Map targetInfo = Map.of(); + + if (valuePointer[0] < value.length() && value.charAt(valuePointer[0]) == '{') { + targetInfo = parseMap(value, valuePointer, '}'); + } + + List typePath = new ArrayList<>(); + + if (valuePointer[0] < value.length() && value.charAt(valuePointer[0]) == '[') { + while (value.charAt(valuePointer[0]) != ']') { int nameStart = ++valuePointer[0]; - while (value.charAt(valuePointer[0]++) != '='); + while (value.charAt(valuePointer[0]++) != ':'); String name = value.substring(nameStart, valuePointer[0] - 1); - attribute2Value.put(name, parseAnnotationValue(value, valuePointer)); + typePath.add(new TypeAnnotationDescription.TypePathComponentDesc(name, Integer.parseInt(readDigits(value, valuePointer)))); } valuePointer[0]++; } - return new AnnotationDescription(className, attribute2Value); + return new TypeAnnotationDescription(ann, targetInfo, typePath); } // diff --git a/make/modules/java.base/Java.gmk b/make/modules/java.base/Java.gmk index 84344f93409..fc091377456 100644 --- a/make/modules/java.base/Java.gmk +++ b/make/modules/java.base/Java.gmk @@ -41,11 +41,6 @@ CLEAN += intrinsic.properties EXCLUDE_FILES += \ $(TOPDIR)/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java -EXCLUDES += java/lang/doc-files \ - java/lang/classfile/snippet-files \ - java/lang/classfile/components/snippet-files \ - java/lang/foreign/snippet-files - # Exclude BreakIterator classes that are just used in compile process to generate # data files and shouldn't go in the product EXCLUDE_FILES += sun/text/resources/BreakIteratorRules.java diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk index 84ee309dadd..51d323a0344 100644 --- a/make/modules/java.base/Lib.gmk +++ b/make/modules/java.base/Lib.gmk @@ -158,6 +158,7 @@ endif $(eval $(call SetupJdkLibrary, BUILD_LIBSYSLOOKUP, \ NAME := syslookup, \ + EXTRA_HEADER_DIRS := java.base:libjava, \ LD_SET_ORIGIN := false, \ LDFLAGS_linux := -Wl$(COMMA)--no-as-needed, \ LDFLAGS_aix := -brtl -bexpfull, \ diff --git a/make/modules/java.compiler/Java.gmk b/make/modules/java.compiler/Java.gmk index cb720672639..d0a1fbf4cd5 100644 --- a/make/modules/java.compiler/Java.gmk +++ b/make/modules/java.compiler/Java.gmk @@ -32,6 +32,4 @@ DOCLINT += -Xdoclint:all/protected \ '-Xdoclint/package:java.*,javax.*' -EXCLUDES += javax/tools/snippet-files - ################################################################################ diff --git a/make/modules/java.desktop/Java.gmk b/make/modules/java.desktop/Java.gmk index 61c7fa44e0e..bab6186fb0d 100644 --- a/make/modules/java.desktop/Java.gmk +++ b/make/modules/java.desktop/Java.gmk @@ -31,15 +31,6 @@ DOCLINT += -Xdoclint:all/protected \ COPY += .gif .png .wav .txt .xml .css .pf CLEAN += iio-plugin.properties cursors.properties -EXCLUDES += \ - java/awt/doc-files \ - javax/swing/doc-files \ - javax/swing/text/doc-files \ - javax/swing/plaf/synth/doc-files \ - javax/swing/undo/doc-files \ - sun/awt/X11/doc-files \ - # - EXCLUDE_FILES += \ javax/swing/plaf/nimbus/InternalFrameTitlePanePainter.java \ javax/swing/plaf/nimbus/OptionPaneMessageAreaPainter.java \ diff --git a/make/modules/java.desktop/lib/AwtLibraries.gmk b/make/modules/java.desktop/lib/AwtLibraries.gmk index 5414c93c908..463e09e12dc 100644 --- a/make/modules/java.desktop/lib/AwtLibraries.gmk +++ b/make/modules/java.desktop/lib/AwtLibraries.gmk @@ -278,7 +278,6 @@ ifeq ($(call isTargetOs, windows macosx)+$(ENABLE_HEADLESS_ONLY), false+false) DISABLED_WARNINGS_gcc_X11TextRenderer_md.c := unused-but-set-variable, \ DISABLED_WARNINGS_gcc_XlibWrapper.c := type-limits pointer-to-int-cast, \ DISABLED_WARNINGS_gcc_XRBackendNative.c := maybe-uninitialized, \ - DISABLED_WARNINGS_gcc_XToolkit.c := unused-result, \ DISABLED_WARNINGS_gcc_XWindow.c := unused-function, \ DISABLED_WARNINGS_clang_awt_Taskbar.c := parentheses, \ DISABLED_WARNINGS_clang_gtk3_interface.c := unused-function parentheses, \ diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index a9511fba58b..dcb41defba3 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -87,7 +87,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBLCMS, \ libawt/java2d \ java.base:libjvm, \ HEADERS_FROM_SRC := $(LIBLCMS_HEADERS_FROM_SRC), \ - DISABLED_WARNINGS_gcc := format-nonliteral stringop-truncation type-limits \ + DISABLED_WARNINGS_gcc := format-nonliteral stringop-truncation \ unused-variable, \ DISABLED_WARNINGS_clang := format-nonliteral, \ JDK_LIBS := libawt java.base:libjava, \ diff --git a/make/modules/jdk.jdi/Java.gmk b/make/modules/jdk.jdi/Java.gmk index d31008c318f..c5e3e715c1a 100644 --- a/make/modules/jdk.jdi/Java.gmk +++ b/make/modules/jdk.jdi/Java.gmk @@ -31,7 +31,6 @@ EXCLUDES += \ com/sun/tools/example/debug/bdi \ com/sun/tools/example/debug/event \ com/sun/tools/example/debug/gui \ - com/sun/jdi/doc-files \ # EXCLUDE_FILES += jdi-overview.html diff --git a/make/modules/jdk.jdwp.agent/Lib.gmk b/make/modules/jdk.jdwp.agent/Lib.gmk index 8fe7787d76e..6ae053d4bec 100644 --- a/make/modules/jdk.jdwp.agent/Lib.gmk +++ b/make/modules/jdk.jdwp.agent/Lib.gmk @@ -68,6 +68,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJDWP, \ DISABLED_WARNINGS_clang_threadControl.c := unused-but-set-variable \ unused-variable, \ DISABLED_WARNINGS_clang_utf_util.c := unused-but-set-variable, \ + DISABLED_WARNINGS_microsoft_debugInit.c := 5287, \ LDFLAGS := $(ICONV_LDFLAGS), \ EXTRA_HEADER_DIRS := \ include \ diff --git a/make/scripts/fixpath.sh b/make/scripts/fixpath.sh index 3a886fee07c..6a524df4c68 100644 --- a/make/scripts/fixpath.sh +++ b/make/scripts/fixpath.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -157,11 +157,21 @@ function import_path() { if [[ $? -eq 0 && -e "$unixpath" ]]; then if [[ ! "$winpath" =~ ^"$ENVROOT"\\.*$ ]] ; then # If it is not in envroot, it's a generic windows path - if [[ ! $winpath =~ ^[-_.:\\a-zA-Z0-9]*$ ]] ; then + if [[ ! $winpath =~ ^[-_.:~+\\a-zA-Z0-9]*$ ]] ; then # Path has forbidden characters, rewrite as short name # This monster of a command uses the %~s support from cmd.exe to # reliably convert to short paths on all winenvs. shortpath="$($CMD /q /c for %I in \( "$winpath" \) do echo %~sI 2>/dev/null | tr -d \\n\\r)" + if [[ ! $shortpath =~ ^[-_.:~+\\a-zA-Z0-9]*$ ]] ; then + if [[ $QUIET != true ]]; then + echo fixpath: failure: Path "'"$path"'" could not be converted to short path >&2 + fi + if [[ $IGNOREFAILURES != true ]]; then + exit 1 + else + shortpath="" + fi + fi unixpath="$($PATHTOOL -u "$shortpath")" # unixpath is based on short name fi diff --git a/make/scripts/update_copyright_year.sh b/make/scripts/update_copyright_year.sh index bb61d48c91c..578ab4cbc99 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, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -41,10 +41,6 @@ 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} @@ -98,10 +94,16 @@ while getopts "c:fhy:" option; do done # VCS check +git_installed=false +which git > /dev/null && git_installed=true +if [ "$git_installed" != "true" ]; then + echo "Error: This script requires git. Please install it." + exit 1 +fi git_found=false -[ -d "${this_script_dir}/../../.git" ] && git_found=true +git status &> /dev/null && git_found=true if [ "$git_found" != "true" ]; then - echo "Error: Please execute script from within make/scripts." + echo "Error: Please execute script from within a JDK git repository." exit 1 else echo "Using Git version control system" diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index 92f40472c3c..347ca44d25f 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -119,7 +119,6 @@ $(JMH_UNPACKED_JARS_DONE): $(JMH_RUNTIME_JARS) $(foreach jar, $(JMH_RUNTIME_JARS), \ $$($(UNZIP) -oq $(jar) -d $(JMH_UNPACKED_DIR))) $(RM) -r $(JMH_UNPACKED_DIR)/META-INF - $(RM) $(JMH_UNPACKED_DIR)/*.xml $(TOUCH) $@ # Copy dependency files for inclusion in the benchmark JARs diff --git a/src/demo/share/jfc/CodePointIM/README.html b/src/demo/share/jfc/CodePointIM/README.html index 4860e0f89c2..5d2173e9fdf 100644 --- a/src/demo/share/jfc/CodePointIM/README.html +++ b/src/demo/share/jfc/CodePointIM/README.html @@ -2,7 +2,7 @@ README - CodePointIM - +

          Code Point Input Method

          diff --git a/src/demo/share/jfc/Metalworks/resources/HelpFiles/metal.html b/src/demo/share/jfc/Metalworks/resources/HelpFiles/metal.html index 6a42b1539ef..1347dda3fe2 100644 --- a/src/demo/share/jfc/Metalworks/resources/HelpFiles/metal.html +++ b/src/demo/share/jfc/Metalworks/resources/HelpFiles/metal.html @@ -1,6 +1,6 @@ - + Java L&F @@ -39,7 +39,7 @@

          The theme mechanism is designed to allow developers to create their own themes. For an example of this, see the themes which are included with Metalworks. Note, like all of the L&F packages, -the metal package is not yet frozen and the theme mechanism may change as +the metal package is not yet frozen and the theme mechanism may change as we get developer feedback on how to improve it.

          @@ -53,7 +53,7 @@

           JSlider slider = new JSlider();
          -slider.putClientProperty("JSlider.isFilled", +slider.putClientProperty("JSlider.isFilled", Boolean.TRUE);

          @@ -64,7 +64,7 @@

          ToolBars

          -

          Many popular applications support "roll-over" effects on buttons in toolbars. +

          Many popular applications support "roll-over" effects on buttons in toolbars. The Java L&F provides an easy way to do this. Here is a code snippit:

          @@ -72,7 +72,7 @@ 

          // add your buttons here
          -toolbar.putClientProperty("JToolBar.isRollover", +toolbar.putClientProperty("JToolBar.isRollover", Boolean.TRUE);

          @@ -98,7 +98,7 @@

          // This will provide lines separating root notes // it is the default setting myTree.putClientProperty("JTree.lineStyle", - "Horizontal"); + "Horizontal");

          BackBack diff --git a/src/demo/share/jfc/Metalworks/resources/HelpFiles/metalworks.html b/src/demo/share/jfc/Metalworks/resources/HelpFiles/metalworks.html index df9a440b273..f8b9d0cc6e3 100644 --- a/src/demo/share/jfc/Metalworks/resources/HelpFiles/metalworks.html +++ b/src/demo/share/jfc/Metalworks/resources/HelpFiles/metalworks.html @@ -1,6 +1,6 @@ - + Metalworks diff --git a/src/demo/share/jfc/SwingSet2/resources/ant.html b/src/demo/share/jfc/SwingSet2/resources/ant.html index eb9619b6825..346678d2de4 100644 --- a/src/demo/share/jfc/SwingSet2/resources/ant.html +++ b/src/demo/share/jfc/SwingSet2/resources/ant.html @@ -1,7 +1,7 @@ Untitled Document - + @@ -10,106 +10,106 @@


           

          -
          +
          -

          This was a creature, more troublesom to be drawn, then any - of the rest, for I could not, for a good while, think of a way to make it +

          This was a creature, more troublesom to be drawn, then any + of the rest, for I could not, for a good while, think of a way to make it suffer its body to ly quiet in a natural posture; but whil'st it was alive, - if its feet were fetter'd in Wax or Glew, it would so twist and wind its body, - that I could not any wayes get a good view of it; and if I killed it, its - body was so little, that I did often spoile the shape of it, before I could - throughly view it: for this is the nature of these minute Bodies, that as - soon, almost, as ever their life is destroy'd, their parts immediately shrivel, - and lose their beauty; and so is it also with small Plants, as I instanced + if its feet were fetter'd in Wax or Glew, it would so twist and wind its body, + that I could not any wayes get a good view of it; and if I killed it, its + body was so little, that I did often spoile the shape of it, before I could + throughly view it: for this is the nature of these minute Bodies, that as + soon, almost, as ever their life is destroy'd, their parts immediately shrivel, + and lose their beauty; and so is it also with small Plants, as I instanced before, in the description of Moss.

          -

          And thence also is the reason of the variations in the beards - of wild Oats, and in those of Muskgrass seed, that their bodies, being exceeding - small, those small variations which are made in the surfaces of all bodies, - almost upon every change of Air, especially if the body be porous, do here - become sensible, where the whole body is so small, that it is almost nothing - but surface; for as in vegetable substances, I see no great reason to think, - that the moisture of the Aire (that, sticking to a wreath'd beard, does make - it untwist) should evaporate, or exhale away, any faster then the moisture - of other bodies, but rather that the avolation from, or access of moisture - to, the surfaces of bodies being much the same, those bodies become most - sensible of it, which have the least proportion of body to their surface. +

          And thence also is the reason of the variations in the beards + of wild Oats, and in those of Muskgrass seed, that their bodies, being exceeding + small, those small variations which are made in the surfaces of all bodies, + almost upon every change of Air, especially if the body be porous, do here + become sensible, where the whole body is so small, that it is almost nothing + but surface; for as in vegetable substances, I see no great reason to think, + that the moisture of the Aire (that, sticking to a wreath'd beard, does make + it untwist) should evaporate, or exhale away, any faster then the moisture + of other bodies, but rather that the avolation from, or access of moisture + to, the surfaces of bodies being much the same, those bodies become most + sensible of it, which have the least proportion of body to their surface.

          -

          So is it also with Animal substances; the dead body of an - Ant, or such little creature, does almost instantly shrivel and dry, and - your object shall be quite another thing, before you can half delineate - it, which proceeds not from the extraordinary exhalation, but from the small - proportion of body and juices, to the usual drying of bodies in the Air, +

          So is it also with Animal substances; the dead body of an + Ant, or such little creature, does almost instantly shrivel and dry, and + your object shall be quite another thing, before you can half delineate + it, which proceeds not from the extraordinary exhalation, but from the small + proportion of body and juices, to the usual drying of bodies in the Air, especially if warm.

          -

          For which inconvenience, where I could not otherwise remove - it, I thought of this expedient. I took the creature, I had design'd to delineate, - and put it into a drop of very well rectified spirit of Wine, this I found - would presently dispatch, as it were, the Animal, and being taken out of - it, and lay'd on a paper,the spirit of Wine would immediately fly away, - and leave the Animal dry, in its natural posture, or at least, in a constitution, - that it might easily with a pin be plac'd, in what posture you desired to - draw it, and the limbs would so remain, without either moving, or shriveling. +

          For which inconvenience, where I could not otherwise remove + it, I thought of this expedient. I took the creature, I had design'd to delineate, + and put it into a drop of very well rectified spirit of Wine, this I found + would presently dispatch, as it were, the Animal, and being taken out of + it, and lay'd on a paper,the spirit of Wine would immediately fly away, + and leave the Animal dry, in its natural posture, or at least, in a constitution, + that it might easily with a pin be plac'd, in what posture you desired to + draw it, and the limbs would so remain, without either moving, or shriveling.

          -

          And thus I dealt with this Ant, which I have here delineated, - which was one of many, of a very large kind, that inhabited under the Roots - of a Tree, from whence they would sally out in great parties, and make most - grievous havock of the Flowers and Fruits, in the ambient Garden, and return back +

          And thus I dealt with this Ant, which I have here delineated, + which was one of many, of a very large kind, that inhabited under the Roots + of a Tree, from whence they would sally out in great parties, and make most + grievous havock of the Flowers and Fruits, in the ambient Garden, and return back again very expertly, by the same wayes and paths they went.

          -

          It was more then half the bigness of an Earwig, of a dark - brown, or reddish colour, with long legs, on the hinder of which it would - stand up, and raise its head as high as it could above the ground, that it - might stare the further about it, just after the same manner as I have also - observ'd a hunting Spider to do: and putting my finger towards them, they - have at first all run towards it, till almost at it; and then they would stand - round about it, at a certain distance, and smell, as it were, and consider - whether they should any of them venture any further, till one more bold then - the rest venturing to climb it, all the rest, if I would have suffered them, - would have immediately followed : much such other seemingly rational actions - I have observ'd in this little Vermine with much pleasure, which would be - too long to be here related; those that desire more of them may satisfie +

          It was more then half the bigness of an Earwig, of a dark + brown, or reddish colour, with long legs, on the hinder of which it would + stand up, and raise its head as high as it could above the ground, that it + might stare the further about it, just after the same manner as I have also + observ'd a hunting Spider to do: and putting my finger towards them, they + have at first all run towards it, till almost at it; and then they would stand + round about it, at a certain distance, and smell, as it were, and consider + whether they should any of them venture any further, till one more bold then + the rest venturing to climb it, all the rest, if I would have suffered them, + would have immediately followed : much such other seemingly rational actions + I have observ'd in this little Vermine with much pleasure, which would be + too long to be here related; those that desire more of them may satisfie their curiosity in Ligons History of the Barbadoes.

          -

          Having insnar'd several of these into a small Box, I made - choice of the tallest grown among them, and separating it from the rest, - I gave it a Gill of Brandy, or Spirit of Wine, which after a while e'en knock'd - him down dead drunk, so that he became moveless, though at first putting - in he struggled for a pretty while very much, till at last, certain bubbles - issuing out of his mouth, it ceased to move; this (because I had before found - them quickly to recover again, if they were taken out presently) I suffered - to lye above an hour in the Spirit; and after I had taken it out, and put - its body and legs into a natural posture, remained moveless about an hour; - but then, upon a sudden, as if it had been awaken out of a drunken sleep, - it suddenly reviv'd and ran away; being caught, and serv'd as before, he - for a while continued struggling and striving, till at last there issued - several bubbles out of its mouth, and then, tanquam animam expirasset, he - remained moveless for a good while ; but at length again recovering, it was - again redipt, and suffered to lye some hours in the Spirit; notwithstanding - which, after it had layen dry some three or four hours, it again recovered - life and motion: Which kind of Experiments, if prosecuted, which they highly - deserve, seem to me of no inconsiderable use towards the invention of the - Latent Scheme, (as the Noble Ve rulam calls it) or the hidden, unknown Texture +

          Having insnar'd several of these into a small Box, I made + choice of the tallest grown among them, and separating it from the rest, + I gave it a Gill of Brandy, or Spirit of Wine, which after a while e'en knock'd + him down dead drunk, so that he became moveless, though at first putting + in he struggled for a pretty while very much, till at last, certain bubbles + issuing out of his mouth, it ceased to move; this (because I had before found + them quickly to recover again, if they were taken out presently) I suffered + to lye above an hour in the Spirit; and after I had taken it out, and put + its body and legs into a natural posture, remained moveless about an hour; + but then, upon a sudden, as if it had been awaken out of a drunken sleep, + it suddenly reviv'd and ran away; being caught, and serv'd as before, he + for a while continued struggling and striving, till at last there issued + several bubbles out of its mouth, and then, tanquam animam expirasset, he + remained moveless for a good while ; but at length again recovering, it was + again redipt, and suffered to lye some hours in the Spirit; notwithstanding + which, after it had layen dry some three or four hours, it again recovered + life and motion: Which kind of Experiments, if prosecuted, which they highly + deserve, seem to me of no inconsiderable use towards the invention of the + Latent Scheme, (as the Noble Ve rulam calls it) or the hidden, unknown Texture of Bodies.

          -

          Of what Figure this Creature appear'd through the Microscope, - the 32. Scheme (though not so carefully graven as it ought) will represent - to the eye, namely, That it had a large head A A, at the upper end of which - were two protuberant eyes, pearl'd like those of a Fly, but smaller B B; - of the Nose, or foremost part, issued two horns C C, of a shape sufficiently - differing from those of a blew Fly, though indeed they seem to be both the - same kind of Organ, and to serve for a kind of smelling; beyond these were - two indented jaws D D, which he open'd sideways, and was able to gape them - asunder very wide; and the ends of them being armed with teeth, which meeting - went between each other, it was able to grasp and hold a heavy body, three - or four times the bulk and weight of its own body: It had only six legs, - shap'd like those of a Fly, which, as I shewed before, is an Argument that - it is a winged Insect, and though I could not perceive any sign of them in - the middle part of its body (which seem'd to consist of three joints or pieces - E F G, out of which sprung two legs, yet 'tis known that there are of them +

          Of what Figure this Creature appear'd through the Microscope, + the 32. Scheme (though not so carefully graven as it ought) will represent + to the eye, namely, That it had a large head A A, at the upper end of which + were two protuberant eyes, pearl'd like those of a Fly, but smaller B B; + of the Nose, or foremost part, issued two horns C C, of a shape sufficiently + differing from those of a blew Fly, though indeed they seem to be both the + same kind of Organ, and to serve for a kind of smelling; beyond these were + two indented jaws D D, which he open'd sideways, and was able to gape them + asunder very wide; and the ends of them being armed with teeth, which meeting + went between each other, it was able to grasp and hold a heavy body, three + or four times the bulk and weight of its own body: It had only six legs, + shap'd like those of a Fly, which, as I shewed before, is an Argument that + it is a winged Insect, and though I could not perceive any sign of them in + the middle part of its body (which seem'd to consist of three joints or pieces + E F G, out of which sprung two legs, yet 'tis known that there are of them that have long wings, and fly up and down in the air.

          -

          The third and last part of its body I I I was bigger and - larger then the other two, unto which it was joyn'd by a very small middle, - and had a kind of loose shell, or another distinct part of its body H, which - seem'd to be interpos'd, and to keep the thorax and belly from touching. - The whole body was cas'd over with a very strong armour, and the belly I - I I was covered likewise with multitudes of small white shining brisles; - the legs, horns, head, and middle parts of its body were bestruck with hairs +

          The third and last part of its body I I I was bigger and + larger then the other two, unto which it was joyn'd by a very small middle, + and had a kind of loose shell, or another distinct part of its body H, which + seem'd to be interpos'd, and to keep the thorax and belly from touching. + The whole body was cas'd over with a very strong armour, and the belly I + I I was covered likewise with multitudes of small white shining brisles; + the legs, horns, head, and middle parts of its body were bestruck with hairs also, but smaller and darker.

           

          diff --git a/src/demo/share/jfc/SwingSet2/resources/bug.html b/src/demo/share/jfc/SwingSet2/resources/bug.html index bf3b159112f..d61cdb9ad25 100644 --- a/src/demo/share/jfc/SwingSet2/resources/bug.html +++ b/src/demo/share/jfc/SwingSet2/resources/bug.html @@ -1,7 +1,7 @@ Untitled Document - + @@ -10,113 +10,113 @@

          Observ. LIV. Of a Louse.

           

          -
          -
          -

          This is a Creature so officious, that 'twill be known to - every one at one time or other, so busie, and so impudent, that it will - be intruding it self in every ones company, and so proud and aspiring withall, - that it fears not to trample on the best, and affects nothing so much as - a Crown; feeds and lives very high, and that makes it so saucy, as to pull - any one by the ears that comes in its way, and will never be quiet till - it has drawn blood: it is troubled at nothing so much as at a man that scratches - his head, as knowing that man is plotting and contriving some mischief against - it, and that makes it oftentime sculk into some meaner and lower place, and - run behind a mans back, though it go very much against the hair; which ill - conditions of it having made it better known then trusted, would exempt me - from making any further description of it, did not my faithful Mercury, my +

          +
          +

          This is a Creature so officious, that 'twill be known to + every one at one time or other, so busie, and so impudent, that it will + be intruding it self in every ones company, and so proud and aspiring withall, + that it fears not to trample on the best, and affects nothing so much as + a Crown; feeds and lives very high, and that makes it so saucy, as to pull + any one by the ears that comes in its way, and will never be quiet till + it has drawn blood: it is troubled at nothing so much as at a man that scratches + his head, as knowing that man is plotting and contriving some mischief against + it, and that makes it oftentime sculk into some meaner and lower place, and + run behind a mans back, though it go very much against the hair; which ill + conditions of it having made it better known then trusted, would exempt me + from making any further description of it, did not my faithful Mercury, my Microscope, bring me other information of it.

          -

          For this has discovered to me, by means of a very bright light - cast on it, that it is a Creature of a very odd shape ; it has a head shap'd - like that exprest in 35. Scheme marked with A, which seems almost Conical, - but is a little flatted on the upper and under sides, at the biggest part - of which, on either side behind the head (as it were, being the place where - other Creatures ears stand) are placed its two black shining goggle eyes - B B, looking backwards, and fenced round with several small cilia or hairs - that incompass it, so that it seems this Creature has no very good foresight: - It does not seem to have any eyelids, and therefore perhaps its eyes were - so placed, that it might the better cleanse them with its forelegs; and perhaps - this may be the reason, why they so much avoid and run from the light behind - them, for being made to live in the shady and dark recesses of the hair, - and thence probably their eye having a great aperture, the open and clear - light, especially that of the Sun, must needs very much offend them; to secure - these eyes from receiving any injury from the hairs through which it passes, - it has two horns that grow before it, in the place where one would have thought - the eyes should be; each of these C C have four joynts, which are fringed, - as 'twere, with small brisles, from which to the tip of its snout D, the - head seems very round and tapering, ending in a very sharp nose D, which - seems to have a small hole, and to be the passage through which he sucks +

          For this has discovered to me, by means of a very bright light + cast on it, that it is a Creature of a very odd shape ; it has a head shap'd + like that exprest in 35. Scheme marked with A, which seems almost Conical, + but is a little flatted on the upper and under sides, at the biggest part + of which, on either side behind the head (as it were, being the place where + other Creatures ears stand) are placed its two black shining goggle eyes + B B, looking backwards, and fenced round with several small cilia or hairs + that incompass it, so that it seems this Creature has no very good foresight: + It does not seem to have any eyelids, and therefore perhaps its eyes were + so placed, that it might the better cleanse them with its forelegs; and perhaps + this may be the reason, why they so much avoid and run from the light behind + them, for being made to live in the shady and dark recesses of the hair, + and thence probably their eye having a great aperture, the open and clear + light, especially that of the Sun, must needs very much offend them; to secure + these eyes from receiving any injury from the hairs through which it passes, + it has two horns that grow before it, in the place where one would have thought + the eyes should be; each of these C C have four joynts, which are fringed, + as 'twere, with small brisles, from which to the tip of its snout D, the + head seems very round and tapering, ending in a very sharp nose D, which + seems to have a small hole, and to be the passage through which he sucks the blood.

           

          -

          Now whereas it if be plac'd on its back, with its belly - upwards, as it is in the 35. Scheme, it seems in several Positions to have - a resemblance of chaps, or jaws, as is represented in the Figure by E E, - yet in other postures those dark strokes disappear; and having kept several - of them in a box for two or three dayes, so that for all that time they had - nothing to feed on, I found, upon letting onecreep on my hand, that it immediately - fell to sucking, and did neither seem to thrust its nose very deep into the - skin, nor to open any kind of mouth, but I could plainly perceive a small - current of blood, which came directly from its snout, and past into its belly; - and about A there seem'd a contrivance, somewhat resembling a Pump, pair - of Bellows, or Heart, for by a very swift systole and diastole the blood +

          Now whereas it if be plac'd on its back, with its belly + upwards, as it is in the 35. Scheme, it seems in several Positions to have + a resemblance of chaps, or jaws, as is represented in the Figure by E E, + yet in other postures those dark strokes disappear; and having kept several + of them in a box for two or three dayes, so that for all that time they had + nothing to feed on, I found, upon letting onecreep on my hand, that it immediately + fell to sucking, and did neither seem to thrust its nose very deep into the + skin, nor to open any kind of mouth, but I could plainly perceive a small + current of blood, which came directly from its snout, and past into its belly; + and about A there seem'd a contrivance, somewhat resembling a Pump, pair + of Bellows, or Heart, for by a very swift systole and diastole the blood seem'd drawn from the nose, and forced into the body.

          -

          It did not seem at all, though I viewed it a good while as - it was sucking, to thrust more of its nose into the skin then the very snout - D, nor did it cause the least discernable pain, and yet the blood seem'd - to run through its head very quick and freely, so that it seems there is - no part of the skin but the blood is dispers'd into, nay, even into the - cuticula; for had it thrust its whole nose in from D to C C, it would not - have amounted to the supposed thickness of that tegument, the length of +

          It did not seem at all, though I viewed it a good while as + it was sucking, to thrust more of its nose into the skin then the very snout + D, nor did it cause the least discernable pain, and yet the blood seem'd + to run through its head very quick and freely, so that it seems there is + no part of the skin but the blood is dispers'd into, nay, even into the + cuticula; for had it thrust its whole nose in from D to C C, it would not + have amounted to the supposed thickness of that tegument, the length of the nose being not more then a three hundredth part of an inch.

          -

          It has six legs, covered with a very transparent shell, - and joynted exactly like a Crab's, or Lobster's; each leg is divided into - six parts by these joynts, and those have here and there several small hairs; - and at the end of each leg it has two claws, very properly adapted for its - peculiar use, being thereby inabled to walk very securely both on the skin - and hair; and indeed this contrivance of the feet is very curious, and could - not be made more commodiously and compendiously, for performing both these - requisite motions, of walking and climbing up the hair of a mans head, then - it is : for, by having the lesser claw (a) set so much short of the bigger - (b) when it walks on the skin the shorter touches not, and then the feet - are the same with those of a Mite, and several other small Insects, but by - means of the small joynts of the longer claw it can bend it round, and so - with both claws take hold of a hair, in the manner represented in the Figure, +

          It has six legs, covered with a very transparent shell, + and joynted exactly like a Crab's, or Lobster's; each leg is divided into + six parts by these joynts, and those have here and there several small hairs; + and at the end of each leg it has two claws, very properly adapted for its + peculiar use, being thereby inabled to walk very securely both on the skin + and hair; and indeed this contrivance of the feet is very curious, and could + not be made more commodiously and compendiously, for performing both these + requisite motions, of walking and climbing up the hair of a mans head, then + it is : for, by having the lesser claw (a) set so much short of the bigger + (b) when it walks on the skin the shorter touches not, and then the feet + are the same with those of a Mite, and several other small Insects, but by + means of the small joynts of the longer claw it can bend it round, and so + with both claws take hold of a hair, in the manner represented in the Figure, the long transparent Cylinder F F F, being a Man's hair held by it.

          -

          The Thorax seem'd cas'd with another kind of substance then - the belly, namely, with a thin transparent horny substance, which upon the fasting - of the Creature did not grow flaccid; through this I could plainly see the - blood, suck'd from my hand, to be variously distributed, and mov'd to and - fro; and about G there seem'd a pretty big white substance, which seem'd - to be moved within its thorax; besides, there appear'd very many small milk-white - vessels, which crost over the breast between the legs, out of which, on - either side, are many small branchings, these seem'd to be the veins and - arteries, for that which is analogus to blood in all Insects is milk-white. +

          The Thorax seem'd cas'd with another kind of substance then + the belly, namely, with a thin transparent horny substance, which upon the fasting + of the Creature did not grow flaccid; through this I could plainly see the + blood, suck'd from my hand, to be variously distributed, and mov'd to and + fro; and about G there seem'd a pretty big white substance, which seem'd + to be moved within its thorax; besides, there appear'd very many small milk-white + vessels, which crost over the breast between the legs, out of which, on + either side, are many small branchings, these seem'd to be the veins and + arteries, for that which is analogus to blood in all Insects is milk-white.

          -

          The belly is covered with a transparent substance likewise, - but more resembling a skin then a shell, for 'tis grain'd all over the belly - just like the skin in the palms of a man's hand, and when the belly is empty, - grows very flaccid and wrinkled ; at the upper end of this is placed the - stomach H H, and perhaps also the white spot I I may be the liver, or pancreas, - which by the peristaltick motion of the guts, is a little mov'd to and fro, - not with a systole and diastole, but rather with a thronging or justling +

          The belly is covered with a transparent substance likewise, + but more resembling a skin then a shell, for 'tis grain'd all over the belly + just like the skin in the palms of a man's hand, and when the belly is empty, + grows very flaccid and wrinkled ; at the upper end of this is placed the + stomach H H, and perhaps also the white spot I I may be the liver, or pancreas, + which by the peristaltick motion of the guts, is a little mov'd to and fro, + not with a systole and diastole, but rather with a thronging or justling motion.

          -

          Viewing one of these Creatures, after it had fasted two - dayes, all the hinder part was lank and flaccid, and the white spot I I - hardly mov'd, most of the white branchings disappear'd, and most also of - the redness or sucked blood in the guts, the peristaltick motion of which - was scarce discernable; but upon the suffering it to suck, it presently - fill'd the skin of the belly, and of the six scolop'd embosments on either side, - as full as it could be stuft ; the stomach and guts were as full as they - could hold; the peristaltick motion of the gut grew quick, and the justling - motion of I I accordingly ; multitudes of milk-white vessels seem'd quickly - filled, and turgid, which were perhaps the veins and arteries, and the Creature - was so greedy, that though it could not contain more, yet it continued sucking - as fast as ever, and as fast emptying it self behind : the digestion of this - Creature must needs be very quick, for though I perceiv'd the blood thicker - and blacker when suck'd, yet, when in the guts, it was of a very lovely - ruby colour, and that part of it, which was digested into the veins, seemed - white; whence it appears, that a further digestion of blood may make it - milk, at least of a resembling colour : What is else observable in the figure +

          Viewing one of these Creatures, after it had fasted two + dayes, all the hinder part was lank and flaccid, and the white spot I I + hardly mov'd, most of the white branchings disappear'd, and most also of + the redness or sucked blood in the guts, the peristaltick motion of which + was scarce discernable; but upon the suffering it to suck, it presently + fill'd the skin of the belly, and of the six scolop'd embosments on either side, + as full as it could be stuft ; the stomach and guts were as full as they + could hold; the peristaltick motion of the gut grew quick, and the justling + motion of I I accordingly ; multitudes of milk-white vessels seem'd quickly + filled, and turgid, which were perhaps the veins and arteries, and the Creature + was so greedy, that though it could not contain more, yet it continued sucking + as fast as ever, and as fast emptying it self behind : the digestion of this + Creature must needs be very quick, for though I perceiv'd the blood thicker + and blacker when suck'd, yet, when in the guts, it was of a very lovely + ruby colour, and that part of it, which was digested into the veins, seemed + white; whence it appears, that a further digestion of blood may make it + milk, at least of a resembling colour : What is else observable in the figure of this Creature, maybe seen by the 35. Scheme.

           

          diff --git a/src/demo/share/jfc/SwingSet2/resources/index.html b/src/demo/share/jfc/SwingSet2/resources/index.html index 0aa73c410ef..ba7d26068a1 100644 --- a/src/demo/share/jfc/SwingSet2/resources/index.html +++ b/src/demo/share/jfc/SwingSet2/resources/index.html @@ -1,7 +1,7 @@ Untitled Document - + @@ -20,21 +20,21 @@

          Of a Louse


          -

          Images and text used by permission of Octavo +

          Images and text used by permission of Octavo Corporation (www.octavo.com),
          -
          (c) 1999 Octavo Corporation. All + (c) 1999 Octavo Corporation. All rights reserved.


          - Octavo Corporation is a publisher of rare - books and manuscripts with digital tools and formats through partnerships - with libraries, museums, and individuals. Using high-resolution digital imaging - technology, Octavo releases digital rare books on CD-ROM as Adobe PDF files - which can be viewed on and printed from almost any computing platform. You - can view each page and the binding on your computer screen, zoom in to view - detail up to 800% in some cases, and search, copy and paste the "live" text - placed invisibly behind the page images which is available for selected Editions. - Also included in each edition is the work's collation and provenance, as well + Octavo Corporation is a publisher of rare + books and manuscripts with digital tools and formats through partnerships + with libraries, museums, and individuals. Using high-resolution digital imaging + technology, Octavo releases digital rare books on CD-ROM as Adobe PDF files + which can be viewed on and printed from almost any computing platform. You + can view each page and the binding on your computer screen, zoom in to view + detail up to 800% in some cases, and search, copy and paste the "live" text + placed invisibly behind the page images which is available for selected Editions. + Also included in each edition is the work's collation and provenance, as well as commentary by a noted expert in its field.

           

          diff --git a/src/demo/share/jfc/SwingSet2/resources/king.html b/src/demo/share/jfc/SwingSet2/resources/king.html index a6f458af419..b14f2d84b51 100644 --- a/src/demo/share/jfc/SwingSet2/resources/king.html +++ b/src/demo/share/jfc/SwingSet2/resources/king.html @@ -1,34 +1,34 @@ Untitled Document - + -

          +

           

          -
          Do here most humbly lay this small Present at Your - Majesties Royal feet. And though it comes accompany'd with two disadvantages, - the meanness of the Author, and of the Subject; yet in both I am incouraged +
          Do here most humbly lay this small Present at Your + Majesties Royal feet. And though it comes accompany'd with two disadvantages, + the meanness of the Author, and of the Subject; yet in both I am incouraged by the greatness of your Mercy and your Knowledge. -

          By the one I am taught , that you can forgive the most presumptuous - Offendors: And by the other, that you will not esteem the least work of Nature, +

          By the one I am taught , that you can forgive the most presumptuous + Offendors: And by the other, that you will not esteem the least work of Nature, or Art, unworthy your Observation.

          -

          Amidst the many felicities that have accompani'd your Majesties - happy Restauration and Government, it is none of the least considerable, that +

          Amidst the many felicities that have accompani'd your Majesties + happy Restauration and Government, it is none of the least considerable, that Philosophy and Experimental Learning have prosper'd under your Royal Patronage.

          -

          And as the calm prosperity of your Reign has given us the - leisure to follow these Studies of quiet and retirement, so it is just, that - the Fruits of them should, by way of acknowledgement, be return'd to your - Majesty. There are, Sir, several other of your Subjects, of your Royal Society, - now busie about Nobler matters: The Improvement of Manufactures and Agriculture, - the Increase of Commerce, the Advantage of Navigation: In all which they are +

          And as the calm prosperity of your Reign has given us the + leisure to follow these Studies of quiet and retirement, so it is just, that + the Fruits of them should, by way of acknowledgement, be return'd to your + Majesty. There are, Sir, several other of your Subjects, of your Royal Society, + now busie about Nobler matters: The Improvement of Manufactures and Agriculture, + the Increase of Commerce, the Advantage of Navigation: In all which they are assisted by your Majesties Incouragement and Example.

          -

          Amidst all those greater Designs, I here presume to bring - in that which is more proportionable to the smalness of my Abilities, and - to offer some of the least of all visible things, to that Mighty King, that - has establisht an Empire over the best of all Invisible things of this World, +

          Amidst all those greater Designs, I here presume to bring + in that which is more proportionable to the smalness of my Abilities, and + to offer some of the least of all visible things, to that Mighty King, that + has establisht an Empire over the best of all Invisible things of this World, the Minds o f Men.

           

          diff --git a/src/demo/share/jfc/SwingSet2/resources/preface.html b/src/demo/share/jfc/SwingSet2/resources/preface.html index 8138b288a18..b7c10d6eec1 100644 --- a/src/demo/share/jfc/SwingSet2/resources/preface.html +++ b/src/demo/share/jfc/SwingSet2/resources/preface.html @@ -1,7 +1,7 @@ Untitled Document - + @@ -9,101 +9,101 @@

           

          THE PREFACE

          -
          +

           

           

          -
          +
          -

          It is the great prerogative of Mankind above - other Creatures, that we are not only able to behold the works of Nature, - or barely to sustein our lives by them, but we have also the power of considering, +

          It is the great prerogative of Mankind above + other Creatures, that we are not only able to behold the works of Nature, + or barely to sustein our lives by them, but we have also the power of considering, comparing, altering, assisting, and improving them to various uses.

          -

          And as this is the peculiar priviledge of humane Nature - in general, so is it capable of being so far advanced by the helps of Art, - and Experience, as to make some Men excel others in their Observations, +

          And as this is the peculiar priviledge of humane Nature + in general, so is it capable of being so far advanced by the helps of Art, + and Experience, as to make some Men excel others in their Observations, and Deductions, almost as much as they do Beasts.

          -

          By the addition of such artificial Instruments and methods, - there may be, in some manner, a reparation made for the mischiefs, and imperfection, - mankind has drawn upon itself, by negligence, and intemperance, and a wilful - and superstitious deserting the Prescripts and Rules of Nature, whereby - every man, both from a deriv'd corruption, innate and born with him, and - from his breeding and converse with men, is very subject to slip into all +

          By the addition of such artificial Instruments and methods, + there may be, in some manner, a reparation made for the mischiefs, and imperfection, + mankind has drawn upon itself, by negligence, and intemperance, and a wilful + and superstitious deserting the Prescripts and Rules of Nature, whereby + every man, both from a deriv'd corruption, innate and born with him, and + from his breeding and converse with men, is very subject to slip into all sorts of errors.

          -

          The only way which now remains for us to recover some degree - of those former perfections, seems to be, by rectifying the operations of - the Sense, the Memory, and Reason, since upon the evidence, the strength, - the integrity, and the right correspondence of all these, all the light, - by which our actions are to be guided, is to be renewed, and all our command +

          The only way which now remains for us to recover some degree + of those former perfections, seems to be, by rectifying the operations of + the Sense, the Memory, and Reason, since upon the evidence, the strength, + the integrity, and the right correspondence of all these, all the light, + by which our actions are to be guided, is to be renewed, and all our command over things is to be establisht.

          -

          It is therefore most worthy of our consideration, to recollect - their several defects, that so we may the better understand how to supply - them, and by what assistances we may inlarge their power, and secure them +

          It is therefore most worthy of our consideration, to recollect + their several defects, that so we may the better understand how to supply + them, and by what assistances we may inlarge their power, and secure them in performing their particular duties.

          -

          As for the actions of our Senses, we cannot but observe - them to be in many particulars much outdone by those of other Creatures, - and when at best, to be far short of the perfection they seem capable of - : And these infirmities of the Senses arise from a double cause, either - from the disproportion of the Object to the Organ, whereby an infinite number - of things can never enter into them, or else from error in the Perception, - that many things, which come within their reach, are not received in a right +

          As for the actions of our Senses, we cannot but observe + them to be in many particulars much outdone by those of other Creatures, + and when at best, to be far short of the perfection they seem capable of + : And these infirmities of the Senses arise from a double cause, either + from the disproportion of the Object to the Organ, whereby an infinite number + of things can never enter into them, or else from error in the Perception, + that many things, which come within their reach, are not received in a right manner.

          -

          The like frailties are to be found in the Memory; we often - let many things slip away from us, which deserve to be retain'd; and of - those which we treasure up, a great part is either frivolous or false ; - and if good, and substantial, either in tract of time obliterated, or at - best so overwhelmed and buried under more frothy notions, that when there +

          The like frailties are to be found in the Memory; we often + let many things slip away from us, which deserve to be retain'd; and of + those which we treasure up, a great part is either frivolous or false ; + and if good, and substantial, either in tract of time obliterated, or at + best so overwhelmed and buried under more frothy notions, that when there is need of them, they are in vain sought for.

          -

          The two main foundations being so deceivable, it is no wonder, - that all the succeeding works which we build upon them, of arguing, concluding, - defining, judging, and all the other degrees of Reason, are lyable to the - same imperfection, being, at best, either vain, or uncertain: So that the - errors of the understanding are answerable to the two other, being defective - both in the quantity and goodness of its knowledge; for the limits, to which - our thoughts are confind, are small in respect of the vast extent of Nature - it self; some parts of it are too large to be comprehended, and some too +

          The two main foundations being so deceivable, it is no wonder, + that all the succeeding works which we build upon them, of arguing, concluding, + defining, judging, and all the other degrees of Reason, are lyable to the + same imperfection, being, at best, either vain, or uncertain: So that the + errors of the understanding are answerable to the two other, being defective + both in the quantity and goodness of its knowledge; for the limits, to which + our thoughts are confind, are small in respect of the vast extent of Nature + it self; some parts of it are too large to be comprehended, and some too little to be perceived.

          -

          And from thence it must follow, that not having a full sensation - of the Object, we must be very lame and imperfect in our conceptions about - it, and in all the propositions which we build upon it; hence we often take - the shadow of things for the substance, small appearances for good similitudes, - similitudes for definitions; and even many of those, which we think to be - the most solid definitions, are rather expressions of our own misguided +

          And from thence it must follow, that not having a full sensation + of the Object, we must be very lame and imperfect in our conceptions about + it, and in all the propositions which we build upon it; hence we often take + the shadow of things for the substance, small appearances for good similitudes, + similitudes for definitions; and even many of those, which we think to be + the most solid definitions, are rather expressions of our own misguided apprehensions then of the true nature of the things themselves.

          -

          The effects of these imperfections are manifested in different - ways, according to the temper and disposition of the several minds of men, - some they incline to gross ignorance and stupidity, and others to a presumptuous - imposing on other mens Opinions, and a confident dogmatizing on matters, +

          The effects of these imperfections are manifested in different + ways, according to the temper and disposition of the several minds of men, + some they incline to gross ignorance and stupidity, and others to a presumptuous + imposing on other mens Opinions, and a confident dogmatizing on matters, whereof there is no assurance to be given.

          -

          Thus all the uncertainty, and mistakes of humane actions, - proceed either from the narrowness and wandring of our Senses, from the - slipperiness or delusion of our Memory, from the confinement or rashness - of our Understanding, so that 'tis no wonder, that our power over natural - causes and effects is so slowly improvd, seeing we are not only to contend - with the obscurity and difficulty of the things whereon we work and think, +

          Thus all the uncertainty, and mistakes of humane actions, + proceed either from the narrowness and wandring of our Senses, from the + slipperiness or delusion of our Memory, from the confinement or rashness + of our Understanding, so that 'tis no wonder, that our power over natural + causes and effects is so slowly improvd, seeing we are not only to contend + with the obscurity and difficulty of the things whereon we work and think, but even the forces of our own minds conspire to betray us.

          -

          These being the dangers in the process of humane Reason, - the remedies of them all can only proceed from the real, the mechanical, - the experimental Philosophy, which has this advantage over the Philosophy - of discourse and disputation, that whereas that chiefly aims at the subtilty - of its Deductions and Conclusions, without much regard to the first groundwork, - which ought to be well laid on the Sense and Memory ; so this intends the - right ordering of them all, and the making them serviceable to each other. +

          These being the dangers in the process of humane Reason, + the remedies of them all can only proceed from the real, the mechanical, + the experimental Philosophy, which has this advantage over the Philosophy + of discourse and disputation, that whereas that chiefly aims at the subtilty + of its Deductions and Conclusions, without much regard to the first groundwork, + which ought to be well laid on the Sense and Memory ; so this intends the + right ordering of them all, and the making them serviceable to each other.

          -

          The first thing to be undertaken in this weighty work, is - a watchfulness over the failings and an inlargement of the dominion, of - the Senses. To which end it is requisite, first, That there should be a - scrupulous choice, and a strict examination, of the reality, constancy, - and certainty of the Particulars that we admit: This is the first rise whereon - truth is to begin, and here the most severe, and most impartial diligence, - must be imployed ; the storing up of all, without any regard to evidence +

          The first thing to be undertaken in this weighty work, is + a watchfulness over the failings and an inlargement of the dominion, of + the Senses. To which end it is requisite, first, That there should be a + scrupulous choice, and a strict examination, of the reality, constancy, + and certainty of the Particulars that we admit: This is the first rise whereon + truth is to begin, and here the most severe, and most impartial diligence, + must be imployed ; the storing up of all, without any regard to evidence or use, will only tend to darkness and confusion.

          -

          We must not therefore esteem the riches of our Philosophical - treasure by the number only, but chiefly by the weight; the most vulgar - Instances are not to be neglected, but above all, the most instructive are - to be entertain'd: the footsteps of Nature are to be trac'd, not only in - her ordinary course,but when she seems to be put to her shifts, to make - many doublings and turnings, and to use some kind of art in indeavouring +

          We must not therefore esteem the riches of our Philosophical + treasure by the number only, but chiefly by the weight; the most vulgar + Instances are not to be neglected, but above all, the most instructive are + to be entertain'd: the footsteps of Nature are to be trac'd, not only in + her ordinary course,but when she seems to be put to her shifts, to make + many doublings and turnings, and to use some kind of art in indeavouring to avoid our discovery.

           

          diff --git a/src/demo/share/jfc/SwingSet2/resources/seaweed.html b/src/demo/share/jfc/SwingSet2/resources/seaweed.html index fd2a9433630..f386751dd7c 100644 --- a/src/demo/share/jfc/SwingSet2/resources/seaweed.html +++ b/src/demo/share/jfc/SwingSet2/resources/seaweed.html @@ -1,7 +1,7 @@ Untitled Document - + @@ -11,47 +11,47 @@


           

          -

          For curiosity and beauty, I have not among all the Plants - or Vegetables I have yet observ'd, seen any one comparable to this Sea-weed - I have here describ'd, of which I am able to say very little more then what - is represented by the second Figure of the ninth Scheme: Namely, that it is - a Plant which grows upon the Rocks under the water, and increases and spreads - it self into a great tuft, which is not onely handsomely branch'd into several - leaves, but the whole surface of the Plant is cover'd over with a most curious - kind of carv'd work, which consists of a texture much resembling a Honeycomb; - for the whole surface on both sides is cover'd over with a multitude of very - small holes, being no bigger then so many holes made with the point of a small - Pinn, and rang'd in the neatest and most delicate order imaginable, they being - plac'd in the manner of a Quincunx, or very much like the rows of the eyes - of a Fly, the rows or orders being very regular, which way soever they are - observ'd: what the texture was, as it appear'd through a pretty bigg Magnifying - Microscope, I have here adjoin'd in the first Figure of the 14. Scheme. which - round Area A B C D represents a part of the surface about one eighth part - of an Inch in Diameter: Those little holes, which to the eye look'd round, - like so many little spots, here appear'd very regularly shap'd holes, representing - almost the shape of the sole of a round toed shoe, the hinder part of which, - is, as it were, trod on or cover'd by the toe of that next below it; these - holes seem'd wall'd about with a very thin and transparent substance, looking - of a pale straw-colour; from the edge of which, against the middle of each - hole, were sprouted out four small transparent straw-colour'd Thorns, which - seem'd to protect and cover those cavities, from either side two; neer the - root of this Plant, were sprouted out several small branches of a kind of +

          For curiosity and beauty, I have not among all the Plants + or Vegetables I have yet observ'd, seen any one comparable to this Sea-weed + I have here describ'd, of which I am able to say very little more then what + is represented by the second Figure of the ninth Scheme: Namely, that it is + a Plant which grows upon the Rocks under the water, and increases and spreads + it self into a great tuft, which is not onely handsomely branch'd into several + leaves, but the whole surface of the Plant is cover'd over with a most curious + kind of carv'd work, which consists of a texture much resembling a Honeycomb; + for the whole surface on both sides is cover'd over with a multitude of very + small holes, being no bigger then so many holes made with the point of a small + Pinn, and rang'd in the neatest and most delicate order imaginable, they being + plac'd in the manner of a Quincunx, or very much like the rows of the eyes + of a Fly, the rows or orders being very regular, which way soever they are + observ'd: what the texture was, as it appear'd through a pretty bigg Magnifying + Microscope, I have here adjoin'd in the first Figure of the 14. Scheme. which + round Area A B C D represents a part of the surface about one eighth part + of an Inch in Diameter: Those little holes, which to the eye look'd round, + like so many little spots, here appear'd very regularly shap'd holes, representing + almost the shape of the sole of a round toed shoe, the hinder part of which, + is, as it were, trod on or cover'd by the toe of that next below it; these + holes seem'd wall'd about with a very thin and transparent substance, looking + of a pale straw-colour; from the edge of which, against the middle of each + hole, were sprouted out four small transparent straw-colour'd Thorns, which + seem'd to protect and cover those cavities, from either side two; neer the + root of this Plant, were sprouted out several small branches of a kind of bastard Coralline, curiously branch'd, though small.

          -

          And to confirm this, having lately the opportunity of viewing - the large Plant (if I may so call it) of a Sponge petrify'd, of which I made - mention in the last Observation, I found, that each of the Branches or Figures - of it, did, by the range of its pores, exhibit just such a texture, the rows - of pores crossing one another, much after the manner as the rows of eyes do - which are describ'd in the 26. Scheme : Coralline also, and several sorts of - white Coral, I have with a Microscope observ'd very curiously shap'd. And - I doubt not, but that he that shall observe these several kinds of Plants that - grow upon Rocks, which the Sea sometimes overflows, and those heaps of others - which are vomited out of it upon the shore, may find multitudes of little - Plants, and other bodies, which like this will afford very beautifull objects - for the Microscope ; and this Specimen here is adjoin'd onely to excite their - curiosities who have opportunity of observing to examine and collect what - they find worthy their notice; for the Sea, among terrestrial bodies, is also - a prolifick mother, and affords as many Instances of spontaneous generations +

          And to confirm this, having lately the opportunity of viewing + the large Plant (if I may so call it) of a Sponge petrify'd, of which I made + mention in the last Observation, I found, that each of the Branches or Figures + of it, did, by the range of its pores, exhibit just such a texture, the rows + of pores crossing one another, much after the manner as the rows of eyes do + which are describ'd in the 26. Scheme : Coralline also, and several sorts of + white Coral, I have with a Microscope observ'd very curiously shap'd. And + I doubt not, but that he that shall observe these several kinds of Plants that + grow upon Rocks, which the Sea sometimes overflows, and those heaps of others + which are vomited out of it upon the shore, may find multitudes of little + Plants, and other bodies, which like this will afford very beautifull objects + for the Microscope ; and this Specimen here is adjoin'd onely to excite their + curiosities who have opportunity of observing to examine and collect what + they find worthy their notice; for the Sea, among terrestrial bodies, is also + a prolifick mother, and affords as many Instances of spontaneous generations as either the Air or Earth.

           

          diff --git a/src/demo/share/jfc/SwingSet2/resources/title.html b/src/demo/share/jfc/SwingSet2/resources/title.html index ea13f5cf005..0e99558ccd7 100644 --- a/src/demo/share/jfc/SwingSet2/resources/title.html +++ b/src/demo/share/jfc/SwingSet2/resources/title.html @@ -1,7 +1,7 @@ Untitled Document - + @@ -14,18 +14,18 @@


          MADE BY

          MAGNIFYING GLASSES.

          WITH

          -

          OBSERVATIONS and INQUIRIES +

          OBSERVATIONS and INQUIRIES thereupon.

          -

          By R. HOOKE +

          By R. HOOKE , Fellow of the ROYAL SOCIETY .

          -
          -
          -
          -

          LONDON, Printed by Jo. - Martyn, and Ja. Allestry, - Printers to the ROYAL SOCIETY , and are to - be sold at their Shop at the Bell in S. Paul's Church-yard. M +

          +
          +
          +

          LONDON, Printed by Jo. + Martyn, and Ja. Allestry, + Printers to the ROYAL SOCIETY , and are to + be sold at their Shop at the Bell in S. Paul's Church-yard. M D C L X V.


          diff --git a/src/hotspot/.editorconfig b/src/hotspot/.editorconfig deleted file mode 100644 index 48e63362b54..00000000000 --- a/src/hotspot/.editorconfig +++ /dev/null @@ -1,3 +0,0 @@ -[*.{cpp,hpp,c,h}] -indent_style = space -indent_size = 2 diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 76e3c92ddc2..f367362b4d8 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. // Copyright (c) 2014, 2024, Red Hat, Inc. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // @@ -2296,6 +2296,26 @@ bool Matcher::match_rule_supported(int opcode) { return false; } break; + case Op_FmaHF: + // UseFMA flag also needs to be checked along with FEAT_FP16 + if (!UseFMA || !is_feat_fp16_supported()) { + return false; + } + break; + case Op_AddHF: + case Op_SubHF: + case Op_MulHF: + case Op_DivHF: + case Op_MinHF: + case Op_MaxHF: + case Op_SqrtHF: + // Half-precision floating point scalar operations require FEAT_FP16 + // to be available. FEAT_FP16 is enabled if both "fphp" and "asimdhp" + // features are supported. + if (!is_feat_fp16_supported()) { + return false; + } + break; } return true; // Per default match rules are supported. @@ -2306,11 +2326,11 @@ const RegMask* Matcher::predicate_reg_mask(void) { } bool Matcher::supports_vector_calling_convention(void) { - return EnableVectorSupport && UseVectorStubs; + return EnableVectorSupport; } OptoRegPair Matcher::vector_return_value(uint ideal_reg) { - assert(EnableVectorSupport && UseVectorStubs, "sanity"); + assert(EnableVectorSupport, "sanity"); int lo = V0_num; int hi = V0_H_num; if (ideal_reg == Op_VecX || ideal_reg == Op_VecA) { @@ -4599,6 +4619,15 @@ operand immF0() interface(CONST_INTER); %} +// Half Float (FP16) Immediate +operand immH() +%{ + match(ConH); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // operand immFPacked() %{ @@ -6942,6 +6971,21 @@ instruct loadConD(vRegD dst, immD con) %{ ins_pipe(fp_load_constant_d); %} +// Load Half Float Constant +// The "ldr" instruction loads a 32-bit word from the constant pool into a +// 32-bit register but only the bottom half will be populated and the top +// 16 bits are zero. +instruct loadConH(vRegF dst, immH con) %{ + match(Set dst con); + format %{ + "ldrs $dst, [$constantaddress]\t# load from constant table: half float=$con\n\t" + %} + ins_encode %{ + __ ldrs(as_FloatRegister($dst$$reg), $constantaddress($con)); + %} + ins_pipe(fp_load_constant_s); +%} + // Store Instructions // Store Byte @@ -7717,14 +7761,12 @@ instruct popCountI(iRegINoSp dst, iRegIorL2I src, vRegF tmp) %{ effect(TEMP tmp); ins_cost(INSN_COST * 13); - format %{ "movw $src, $src\n\t" - "mov $tmp, $src\t# vector (1D)\n\t" + format %{ "fmovs $tmp, $src\t# vector (1S)\n\t" "cnt $tmp, $tmp\t# vector (8B)\n\t" "addv $tmp, $tmp\t# vector (8B)\n\t" "mov $dst, $tmp\t# vector (1D)" %} ins_encode %{ - __ movw($src$$Register, $src$$Register); // ensure top 32 bits 0 - __ mov($tmp$$FloatRegister, __ D, 0, $src$$Register); + __ fmovs($tmp$$FloatRegister, $src$$Register); __ cnt($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ addv($tmp$$FloatRegister, __ T8B, $tmp$$FloatRegister); __ mov($dst$$Register, $tmp$$FloatRegister, __ D, 0); @@ -8144,6 +8186,7 @@ instruct castPP(iRegPNoSp dst) instruct castII(iRegI dst) %{ + predicate(VerifyConstraintCasts == 0); match(Set dst (CastII dst)); size(0); @@ -8153,8 +8196,22 @@ instruct castII(iRegI dst) ins_pipe(pipe_class_empty); %} +instruct castII_checked(iRegI dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0); + match(Set dst (CastII dst)); + effect(KILL cr); + + format %{ "# castII_checked of $dst" %} + ins_encode %{ + __ verify_int_in_range(_idx, bottom_type()->is_int(), $dst$$Register, rscratch1); + %} + ins_pipe(pipe_slow); +%} + instruct castLL(iRegL dst) %{ + predicate(VerifyConstraintCasts == 0); match(Set dst (CastLL dst)); size(0); @@ -8164,6 +8221,29 @@ instruct castLL(iRegL dst) ins_pipe(pipe_class_empty); %} +instruct castLL_checked(iRegL dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0); + match(Set dst (CastLL dst)); + effect(KILL cr); + + format %{ "# castLL_checked of $dst" %} + ins_encode %{ + __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, rscratch1); + %} + ins_pipe(pipe_slow); +%} + +instruct castHH(vRegF dst) +%{ + match(Set dst (CastHH dst)); + size(0); + format %{ "# castHH of $dst" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(pipe_class_empty); +%} + instruct castFF(vRegF dst) %{ match(Set dst (CastFF dst)); @@ -13606,6 +13686,17 @@ instruct bits_reverse_L(iRegLNoSp dst, iRegL src) // ============================================================================ // Floating Point Arithmetic Instructions +instruct addHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (AddHF src1 src2)); + format %{ "faddh $dst, $src1, $src2" %} + ins_encode %{ + __ faddh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + instruct addF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (AddF src1 src2)); @@ -13636,6 +13727,17 @@ instruct addD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ ins_pipe(fp_dop_reg_reg_d); %} +instruct subHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (SubHF src1 src2)); + format %{ "fsubh $dst, $src1, $src2" %} + ins_encode %{ + __ fsubh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + instruct subF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (SubF src1 src2)); @@ -13666,6 +13768,17 @@ instruct subD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ ins_pipe(fp_dop_reg_reg_d); %} +instruct mulHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (MulHF src1 src2)); + format %{ "fmulh $dst, $src1, $src2" %} + ins_encode %{ + __ fmulh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + instruct mulF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (MulF src1 src2)); @@ -13696,6 +13809,20 @@ instruct mulD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ ins_pipe(fp_dop_reg_reg_d); %} +// src1 * src2 + src3 (half-precision float) +instruct maddHF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{ + match(Set dst (FmaHF src3 (Binary src1 src2))); + format %{ "fmaddh $dst, $src1, $src2, $src3" %} + ins_encode %{ + assert(UseFMA, "Needs FMA instructions support."); + __ fmaddh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister, + $src3$$FloatRegister); + %} + ins_pipe(pipe_class_default); +%} + // src1 * src2 + src3 instruct maddF_reg_reg(vRegF dst, vRegF src1, vRegF src2, vRegF src3) %{ match(Set dst (FmaF src3 (Binary src1 src2))); @@ -13837,6 +13964,29 @@ instruct mnsubD_reg_reg(vRegD dst, vRegD src1, vRegD src2, vRegD src3, immD0 zer ins_pipe(pipe_class_default); %} +// Math.max(HH)H (half-precision float) +instruct maxHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (MaxHF src1 src2)); + format %{ "fmaxh $dst, $src1, $src2" %} + ins_encode %{ + __ fmaxh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + +// Math.min(HH)H (half-precision float) +instruct minHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (MinHF src1 src2)); + format %{ "fminh $dst, $src1, $src2" %} + ins_encode %{ + __ fminh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_dop_reg_reg_s); +%} // Math.max(FF)F instruct maxF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ @@ -13894,6 +14044,16 @@ instruct minD_reg_reg(vRegD dst, vRegD src1, vRegD src2) %{ ins_pipe(fp_dop_reg_reg_d); %} +instruct divHF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ + match(Set dst (DivHF src1 src2)); + format %{ "fdivh $dst, $src1, $src2" %} + ins_encode %{ + __ fdivh($dst$$FloatRegister, + $src1$$FloatRegister, + $src2$$FloatRegister); + %} + ins_pipe(fp_div_s); +%} instruct divF_reg_reg(vRegF dst, vRegF src1, vRegF src2) %{ match(Set dst (DivF src1 src2)); @@ -14067,6 +14227,16 @@ instruct sqrtF_reg(vRegF dst, vRegF src) %{ ins_pipe(fp_div_d); %} +instruct sqrtHF_reg(vRegF dst, vRegF src) %{ + match(Set dst (SqrtHF src)); + format %{ "fsqrth $dst, $src" %} + ins_encode %{ + __ fsqrth($dst$$FloatRegister, + $src$$FloatRegister); + %} + ins_pipe(fp_div_s); +%} + // Math.rint, floor, ceil instruct roundD_reg(vRegD dst, vRegD src, immI rmode) %{ match(Set dst (RoundDoubleMode src rmode)); @@ -17116,6 +17286,64 @@ instruct expandBitsL_memcon(iRegINoSp dst, memory8 mem, immL mask, ins_pipe(pipe_slow); %} +//----------------------------- Reinterpret ---------------------------------- +// Reinterpret a half-precision float value in a floating point register to a general purpose register +instruct reinterpretHF2S(iRegINoSp dst, vRegF src) %{ + match(Set dst (ReinterpretHF2S src)); + format %{ "reinterpretHF2S $dst, $src" %} + ins_encode %{ + __ smov($dst$$Register, $src$$FloatRegister, __ H, 0); + %} + ins_pipe(pipe_slow); +%} + +// Reinterpret a half-precision float value in a general purpose register to a floating point register +instruct reinterpretS2HF(vRegF dst, iRegINoSp src) %{ + match(Set dst (ReinterpretS2HF src)); + format %{ "reinterpretS2HF $dst, $src" %} + ins_encode %{ + __ mov($dst$$FloatRegister, __ H, 0, $src$$Register); + %} + ins_pipe(pipe_slow); +%} + +// Without this optimization, ReinterpretS2HF (ConvF2HF src) would result in the following +// instructions (the first two are for ConvF2HF and the last instruction is for ReinterpretS2HF) - +// fcvt $tmp1_fpr, $src_fpr // Convert float to half-precision float +// mov $tmp2_gpr, $tmp1_fpr // Move half-precision float in FPR to a GPR +// mov $dst_fpr, $tmp2_gpr // Move the result from a GPR to an FPR +// The move from FPR to GPR in ConvF2HF and the move from GPR to FPR in ReinterpretS2HF +// can be omitted in this pattern, resulting in - +// fcvt $dst, $src // Convert float to half-precision float +instruct convF2HFAndS2HF(vRegF dst, vRegF src) +%{ + match(Set dst (ReinterpretS2HF (ConvF2HF src))); + format %{ "convF2HFAndS2HF $dst, $src" %} + ins_encode %{ + __ fcvtsh($dst$$FloatRegister, $src$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + +// Without this optimization, ConvHF2F (ReinterpretHF2S src) would result in the following +// instructions (the first one is for ReinterpretHF2S and the last two are for ConvHF2F) - +// mov $tmp1_gpr, $src_fpr // Move the half-precision float from an FPR to a GPR +// mov $tmp2_fpr, $tmp1_gpr // Move the same value from GPR to an FPR +// fcvt $dst_fpr, $tmp2_fpr // Convert the half-precision float to 32-bit float +// The move from FPR to GPR in ReinterpretHF2S and the move from GPR to FPR in ConvHF2F +// can be omitted as the input (src) is already in an FPR required for the fcvths instruction +// resulting in - +// fcvt $dst, $src // Convert half-precision float to a 32-bit float +instruct convHF2SAndHF2F(vRegF dst, vRegF src) +%{ + match(Set dst (ConvHF2F (ReinterpretHF2S src))); + format %{ "convHF2SAndHF2F $dst, $src" %} + ins_encode %{ + __ fcvths($dst$$FloatRegister, $src$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + // ============================================================================ // This name is KNOWN by the ADLC and cannot be changed. // The ADLC forces a 'TypeRawPtr::BOTTOM' output type diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index c7a0fc5724b..b4e6d79347f 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -1,6 +1,6 @@ // // Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2024, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2025, 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 @@ -225,6 +225,26 @@ source %{ return false; } break; + case Op_AddVHF: + case Op_SubVHF: + case Op_MulVHF: + case Op_DivVHF: + case Op_MinVHF: + case Op_MaxVHF: + case Op_SqrtVHF: + // FEAT_FP16 is enabled if both "fphp" and "asimdhp" features are supported. + // Only the Neon instructions need this check. SVE supports half-precision floats + // by default. + if (UseSVE == 0 && !is_feat_fp16_supported()) { + return false; + } + break; + case Op_FmaVHF: + // UseFMA flag needs to be checked along with FEAT_FP16 + if (!UseFMA || (UseSVE == 0 && !is_feat_fp16_supported())) { + return false; + } + break; default: break; } @@ -270,6 +290,19 @@ source %{ case Op_StoreVectorScatter: opcode = Op_StoreVectorScatterMasked; break; + // Currently, the masked versions of the following 8 Float16 operations are disabled. + // When the support for Float16 vector classes is added in VectorAPI and the masked + // Float16 IR can be generated, these masked operations will be enabled and relevant + // backend support added. + case Op_AddVHF: + case Op_SubVHF: + case Op_MulVHF: + case Op_DivVHF: + case Op_MaxVHF: + case Op_MinVHF: + case Op_SqrtVHF: + case Op_FmaVHF: + return false; default: break; } @@ -583,6 +616,22 @@ instruct vaddL(vReg dst, vReg src1, vReg src2) %{ ins_pipe(pipe_slow); %} +instruct vaddHF(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (AddVHF src1 src2)); + format %{ "vaddHF $dst, $src1, $src2" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this); + if (VM_Version::use_neon_for_vector(length_in_bytes)) { + __ fadd($dst$$FloatRegister, get_arrangement(this), + $src1$$FloatRegister, $src2$$FloatRegister); + } else { + assert(UseSVE > 0, "must be sve"); + __ sve_fadd($dst$$FloatRegister, __ H, $src1$$FloatRegister, $src2$$FloatRegister); + } + %} + ins_pipe(pipe_slow); +%} + instruct vaddF(vReg dst, vReg src1, vReg src2) %{ match(Set dst (AddVF src1 src2)); format %{ "vaddF $dst, $src1, $src2" %} @@ -807,6 +856,22 @@ instruct vsubL(vReg dst, vReg src1, vReg src2) %{ ins_pipe(pipe_slow); %} +instruct vsubHF(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (SubVHF src1 src2)); + format %{ "vsubHF $dst, $src1, $src2" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this); + if (VM_Version::use_neon_for_vector(length_in_bytes)) { + __ fsub($dst$$FloatRegister, get_arrangement(this), + $src1$$FloatRegister, $src2$$FloatRegister); + } else { + assert(UseSVE > 0, "must be sve"); + __ sve_fsub($dst$$FloatRegister, __ H, $src1$$FloatRegister, $src2$$FloatRegister); + } + %} + ins_pipe(pipe_slow); +%} + instruct vsubF(vReg dst, vReg src1, vReg src2) %{ match(Set dst (SubVF src1 src2)); format %{ "vsubF $dst, $src1, $src2" %} @@ -1004,6 +1069,22 @@ instruct vmulL_sve(vReg dst_src1, vReg src2) %{ // vector mul - floating-point +instruct vmulHF(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (MulVHF src1 src2)); + format %{ "vmulHF $dst, $src1, $src2" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this); + if (VM_Version::use_neon_for_vector(length_in_bytes)) { + __ fmul($dst$$FloatRegister, get_arrangement(this), + $src1$$FloatRegister, $src2$$FloatRegister); + } else { + assert(UseSVE > 0, "must be sve"); + __ sve_fmul($dst$$FloatRegister, __ H, $src1$$FloatRegister, $src2$$FloatRegister); + } + %} + ins_pipe(pipe_slow); +%} + instruct vmulF(vReg dst, vReg src1, vReg src2) %{ match(Set dst (MulVF src1 src2)); format %{ "vmulF $dst, $src1, $src2" %} @@ -1102,6 +1183,28 @@ instruct vmulD_masked(vReg dst_src1, vReg src2, pRegGov pg) %{ // vector float div +instruct vdivHF_neon(vReg dst, vReg src1, vReg src2) %{ + predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n))); + match(Set dst (DivVHF src1 src2)); + format %{ "vdivHF_neon $dst, $src1, $src2" %} + ins_encode %{ + __ fdiv($dst$$FloatRegister, get_arrangement(this), + $src1$$FloatRegister, $src2$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct vdivHF_sve(vReg dst_src1, vReg src2) %{ + predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n))); + match(Set dst_src1 (DivVHF dst_src1 src2)); + format %{ "vdivHF_sve $dst_src1, $dst_src1, $src2" %} + ins_encode %{ + assert(UseSVE > 0, "must be sve"); + __ sve_fdiv($dst_src1$$FloatRegister, __ H, ptrue, $src2$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + instruct vdivF_neon(vReg dst, vReg src1, vReg src2) %{ predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n))); match(Set dst (DivVF src1 src2)); @@ -1991,6 +2094,21 @@ instruct vnegD_masked(vReg dst_src, pRegGov pg) %{ // vector sqrt +instruct vsqrtHF(vReg dst, vReg src) %{ + match(Set dst (SqrtVHF src)); + format %{ "vsqrtHF $dst, $src" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this); + if (VM_Version::use_neon_for_vector(length_in_bytes)) { + __ fsqrt($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister); + } else { + assert(UseSVE > 0, "must be sve"); + __ sve_fsqrt($dst$$FloatRegister, __ H, ptrue, $src$$FloatRegister); + } + %} + ins_pipe(pipe_slow); +%} + instruct vsqrtF(vReg dst, vReg src) %{ match(Set dst (SqrtVF src)); format %{ "vsqrtF $dst, $src" %} @@ -2069,7 +2187,7 @@ instruct vminL_sve(vReg dst_src1, vReg src2) %{ ins_pipe(pipe_slow); %} -// vector min - B/S/I/F/D +// vector min - B/S/I/HF/F/D instruct vmin_neon(vReg dst, vReg src1, vReg src2) %{ predicate(Matcher::vector_element_basic_type(n) != T_LONG && @@ -2110,6 +2228,29 @@ instruct vmin_sve(vReg dst_src1, vReg src2) %{ ins_pipe(pipe_slow); %} +instruct vmin_HF_neon(vReg dst, vReg src1, vReg src2) %{ + predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n))); + match(Set dst (MinVHF src1 src2)); + format %{ "vmin_HF_neon $dst, $src1, $src2\t# Half float" %} + ins_encode %{ + __ fmin($dst$$FloatRegister, get_arrangement(this), + $src1$$FloatRegister, $src2$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct vmin_HF_sve(vReg dst_src1, vReg src2) %{ + predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n))); + match(Set dst_src1 (MinVHF dst_src1 src2)); + format %{ "vmin_HF_sve $dst_src1, $dst_src1, $src2\t# Half float" %} + ins_encode %{ + assert(UseSVE > 0, "must be sve"); + __ sve_fmin($dst_src1$$FloatRegister, __ H, + ptrue, $src2$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + // vector min - predicated instruct vmin_masked(vReg dst_src1, vReg src2, pRegGov pg) %{ @@ -2226,7 +2367,7 @@ instruct vmaxL_sve(vReg dst_src1, vReg src2) %{ ins_pipe(pipe_slow); %} -// vector max - B/S/I/F/D +// vector max - B/S/I/HF/F/D instruct vmax_neon(vReg dst, vReg src1, vReg src2) %{ predicate(Matcher::vector_element_basic_type(n) != T_LONG && @@ -2267,6 +2408,29 @@ instruct vmax_sve(vReg dst_src1, vReg src2) %{ ins_pipe(pipe_slow); %} +instruct vmax_HF_neon(vReg dst, vReg src1, vReg src2) %{ + predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n))); + match(Set dst (MaxVHF src1 src2)); + format %{ "vmax_HF_neon $dst, $src1, $src2\t# Half float" %} + ins_encode %{ + __ fmax($dst$$FloatRegister, get_arrangement(this), + $src1$$FloatRegister, $src2$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct vmax_HF_sve(vReg dst_src1, vReg src2) %{ + predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n))); + match(Set dst_src1 (MaxVHF dst_src1 src2)); + format %{ "vmax_HF_sve $dst_src1, $dst_src1, $src2\t# Half float" %} + ins_encode %{ + assert(UseSVE > 0, "must be sve"); + __ sve_fmax($dst_src1$$FloatRegister, __ H, + ptrue, $src2$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + // vector max - predicated instruct vmax_masked(vReg dst_src1, vReg src2, pRegGov pg) %{ @@ -2413,8 +2577,9 @@ instruct vmla_masked(vReg dst_src1, vReg src2, vReg src3, pRegGov pg) %{ // dst_src1 = src2 * src3 + dst_src1 instruct vfmla(vReg dst_src1, vReg src2, vReg src3) %{ - match(Set dst_src1 (FmaVF dst_src1 (Binary src2 src3))); - match(Set dst_src1 (FmaVD dst_src1 (Binary src2 src3))); + match(Set dst_src1 (FmaVHF dst_src1 (Binary src2 src3))); + match(Set dst_src1 (FmaVF dst_src1 (Binary src2 src3))); + match(Set dst_src1 (FmaVD dst_src1 (Binary src2 src3))); format %{ "vfmla $dst_src1, $src2, $src3" %} ins_encode %{ assert(UseFMA, "Needs FMA instructions support."); @@ -4613,6 +4778,23 @@ instruct replicateD(vReg dst, vRegD src) %{ ins_pipe(pipe_slow); %} +// Replicate a half-precision float value held in a floating point register +instruct replicateHF(vReg dst, vRegF src) %{ + predicate(Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst (Replicate src)); + format %{ "replicateHF $dst, $src\t# replicate half-precision float" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this); + if (VM_Version::use_neon_for_vector(length_in_bytes)) { + __ dup($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister); + } else { // length_in_bytes must be > 16 and SVE should be enabled + assert(UseSVE > 0, "must be sve"); + __ sve_cpy($dst$$FloatRegister, __ H, ptrue, $src$$FloatRegister); + } + %} + ins_pipe(pipe_slow); +%} + // replicate from imm instruct replicateI_imm_le128b(vReg dst, immI con) %{ @@ -4681,6 +4863,23 @@ instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ ins_pipe(pipe_slow); %} +// Replicate a 16-bit half precision float value +instruct replicateHF_imm(vReg dst, immH con) %{ + match(Set dst (Replicate con)); + format %{ "replicateHF_imm $dst, $con\t# replicate immediate half-precision float" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this); + int imm = (int)($con$$constant) & 0xffff; + if (VM_Version::use_neon_for_vector(length_in_bytes)) { + __ mov($dst$$FloatRegister, get_arrangement(this), imm); + } else { // length_in_bytes must be > 16 and SVE should be enabled + assert(UseSVE > 0, "must be sve"); + __ sve_dup($dst$$FloatRegister, __ H, imm); + } + %} + ins_pipe(pipe_slow); +%} + // ------------------------------ Vector insert -------------------------------- // BYTE, SHORT, INT diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 171bc390545..cc07e0e4076 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -1,6 +1,6 @@ // // Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2020, 2024, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2025, 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 @@ -215,6 +215,26 @@ source %{ return false; } break; + case Op_AddVHF: + case Op_SubVHF: + case Op_MulVHF: + case Op_DivVHF: + case Op_MinVHF: + case Op_MaxVHF: + case Op_SqrtVHF: + // FEAT_FP16 is enabled if both "fphp" and "asimdhp" features are supported. + // Only the Neon instructions need this check. SVE supports half-precision floats + // by default. + if (UseSVE == 0 && !is_feat_fp16_supported()) { + return false; + } + break; + case Op_FmaVHF: + // UseFMA flag needs to be checked along with FEAT_FP16 + if (!UseFMA || (UseSVE == 0 && !is_feat_fp16_supported())) { + return false; + } + break; default: break; } @@ -260,6 +280,19 @@ source %{ case Op_StoreVectorScatter: opcode = Op_StoreVectorScatterMasked; break; + // Currently, the masked versions of the following 8 Float16 operations are disabled. + // When the support for Float16 vector classes is added in VectorAPI and the masked + // Float16 IR can be generated, these masked operations will be enabled and relevant + // backend support added. + case Op_AddVHF: + case Op_SubVHF: + case Op_MulVHF: + case Op_DivVHF: + case Op_MaxVHF: + case Op_MinVHF: + case Op_SqrtVHF: + case Op_FmaVHF: + return false; default: break; } @@ -508,12 +541,13 @@ dnl // ------------------------------ Vector add ----------------------------------- // vector add -BINARY_OP(vaddB, AddVB, addv, sve_add, B) -BINARY_OP(vaddS, AddVS, addv, sve_add, H) -BINARY_OP(vaddI, AddVI, addv, sve_add, S) -BINARY_OP(vaddL, AddVL, addv, sve_add, D) -BINARY_OP(vaddF, AddVF, fadd, sve_fadd, S) -BINARY_OP(vaddD, AddVD, fadd, sve_fadd, D) +BINARY_OP(vaddB, AddVB, addv, sve_add, B) +BINARY_OP(vaddS, AddVS, addv, sve_add, H) +BINARY_OP(vaddI, AddVI, addv, sve_add, S) +BINARY_OP(vaddL, AddVL, addv, sve_add, D) +BINARY_OP(vaddHF, AddVHF, fadd, sve_fadd, H) +BINARY_OP(vaddF, AddVF, fadd, sve_fadd, S) +BINARY_OP(vaddD, AddVD, fadd, sve_fadd, D) // vector add - predicated BINARY_OP_PREDICATE(vaddB, AddVB, sve_add, B) @@ -532,12 +566,13 @@ VADD_IMM(L, immLAddSubV, D) // ------------------------------ Vector sub ----------------------------------- // vector sub -BINARY_OP(vsubB, SubVB, subv, sve_sub, B) -BINARY_OP(vsubS, SubVS, subv, sve_sub, H) -BINARY_OP(vsubI, SubVI, subv, sve_sub, S) -BINARY_OP(vsubL, SubVL, subv, sve_sub, D) -BINARY_OP(vsubF, SubVF, fsub, sve_fsub, S) -BINARY_OP(vsubD, SubVD, fsub, sve_fsub, D) +BINARY_OP(vsubB, SubVB, subv, sve_sub, B) +BINARY_OP(vsubS, SubVS, subv, sve_sub, H) +BINARY_OP(vsubI, SubVI, subv, sve_sub, S) +BINARY_OP(vsubL, SubVL, subv, sve_sub, D) +BINARY_OP(vsubHF, SubVHF, fsub, sve_fsub, H) +BINARY_OP(vsubF, SubVF, fsub, sve_fsub, S) +BINARY_OP(vsubD, SubVD, fsub, sve_fsub, D) // vector sub - predicated BINARY_OP_PREDICATE(vsubB, SubVB, sve_sub, B) @@ -612,8 +647,9 @@ instruct vmulL_sve(vReg dst_src1, vReg src2) %{ %} // vector mul - floating-point -BINARY_OP(vmulF, MulVF, fmul, sve_fmul, S) -BINARY_OP(vmulD, MulVD, fmul, sve_fmul, D) +BINARY_OP(vmulHF, MulVHF, fmul, sve_fmul, H) +BINARY_OP(vmulF, MulVF, fmul, sve_fmul, S) +BINARY_OP(vmulD, MulVD, fmul, sve_fmul, D) // vector mul - predicated BINARY_OP_PREDICATE(vmulB, MulVB, sve_mul, B) @@ -626,8 +662,9 @@ BINARY_OP_PREDICATE(vmulD, MulVD, sve_fmul, D) // ------------------------------ Vector float div ----------------------------- // vector float div -BINARY_OP_NEON_SVE_PAIRWISE(vdivF, DivVF, fdiv, sve_fdiv, S) -BINARY_OP_NEON_SVE_PAIRWISE(vdivD, DivVD, fdiv, sve_fdiv, D) +BINARY_OP_NEON_SVE_PAIRWISE(vdivHF, DivVHF, fdiv, sve_fdiv, H) +BINARY_OP_NEON_SVE_PAIRWISE(vdivF, DivVF, fdiv, sve_fdiv, S) +BINARY_OP_NEON_SVE_PAIRWISE(vdivD, DivVD, fdiv, sve_fdiv, D) // vector float div - predicated BINARY_OP_PREDICATE(vdivF, DivVF, sve_fdiv, S) @@ -1016,8 +1053,9 @@ UNARY_OP_PREDICATE_WITH_SIZE(vnegD, NegVD, sve_fneg, D) // ------------------------------ Vector sqrt ---------------------------------- // vector sqrt -UNARY_OP(vsqrtF, SqrtVF, fsqrt, sve_fsqrt, S) -UNARY_OP(vsqrtD, SqrtVD, fsqrt, sve_fsqrt, D) +UNARY_OP(vsqrtHF, SqrtVHF, fsqrt, sve_fsqrt, H) +UNARY_OP(vsqrtF, SqrtVF, fsqrt, sve_fsqrt, S) +UNARY_OP(vsqrtD, SqrtVD, fsqrt, sve_fsqrt, D) // vector sqrt - predicated UNARY_OP_PREDICATE_WITH_SIZE(vsqrtF, SqrtVF, sve_fsqrt, S) @@ -1074,6 +1112,20 @@ instruct v$1_neon(vReg dst, vReg src1, vReg src2) %{ ins_pipe(pipe_slow); %}')dnl dnl +dnl VMINMAX_HF_NEON($1, $2, $3 ) +dnl VMINMAX_HF_NEON(type, op_name, insn_fp) +define(`VMINMAX_HF_NEON', ` +instruct v$1_HF_neon(vReg dst, vReg src1, vReg src2) %{ + predicate(VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n))); + match(Set dst ($2 src1 src2)); + format %{ "v$1_HF_neon $dst, $src1, $src2\t# Half float" %} + ins_encode %{ + __ $3($dst$$FloatRegister, get_arrangement(this), + $src1$$FloatRegister, $src2$$FloatRegister); + %} + ins_pipe(pipe_slow); +%}')dnl +dnl dnl VMINMAX_SVE($1, $2, $3, $4 ) dnl VMINMAX_SVE(type, op_name, insn_fp, insn_integral) define(`VMINMAX_SVE', ` @@ -1097,6 +1149,21 @@ instruct v$1_sve(vReg dst_src1, vReg src2) %{ ins_pipe(pipe_slow); %}')dnl dnl +dnl VMINMAX_HF_SVE($1, $2, $3 ) +dnl VMINMAX_HF_SVE(type, op_name, insn_fp) +define(`VMINMAX_HF_SVE', ` +instruct v$1_HF_sve(vReg dst_src1, vReg src2) %{ + predicate(!VM_Version::use_neon_for_vector(Matcher::vector_length_in_bytes(n))); + match(Set dst_src1 ($2 dst_src1 src2)); + format %{ "v$1_HF_sve $dst_src1, $dst_src1, $src2\t# Half float" %} + ins_encode %{ + assert(UseSVE > 0, "must be sve"); + __ $3($dst_src1$$FloatRegister, __ H, + ptrue, $src2$$FloatRegister); + %} + ins_pipe(pipe_slow); +%}')dnl +dnl dnl VMINMAX_PREDICATE($1, $2, $3, $4 ) dnl VMINMAX_PREDICATE(type, op_name, insn_fp, insn_integral) define(`VMINMAX_PREDICATE', ` @@ -1175,9 +1242,11 @@ dnl VMINMAX_L_NEON(min, MinV) VMINMAX_L_SVE(min, MinV, sve_smin) -// vector min - B/S/I/F/D +// vector min - B/S/I/HF/F/D VMINMAX_NEON(min, MinV, fmin, minv) VMINMAX_SVE(min, MinV, sve_fmin, sve_smin) +VMINMAX_HF_NEON(min, MinVHF, fmin) +VMINMAX_HF_SVE(min, MinVHF, sve_fmin) // vector min - predicated VMINMAX_PREDICATE(min, MinV, sve_fmin, sve_smin) @@ -1199,9 +1268,11 @@ VUMINMAX_PREDICATE(umin, UMinV, sve_umin) VMINMAX_L_NEON(max, MaxV) VMINMAX_L_SVE(max, MaxV, sve_smax) -// vector max - B/S/I/F/D +// vector max - B/S/I/HF/F/D VMINMAX_NEON(max, MaxV, fmax, maxv) VMINMAX_SVE(max, MaxV, sve_fmax, sve_smax) +VMINMAX_HF_NEON(max, MaxVHF, fmax) +VMINMAX_HF_SVE(max, MaxVHF, sve_fmax) // vector max - predicated VMINMAX_PREDICATE(max, MaxV, sve_fmax, sve_smax) @@ -1273,8 +1344,9 @@ instruct vmla_masked(vReg dst_src1, vReg src2, vReg src3, pRegGov pg) %{ // dst_src1 = src2 * src3 + dst_src1 instruct vfmla(vReg dst_src1, vReg src2, vReg src3) %{ - match(Set dst_src1 (FmaVF dst_src1 (Binary src2 src3))); - match(Set dst_src1 (FmaVD dst_src1 (Binary src2 src3))); + match(Set dst_src1 (FmaVHF dst_src1 (Binary src2 src3))); + match(Set dst_src1 (FmaVF dst_src1 (Binary src2 src3))); + match(Set dst_src1 (FmaVD dst_src1 (Binary src2 src3))); format %{ "vfmla $dst_src1, $src2, $src3" %} ins_encode %{ assert(UseFMA, "Needs FMA instructions support."); @@ -2938,6 +3010,23 @@ REPLICATE_INT(L, iRegL) REPLICATE_FP(F, S, T_FLOAT ) REPLICATE_FP(D, D, T_DOUBLE) +// Replicate a half-precision float value held in a floating point register +instruct replicateHF(vReg dst, vRegF src) %{ + predicate(Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst (Replicate src)); + format %{ "replicateHF $dst, $src\t# replicate half-precision float" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this); + if (VM_Version::use_neon_for_vector(length_in_bytes)) { + __ dup($dst$$FloatRegister, get_arrangement(this), $src$$FloatRegister); + } else { // length_in_bytes must be > 16 and SVE should be enabled + assert(UseSVE > 0, "must be sve"); + __ sve_cpy($dst$$FloatRegister, __ H, ptrue, $src$$FloatRegister); + } + %} + ins_pipe(pipe_slow); +%} + // replicate from imm instruct replicateI_imm_le128b(vReg dst, immI con) %{ @@ -3006,6 +3095,23 @@ instruct replicateL_imm8_gt128b(vReg dst, immL8_shift8 con) %{ ins_pipe(pipe_slow); %} +// Replicate a 16-bit half precision float value +instruct replicateHF_imm(vReg dst, immH con) %{ + match(Set dst (Replicate con)); + format %{ "replicateHF_imm $dst, $con\t# replicate immediate half-precision float" %} + ins_encode %{ + uint length_in_bytes = Matcher::vector_length_in_bytes(this); + int imm = (int)($con$$constant) & 0xffff; + if (VM_Version::use_neon_for_vector(length_in_bytes)) { + __ mov($dst$$FloatRegister, get_arrangement(this), imm); + } else { // length_in_bytes must be > 16 and SVE should be enabled + assert(UseSVE > 0, "must be sve"); + __ sve_dup($dst$$FloatRegister, __ H, imm); + } + %} + ins_pipe(pipe_slow); +%} + // ------------------------------ Vector insert -------------------------------- // BYTE, SHORT, INT diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp index b03344f2d80..5e5d6c16b45 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.cpp @@ -240,6 +240,19 @@ void Assembler::add_sub_immediate(Instruction_aarch64 ¤t_insn, srf(Rn, 5); } +// This method is used to generate Advanced SIMD data processing instructions +void Assembler::adv_simd_three_same(Instruction_aarch64 ¤t_insn, FloatRegister Vd, + SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, + int op1, int op2, int op3) { + assert(T == T4H || T == T8H || T == T2S || T == T4S || T == T2D, "invalid arrangement"); + int op22 = (T == T2S || T == T4S) ? 0b0 : 0b1; + int op21 = (T == T4H || T == T8H) ? 0b0 : 0b1; + int op14 = (T == T4H || T == T8H) ? 0b00 : 0b11; + f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01110, 28, 24), f(op2, 23); + f(op22, 22); f(op21, 21), rf(Vm, 16), f(op14, 15, 14), f(op3, 13, 10), + rf(Vn, 5), rf(Vd, 0); +} + #undef f #undef sf #undef rf @@ -456,7 +469,7 @@ 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); + uint64_t uimm = (uint64_t)g_uabs((jlong)imm); if (uimm < (UCONST64(1) << nbits)) return true; if (uimm < (UCONST64(1) << (2 * nbits)) diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 3db7d308844..573b451261f 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -932,7 +932,7 @@ class Assembler : public AbstractAssembler { static const uint64_t branch_range = NOT_DEBUG(128 * M) DEBUG_ONLY(2 * M); static bool reachable_from_branch_at(address branch, address target) { - return uabs(target - branch) < branch_range; + return g_uabs(target - branch) < branch_range; } // Unconditional branch (immediate) @@ -2032,6 +2032,8 @@ void mvnw(Register Rd, Register Rm, INSN(fsqrtd, 0b01, 0b000011); INSN(fcvtd, 0b01, 0b000100); // Double-precision to single-precision + INSN(fsqrth, 0b11, 0b000011); // Half-precision sqrt + private: void _fcvt_narrow_extend(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, bool do_extend) { @@ -2059,37 +2061,68 @@ void mvnw(Register Rd, Register Rm, #undef INSN // Floating-point data-processing (2 source) - void data_processing(unsigned op31, unsigned type, unsigned opcode, + void data_processing(unsigned op31, unsigned type, unsigned opcode, unsigned op21, FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { starti; f(op31, 31, 29); f(0b11110, 28, 24); - f(type, 23, 22), f(1, 21), f(opcode, 15, 10); + f(type, 23, 22), f(op21, 21), f(opcode, 15, 10); rf(Vm, 16), rf(Vn, 5), rf(Vd, 0); } -#define INSN(NAME, op31, type, opcode) \ +#define INSN(NAME, op31, type, opcode, op21) \ void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \ - data_processing(op31, type, opcode, Vd, Vn, Vm); \ - } - - INSN(fabds, 0b011, 0b10, 0b110101); - INSN(fmuls, 0b000, 0b00, 0b000010); - INSN(fdivs, 0b000, 0b00, 0b000110); - INSN(fadds, 0b000, 0b00, 0b001010); - INSN(fsubs, 0b000, 0b00, 0b001110); - INSN(fmaxs, 0b000, 0b00, 0b010010); - INSN(fmins, 0b000, 0b00, 0b010110); - INSN(fnmuls, 0b000, 0b00, 0b100010); - - INSN(fabdd, 0b011, 0b11, 0b110101); - INSN(fmuld, 0b000, 0b01, 0b000010); - INSN(fdivd, 0b000, 0b01, 0b000110); - INSN(faddd, 0b000, 0b01, 0b001010); - INSN(fsubd, 0b000, 0b01, 0b001110); - INSN(fmaxd, 0b000, 0b01, 0b010010); - INSN(fmind, 0b000, 0b01, 0b010110); - INSN(fnmuld, 0b000, 0b01, 0b100010); + data_processing(op31, type, opcode, op21, Vd, Vn, Vm); \ + } + + INSN(fmuls, 0b000, 0b00, 0b000010, 0b1); + INSN(fdivs, 0b000, 0b00, 0b000110, 0b1); + INSN(fadds, 0b000, 0b00, 0b001010, 0b1); + INSN(fsubs, 0b000, 0b00, 0b001110, 0b1); + INSN(fmaxs, 0b000, 0b00, 0b010010, 0b1); + INSN(fmins, 0b000, 0b00, 0b010110, 0b1); + INSN(fnmuls, 0b000, 0b00, 0b100010, 0b1); + + INSN(fmuld, 0b000, 0b01, 0b000010, 0b1); + INSN(fdivd, 0b000, 0b01, 0b000110, 0b1); + INSN(faddd, 0b000, 0b01, 0b001010, 0b1); + INSN(fsubd, 0b000, 0b01, 0b001110, 0b1); + INSN(fmaxd, 0b000, 0b01, 0b010010, 0b1); + INSN(fmind, 0b000, 0b01, 0b010110, 0b1); + INSN(fnmuld, 0b000, 0b01, 0b100010, 0b1); + + // Half-precision floating-point instructions + INSN(fmulh, 0b000, 0b11, 0b000010, 0b1); + INSN(fdivh, 0b000, 0b11, 0b000110, 0b1); + INSN(faddh, 0b000, 0b11, 0b001010, 0b1); + INSN(fsubh, 0b000, 0b11, 0b001110, 0b1); + INSN(fmaxh, 0b000, 0b11, 0b010010, 0b1); + INSN(fminh, 0b000, 0b11, 0b010110, 0b1); + INSN(fnmulh, 0b000, 0b11, 0b100010, 0b1); +#undef INSN + +// Advanced SIMD scalar three same +#define INSN(NAME, U, size, opcode) \ + void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \ + starti; \ + f(0b01, 31, 30), f(U, 29), f(0b11110, 28, 24), f(size, 23, 22), f(1, 21); \ + rf(Vm, 16), f(opcode, 15, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0); \ + } + + INSN(fabds, 0b1, 0b10, 0b11010); // Floating-point Absolute Difference (single-precision) + INSN(fabdd, 0b1, 0b11, 0b11010); // Floating-point Absolute Difference (double-precision) + +#undef INSN + +// Advanced SIMD scalar three same FP16 +#define INSN(NAME, U, a, opcode) \ + void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \ + starti; \ + f(0b01, 31, 30), f(U, 29), f(0b11110, 28, 24), f(a, 23), f(0b10, 22, 21); \ + rf(Vm, 16), f(0b00, 15, 14), f(opcode, 13, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0); \ + } + + INSN(fabdh, 0b1, 0b1, 0b010); // Floating-point Absolute Difference (half-precision float) #undef INSN @@ -2120,6 +2153,7 @@ void mvnw(Register Rd, Register Rm, INSN(fnmaddd, 0b000, 0b01, 1, 0); INSN(fnmsub, 0b000, 0b01, 1, 1); + INSN(fmaddh, 0b000, 0b11, 0, 0); // half-precision fused multiply-add (scalar) #undef INSN // Floating-point conditional select @@ -2709,26 +2743,26 @@ template #undef INSN -// Advanced SIMD three same -#define INSN(NAME, op1, op2, op3) \ - void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \ - starti; \ - assert(T == T2S || T == T4S || T == T2D, "invalid arrangement"); \ - f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01110, 28, 24), f(op2, 23); \ - f(T==T2D ? 1:0, 22); f(1, 21), rf(Vm, 16), f(op3, 15, 10), rf(Vn, 5), rf(Vd, 0); \ - } - - INSN(fabd, 1, 1, 0b110101); - INSN(fadd, 0, 0, 0b110101); - INSN(fdiv, 1, 0, 0b111111); - INSN(faddp, 1, 0, 0b110101); - INSN(fmul, 1, 0, 0b110111); - INSN(fsub, 0, 1, 0b110101); - INSN(fmla, 0, 0, 0b110011); - INSN(fmls, 0, 1, 0b110011); - INSN(fmax, 0, 0, 0b111101); - INSN(fmin, 0, 1, 0b111101); - INSN(facgt, 1, 1, 0b111011); + // Advanced SIMD three same + void adv_simd_three_same(Instruction_aarch64 ¤t_insn, FloatRegister Vd, + SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, + int op1, int op2, int op3); +#define INSN(NAME, op1, op2, op3) \ + void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \ + starti; \ + adv_simd_three_same(current_insn, Vd, T, Vn, Vm, op1, op2, op3); \ + } + INSN(fabd, 1, 1, 0b0101); + INSN(fadd, 0, 0, 0b0101); + INSN(fdiv, 1, 0, 0b1111); + INSN(faddp, 1, 0, 0b0101); + INSN(fmul, 1, 0, 0b0111); + INSN(fsub, 0, 1, 0b0101); + INSN(fmla, 0, 0, 0b0011); + INSN(fmls, 0, 1, 0b0011); + INSN(fmax, 0, 0, 0b1101); + INSN(fmin, 0, 1, 0b1101); + INSN(facgt, 1, 1, 0b1011); #undef INSN @@ -3228,18 +3262,24 @@ template // parameter "tmask" is a 2-bit mask used to indicate which bits in the size // field are determined by the SIMD_Arrangement. The bit of "tmask" should be // set to 1 if corresponding bit marked as "x" in the ArmARM. -#define INSN(NAME, U, size, tmask, opcode) \ - void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \ - starti; \ - assert((ASSERTION), MSG); \ - f(0, 31), f((int)T & 1, 30), f(U, 29), f(0b01110, 28, 24); \ - f(size | ((int)(T >> 1) & tmask), 23, 22), f(0b10000, 21, 17); \ - f(opcode, 16, 12), f(0b10, 11, 10), rf(Vn, 5), rf(Vd, 0); \ +#define INSN(NAME, U, size, tmask, opcode) \ + void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \ + starti; \ + assert((ASSERTION), MSG); \ + int op22 = (int)(T >> 1) & tmask; \ + int op19 = 0b00; \ + if (tmask == 0b01 && (T == T4H || T == T8H)) { \ + op22 = 0b1; \ + op19 = 0b11; \ + } \ + f(0, 31), f((int)T & 1, 30), f(U, 29), f(0b01110, 28, 24); \ + f(size | op22, 23, 22), f(1, 21), f(op19, 20, 19), f(0b00, 18, 17); \ + f(opcode, 16, 12), f(0b10, 11, 10), rf(Vn, 5), rf(Vd, 0); \ } #define MSG "invalid arrangement" -#define ASSERTION (T == T2S || T == T4S || T == T2D) +#define ASSERTION (T == T4H || T == T8H || T == T2S || T == T4S || T == T2D) INSN(fsqrt, 1, 0b10, 0b01, 0b11111); INSN(fabs, 0, 0b10, 0b01, 0b01111); INSN(fneg, 1, 0b10, 0b01, 0b01111); @@ -3366,7 +3406,7 @@ template #define INSN(NAME, opcode) \ void NAME(FloatRegister Zd, SIMD_RegVariant T, FloatRegister Zn, FloatRegister Zm) { \ starti; \ - assert(T == S || T == D, "invalid register variant"); \ + assert(T == H || T == S || T == D, "invalid register variant"); \ f(0b01100101, 31, 24), f(T, 23, 22), f(0, 21), \ rf(Zm, 16), f(0, 15, 13), f(opcode, 12, 10), rf(Zn, 5), rf(Zd, 0); \ } @@ -3451,7 +3491,7 @@ template // SVE floating-point arithmetic - predicate #define INSN(NAME, op1, op2) \ void NAME(FloatRegister Zd_or_Zdn_or_Vd, SIMD_RegVariant T, PRegister Pg, FloatRegister Zn_or_Zm) { \ - assert(T == S || T == D, "invalid register variant"); \ + assert(T == H || T == S || T == D, "invalid register variant"); \ sve_predicate_reg_insn(op1, op2, Zd_or_Zdn_or_Vd, T, Pg, Zn_or_Zm); \ } diff --git a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp index 2334cbdff24..2e53ecb8058 100644 --- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp @@ -69,7 +69,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } @@ -90,7 +90,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ blr(lr); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { @@ -103,7 +103,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void DivByZeroStub::emit_code(LIR_Assembler* ce) { @@ -274,7 +274,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } @@ -289,7 +289,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { } __ far_call(RuntimeAddress(Runtime1::entry_for(_stub)), rscratch2); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } diff --git a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp index 6b1a5a7f1e0..afa2ddb47b4 100644 --- a/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_MacroAssembler_aarch64.cpp @@ -72,16 +72,17 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj); - ldrb(hdr, Address(hdr, Klass::misc_flags_offset())); - tst(hdr, KlassFlags::_misc_is_value_based_class); - br(Assembler::NE, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(disp_hdr, obj, hdr, temp, rscratch2, slow_case); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(hdr, obj); + ldrb(hdr, Address(hdr, Klass::misc_flags_offset())); + tst(hdr, KlassFlags::_misc_is_value_based_class); + br(Assembler::NE, slow_case); + } + Label done; // Load object header ldr(hdr, Address(obj, hdr_offset)); diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index 605a05a44a7..914967e4009 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -107,7 +107,8 @@ address C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register assert(is_power_of_2(unroll_factor), "can't use this value to calculate the jump target PC"); andr(tmp2, cnt, unroll_factor - 1); adr(tmp1, BR_BASE); - sub(tmp1, tmp1, tmp2, ext::sxtw, 3); + // For Cortex-A53 offset is 4 because 2 nops are generated. + sub(tmp1, tmp1, tmp2, ext::sxtw, VM_Version::supports_a53mac() ? 4 : 3); movw(tmp2, 0x1f); br(tmp1); @@ -115,6 +116,11 @@ address C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register for (size_t i = 0; i < unroll_factor; ++i) { load(tmp1, Address(post(ary, type2aelembytes(eltype))), eltype); maddw(result, result, tmp2, tmp1); + // maddw generates an extra nop for Cortex-A53 (see maddw definition in macroAssembler). + // Generate 2nd nop to have 4 instructions per iteration. + if (VM_Version::supports_a53mac()) { + nop(); + } } bind(BR_BASE); subsw(cnt, cnt, unroll_factor); @@ -360,7 +366,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist Label slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. str(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); } @@ -2743,3 +2749,107 @@ bool C2_MacroAssembler::in_scratch_emit_size() { } return MacroAssembler::in_scratch_emit_size(); } + +static void abort_verify_int_in_range(uint idx, jint val, jint lo, jint hi) { + fatal("Invalid CastII, idx: %u, val: %d, lo: %d, hi: %d", idx, val, lo, hi); +} + +void C2_MacroAssembler::verify_int_in_range(uint idx, const TypeInt* t, Register rval, Register rtmp) { + assert(!t->empty() && !t->singleton(), "%s", Type::str(t)); + if (t == TypeInt::INT) { + return; + } + BLOCK_COMMENT("verify_int_in_range {"); + Label L_success, L_failure; + + jint lo = t->_lo; + jint hi = t->_hi; + + if (lo != min_jint && hi != max_jint) { + subsw(rtmp, rval, lo); + br(Assembler::LT, L_failure); + subsw(rtmp, rval, hi); + br(Assembler::LE, L_success); + } else if (lo != min_jint) { + subsw(rtmp, rval, lo); + br(Assembler::GE, L_success); + } else if (hi != max_jint) { + subsw(rtmp, rval, hi); + br(Assembler::LE, L_success); + } else { + ShouldNotReachHere(); + } + + bind(L_failure); + movw(c_rarg0, idx); + mov(c_rarg1, rval); + movw(c_rarg2, lo); + movw(c_rarg3, hi); + reconstruct_frame_pointer(rtmp); + rt_call(CAST_FROM_FN_PTR(address, abort_verify_int_in_range), rtmp); + hlt(0); + + bind(L_success); + BLOCK_COMMENT("} verify_int_in_range"); +} + +static void abort_verify_long_in_range(uint idx, jlong val, jlong lo, jlong hi) { + fatal("Invalid CastLL, idx: %u, val: " JLONG_FORMAT ", lo: " JLONG_FORMAT ", hi: " JLONG_FORMAT, idx, val, lo, hi); +} + +void C2_MacroAssembler::verify_long_in_range(uint idx, const TypeLong* t, Register rval, Register rtmp) { + assert(!t->empty() && !t->singleton(), "%s", Type::str(t)); + if (t == TypeLong::LONG) { + return; + } + BLOCK_COMMENT("verify_long_in_range {"); + Label L_success, L_failure; + + jlong lo = t->_lo; + jlong hi = t->_hi; + + if (lo != min_jlong && hi != max_jlong) { + subs(rtmp, rval, lo); + br(Assembler::LT, L_failure); + subs(rtmp, rval, hi); + br(Assembler::LE, L_success); + } else if (lo != min_jlong) { + subs(rtmp, rval, lo); + br(Assembler::GE, L_success); + } else if (hi != max_jlong) { + subs(rtmp, rval, hi); + br(Assembler::LE, L_success); + } else { + ShouldNotReachHere(); + } + + bind(L_failure); + movw(c_rarg0, idx); + mov(c_rarg1, rval); + mov(c_rarg2, lo); + mov(c_rarg3, hi); + reconstruct_frame_pointer(rtmp); + rt_call(CAST_FROM_FN_PTR(address, abort_verify_long_in_range), rtmp); + hlt(0); + + bind(L_success); + BLOCK_COMMENT("} verify_long_in_range"); +} + +void C2_MacroAssembler::reconstruct_frame_pointer(Register rtmp) { + const int framesize = Compile::current()->output()->frame_size_in_bytes(); + if (PreserveFramePointer) { + // frame pointer is valid +#ifdef ASSERT + // Verify frame pointer value in rfp. + add(rtmp, sp, framesize - 2 * wordSize); + Label L_success; + cmp(rfp, rtmp); + br(Assembler::EQ, L_success); + stop("frame pointer mismatch"); + bind(L_success); +#endif // ASSERT + } else { + add(rfp, sp, framesize - 2 * wordSize); + } +} diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index e0eaa0b76e6..70e4265c7cc 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -188,4 +188,9 @@ void vector_signum_sve(FloatRegister dst, FloatRegister src, FloatRegister zero, FloatRegister one, FloatRegister vtmp, PRegister pgtmp, SIMD_RegVariant T); + void verify_int_in_range(uint idx, const TypeInt* t, Register val, Register tmp); + void verify_long_in_range(uint idx, const TypeLong* t, Register val, Register tmp); + + void reconstruct_frame_pointer(Register rtmp); + #endif // CPU_AARCH64_C2_MACROASSEMBLER_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp index 0c2d9a32c8c..3874c8cd54e 100644 --- a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp @@ -70,7 +70,7 @@ static char* reserve_at_eor_compatible_address(size_t size, bool aslr) { const uint64_t immediate = ((uint64_t)immediates[index]) << 32; assert(immediate > 0 && Assembler::operand_valid_for_logical_immediate(/*is32*/false, immediate), "Invalid immediate %d " UINT64_FORMAT, index, immediate); - result = os::attempt_reserve_memory_at((char*)immediate, size, false); + result = os::attempt_reserve_memory_at((char*)immediate, size, mtNone); if (result == nullptr) { log_trace(metaspace, map)("Failed to attach at " UINT64_FORMAT_X, immediate); } @@ -114,7 +114,7 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size if (result == nullptr) { constexpr size_t alignment = nth_bit(32); log_debug(metaspace, map)("Trying to reserve at a 32-bit-aligned address"); - result = os::reserve_memory_aligned(size, alignment, false); + result = os::reserve_memory_aligned(size, alignment, mtNone); } return result; diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index b07fa2fa9df..7ffba17bab3 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -828,7 +828,6 @@ void JavaFrameAnchor::make_walkable() { // already walkable? if (walkable()) return; vmassert(last_Java_sp() != nullptr, "not called from Java code?"); - vmassert(last_Java_pc() == nullptr, "already walkable"); _last_Java_pc = (address)_last_Java_sp[-1]; vmassert(walkable(), "something went wrong"); } diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index d22442db0d7..47ae93a4932 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -35,6 +35,53 @@ // Inline functions for AArch64 frames: +#if INCLUDE_JFR + +// Static helper routines + +inline address frame::interpreter_bcp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (fp[frame::interpreter_frame_bcp_offset]); +} + +inline address frame::interpreter_return_address(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (fp[frame::return_addr_offset]); +} + +inline intptr_t* frame::interpreter_sender_sp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(fp[frame::interpreter_frame_sender_sp_offset]); +} + +inline bool frame::is_interpreter_frame_setup_at(const intptr_t* fp, const void* sp) { + assert(fp != nullptr, "invariant"); + assert(sp != nullptr, "invariant"); + return sp <= fp + frame::interpreter_frame_initial_sp_offset; +} + +inline intptr_t* frame::sender_sp(intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return fp + frame::sender_sp_offset; +} + +inline intptr_t* frame::link(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(fp[frame::link_offset]); +} + +inline address frame::return_address(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast
          (sp[-1]); +} + +inline intptr_t* frame::fp(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast(sp[-2]); +} + +#endif // INCLUDE_JFR + // Constructors: inline frame::frame() { diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp index e33ef47cf3c..e4db8a9ab1f 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp @@ -27,9 +27,9 @@ #include "c1/c1_MacroAssembler.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" -#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #define __ masm->masm()-> diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index ac22b43faaf..a2b3f44c68b 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -23,6 +23,8 @@ * */ +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" @@ -30,10 +32,8 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" -#include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/interpreter.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" #ifdef COMPILER1 diff --git a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp index 20e37528c04..7008615ed43 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp @@ -21,8 +21,8 @@ * questions. */ -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zAddress.hpp" #include "gc/z/zBarrierSetAssembler.hpp" #include "gc/z/zGlobals.hpp" diff --git a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp index faf635dc332..948ba97aa22 100644 --- a/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globalDefinitions_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -46,7 +46,7 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define DEFAULT_CACHE_LINE_SIZE 64 // The default padding size for data structures to avoid false sharing. -#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE +#define DEFAULT_PADDING_SIZE (2*DEFAULT_CACHE_LINE_SIZE) // According to the ARMv8 ARM, "Concurrent modification and execution // of instructions can lead to the resulting instruction performing diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index 800e7718921..b316103d656 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2019, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -83,8 +83,6 @@ define_pd_global(intx, InlineSmallCode, 1000); range, \ constraint) \ \ - product(bool, NearCpool, true, \ - "constant pool is close to instructions") \ product(bool, UseCRC32, false, \ "Use CRC32 instructions for CRC32 computation") \ product(bool, UseCryptoPmullForCRC32, false, \ @@ -97,6 +95,8 @@ define_pd_global(intx, InlineSmallCode, 1000); "Use simplest and shortest implementation for array equals") \ product(bool, UseSIMDForBigIntegerShiftIntrinsics, true, \ "Use SIMD instructions for left/right shift of BigInteger") \ + product(bool, UseSIMDForSHA3Intrinsic, true, \ + "Use SIMD SHA3 instructions for SHA3 intrinsic") \ product(bool, AvoidUnalignedAccesses, false, \ "Avoid generating unaligned memory accesses") \ product(bool, UseLSE, false, \ diff --git a/src/hotspot/cpu/aarch64/icache_aarch64.cpp b/src/hotspot/cpu/aarch64/icache_aarch64.cpp index 311f3a7de1f..a942406f45e 100644 --- a/src/hotspot/cpu/aarch64/icache_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/icache_aarch64.cpp @@ -31,4 +31,4 @@ void ICacheStubGenerator::generate_icache_flush( *flush_icache_stub = nullptr; } -void ICache::initialize() {} +void ICache::initialize(int phase) {} diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index d5ba85da989..276fdd013db 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -458,9 +458,10 @@ void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { // remove activation // -// Apply stack watermark barrier. // Unlock the receiver if this is a synchronized method. // Unlock any Java monitors from synchronized blocks. +// Apply stack watermark barrier. +// Notify JVMTI. // Remove the activation from the stack. // // If there are locked Java monitors @@ -470,30 +471,14 @@ void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { // installs IllegalMonitorStateException // Else // no error processing -void InterpreterMacroAssembler::remove_activation( - TosState state, - bool throw_monitor_exception, - bool install_monitor_exception, - bool notify_jvmdi) { +void InterpreterMacroAssembler::remove_activation(TosState state, + bool throw_monitor_exception, + bool install_monitor_exception, + bool notify_jvmdi) { // Note: Registers r3 xmm0 may be in use for the // result check if synchronized method Label unlocked, unlock, no_unlock; - // The below poll is for the stack watermark barrier. It allows fixing up frames lazily, - // that would normally not be safe to use. Such bad returns into unsafe territory of - // the stack, will call InterpreterRuntime::at_unwind. - Label slow_path; - Label fast_path; - safepoint_poll(slow_path, true /* at_return */, false /* acquire */, false /* in_nmethod */); - br(Assembler::AL, fast_path); - bind(slow_path); - push(state); - set_last_Java_frame(esp, rfp, (address)pc(), rscratch1); - super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), rthread); - reset_last_Java_frame(true); - pop(state); - bind(fast_path); - // get the value of _do_not_unlock_if_synchronized into r3 const Address do_not_unlock_if_synchronized(rthread, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); @@ -611,7 +596,24 @@ void InterpreterMacroAssembler::remove_activation( bind(no_unlock); - // jvmti support + JFR_ONLY(enter_jfr_critical_section();) + + // The below poll is for the stack watermark barrier. It allows fixing up frames lazily, + // that would normally not be safe to use. Such bad returns into unsafe territory of + // the stack, will call InterpreterRuntime::at_unwind. + Label slow_path; + Label fast_path; + safepoint_poll(slow_path, true /* at_return */, false /* acquire */, false /* in_nmethod */); + br(Assembler::AL, fast_path); + bind(slow_path); + push(state); + set_last_Java_frame(esp, rfp, pc(), rscratch1); + super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), rthread); + reset_last_Java_frame(true); + pop(state); + bind(fast_path); + + // JVMTI support. Make sure the safepoint poll test is issued prior. if (notify_jvmdi) { notify_method_exit(state, NotifyJVMTI); // preserve TOSCA } else { @@ -638,6 +640,8 @@ void InterpreterMacroAssembler::remove_activation( cmp(rscratch2, rscratch1); br(Assembler::LS, no_reserved_zone_enabling); + JFR_ONLY(leave_jfr_critical_section();) + call_VM_leaf( CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread); call_VM(noreg, CAST_FROM_FN_PTR(address, @@ -647,10 +651,14 @@ void InterpreterMacroAssembler::remove_activation( bind(no_reserved_zone_enabling); } - // restore sender esp - mov(esp, rscratch2); // remove frame anchor leave(); + + JFR_ONLY(leave_jfr_critical_section();) + + // restore sender esp + mov(esp, rscratch2); + // If we're returning to interpreted code we will shortly be // adjusting SP to allow some space for ESP. If we're returning to // compiled code the saved sender SP was saved in sender_sp, so this @@ -658,6 +666,19 @@ void InterpreterMacroAssembler::remove_activation( andr(sp, esp, -16); } +#if INCLUDE_JFR +void InterpreterMacroAssembler::enter_jfr_critical_section() { + const Address sampling_critical_section(rthread, in_bytes(SAMPLING_CRITICAL_SECTION_OFFSET_JFR)); + mov(rscratch1, true); + strb(rscratch1, sampling_critical_section); +} + +void InterpreterMacroAssembler::leave_jfr_critical_section() { + const Address sampling_critical_section(rthread, in_bytes(SAMPLING_CRITICAL_SECTION_OFFSET_JFR)); + strb(zr, sampling_critical_section); +} +#endif // INCLUDE_JFR + // Lock object // // Args: @@ -693,17 +714,18 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) // Load object pointer into obj_reg %c_rarg3 ldr(obj_reg, Address(lock_reg, obj_offset)); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, obj_reg); - ldrb(tmp, Address(tmp, Klass::misc_flags_offset())); - tst(tmp, KlassFlags::_misc_is_value_based_class); - br(Assembler::NE, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); b(done); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, obj_reg); + ldrb(tmp, Address(tmp, Klass::misc_flags_offset())); + tst(tmp, KlassFlags::_misc_is_value_based_class); + br(Assembler::NE, slow_case); + } + // Load (object->mark() | 1) into swap_reg ldr(rscratch1, Address(obj_reg, oopDesc::mark_offset_in_bytes())); orr(swap_reg, rscratch1, 1); @@ -904,60 +926,26 @@ void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - int constant, - bool decrement) { - increment_mdp_data_at(mdp_in, noreg, constant, decrement); + int constant) { + increment_mdp_data_at(mdp_in, noreg, constant); } void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - Register reg, - int constant, - bool decrement) { + Register index, + int constant) { assert(ProfileInterpreter, "must be profiling interpreter"); - // %%% this does 64bit counters at best it is wasting space - // at worst it is a rare bug when counters overflow - assert_different_registers(rscratch2, rscratch1, mdp_in, reg); + assert_different_registers(rscratch2, rscratch1, mdp_in, index); Address addr1(mdp_in, constant); - Address addr2(rscratch2, reg, Address::lsl(0)); + Address addr2(rscratch2, index, Address::lsl(0)); Address &addr = addr1; - if (reg != noreg) { + if (index != noreg) { lea(rscratch2, addr1); addr = addr2; } - if (decrement) { - // Decrement the register. Set condition codes. - // Intel does this - // addptr(data, (int32_t) -DataLayout::counter_increment); - // If the decrement causes the counter to overflow, stay negative - // Label L; - // jcc(Assembler::negative, L); - // addptr(data, (int32_t) DataLayout::counter_increment); - // so we do this - ldr(rscratch1, addr); - subs(rscratch1, rscratch1, (unsigned)DataLayout::counter_increment); - Label L; - br(Assembler::LO, L); // skip store if counter underflow - str(rscratch1, addr); - bind(L); - } else { - assert(DataLayout::counter_increment == 1, - "flow-free idiom only works with 1"); - // Intel does this - // Increment the register. Set carry flag. - // addptr(data, DataLayout::counter_increment); - // If the increment causes the counter to overflow, pull back by 1. - // sbbptr(data, (int32_t)0); - // so we do this - ldr(rscratch1, addr); - adds(rscratch1, rscratch1, DataLayout::counter_increment); - Label L; - br(Assembler::CS, L); // skip store if counter overflow - str(rscratch1, addr); - bind(L); - } + increment(addr, DataLayout::counter_increment); } void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp index 059d79c3cb9..447d4f8244e 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -247,11 +247,8 @@ class InterpreterMacroAssembler: public MacroAssembler { void verify_method_data_pointer(); void set_mdp_data_at(Register mdp_in, int constant, Register value); - void increment_mdp_data_at(Address data, bool decrement = false); - void increment_mdp_data_at(Register mdp_in, int constant, - bool decrement = false); - void increment_mdp_data_at(Register mdp_in, Register reg, int constant, - bool decrement = false); + void increment_mdp_data_at(Register mdp_in, int constant); + void increment_mdp_data_at(Register mdp_in, Register index, int constant); void increment_mask_and_jump(Address counter_addr, int increment, Address mask, Register scratch, Register scratch2, @@ -310,6 +307,9 @@ class InterpreterMacroAssembler: public MacroAssembler { void notify_method_entry(); void notify_method_exit(TosState state, NotifyMethodExitMode mode); + JFR_ONLY(void enter_jfr_critical_section();) + JFR_ONLY(void leave_jfr_critical_section();) + virtual void _call_Unimplemented(address call_site) { save_bcp(); set_last_Java_frame(esp, rfp, (address) pc(), rscratch1); diff --git a/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp b/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp index 3015206dadc..071dd2c4179 100644 --- a/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/jvmciCodeInstaller_aarch64.cpp @@ -180,6 +180,7 @@ bool CodeInstaller::pd_relocate(address pc, jint mark) { case POLL_RETURN_FAR: _instructions->relocate(pc, relocInfo::poll_return_type); return true; +#if INCLUDE_ZGC case Z_BARRIER_RELOCATION_FORMAT_LOAD_GOOD_BEFORE_TB_X: _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatLoadGoodBeforeTbX); return true; @@ -192,6 +193,7 @@ bool CodeInstaller::pd_relocate(address pc, jint mark) { case Z_BARRIER_RELOCATION_FORMAT_STORE_BAD_BEFORE_MOV: _instructions->relocate(pc, barrier_Relocation::spec(), ZBarrierRelocationFormatStoreBadBeforeMov); return true; +#endif } return false; diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 1e226c70420..a277a689280 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -675,6 +675,9 @@ void MacroAssembler::set_last_Java_frame(Register last_java_sp, } static inline bool target_needs_far_branch(address addr) { + if (AOTCodeCache::is_on_for_dump()) { + return true; + } // codecache size <= 128M if (!MacroAssembler::far_branches()) { return false; @@ -859,6 +862,9 @@ void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, in // Check the entry target is always reachable from any branch. static bool is_always_within_branch_range(Address entry) { + if (AOTCodeCache::is_on_for_dump()) { + return false; + } const address target = entry.target(); if (!CodeCache::contains(target)) { @@ -1003,9 +1009,6 @@ void MacroAssembler::c2bool(Register x) { address MacroAssembler::ic_call(address entry, jint method_index) { RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); - // address const_ptr = long_constant((jlong)Universe::non_oop_word()); - // uintptr_t offset; - // ldr_constant(rscratch2, const_ptr); movptr(rscratch2, (intptr_t)Universe::non_oop_word()); return trampoline_call(Address(entry, rh)); } @@ -2041,7 +2044,7 @@ void MacroAssembler::clinit_barrier(Register klass, Register scratch, Label* L_f // Fast path check: class is fully initialized lea(scratch, Address(klass, InstanceKlass::init_state_offset())); ldarb(scratch, scratch); - subs(zr, scratch, InstanceKlass::fully_initialized); + cmp(scratch, InstanceKlass::fully_initialized); br(Assembler::EQ, *L_fast_path); // Fast path check: current thread is initializer thread @@ -2157,7 +2160,7 @@ void MacroAssembler::call_VM_leaf_base(address entry_point, stp(rscratch1, rmethod, Address(pre(sp, -2 * wordSize))); - mov(rscratch1, entry_point); + mov(rscratch1, RuntimeAddress(entry_point)); blr(rscratch1); if (retaddr) bind(*retaddr); @@ -3234,9 +3237,13 @@ void MacroAssembler::resolve_global_jobject(Register value, Register tmp1, Regis } void MacroAssembler::stop(const char* msg) { - BLOCK_COMMENT(msg); + // Skip AOT caching C strings in scratch buffer. + const char* str = (code_section()->scratch_emit()) ? msg : AOTCodeCache::add_C_string(msg); + BLOCK_COMMENT(str); + // load msg into r0 so we can access it from the signal handler + // ExternalAddress enables saving and restoring via the code cache + lea(c_rarg0, ExternalAddress((address) str)); dcps1(0xdeae); - emit_int64((uintptr_t)msg); } void MacroAssembler::unimplemented(const char* what) { @@ -3270,7 +3277,7 @@ void MacroAssembler::wrap_add_sub_imm_insn(Register Rd, Register Rn, uint64_t im if (fits) { (this->*insn1)(Rd, Rn, imm); } else { - if (uabs(imm) < (1 << 24)) { + if (g_uabs(imm) < (1 << 24)) { (this->*insn1)(Rd, Rn, imm & -(1 << 12)); (this->*insn1)(Rd, Rd, imm & ((1 << 12)-1)); } else { @@ -5333,7 +5340,41 @@ bool MacroAssembler::set_klass_decode_mode(address base, int shift, const size_t return _klass_decode_mode != KlassDecodeNone; } +static Register pick_different_tmp(Register dst, Register src) { + auto tmps = RegSet::of(r0, r1, r2) - RegSet::of(src, dst); + return *tmps.begin(); +} + +void MacroAssembler::encode_klass_not_null_for_aot(Register dst, Register src) { + // we have to load the klass base from the AOT constants area but + // not the shift because it is not allowed to change + int shift = CompressedKlassPointers::shift(); + assert(shift >= 0 && shift <= CompressedKlassPointers::max_shift(), "unexpected compressed klass shift!"); + if (dst != src) { + // we can load the base into dst, subtract it formthe src and shift down + lea(dst, ExternalAddress(CompressedKlassPointers::base_addr())); + ldr(dst, dst); + sub(dst, src, dst); + lsr(dst, dst, shift); + } else { + // we need an extra register in order to load the coop base + Register tmp = pick_different_tmp(dst, src); + RegSet regs = RegSet::of(tmp); + push(regs, sp); + lea(tmp, ExternalAddress(CompressedKlassPointers::base_addr())); + ldr(tmp, tmp); + sub(dst, src, tmp); + lsr(dst, dst, shift); + pop(regs, sp); + } +} + void MacroAssembler::encode_klass_not_null(Register dst, Register src) { + if (AOTCodeCache::is_on_for_dump()) { + encode_klass_not_null_for_aot(dst, src); + return; + } + switch (klass_decode_mode()) { case KlassDecodeZero: if (CompressedKlassPointers::shift() != 0) { @@ -5370,9 +5411,36 @@ void MacroAssembler::encode_klass_not_null(Register r) { encode_klass_not_null(r, r); } +void MacroAssembler::decode_klass_not_null_for_aot(Register dst, Register src) { + // we have to load the klass base from the AOT constants area but + // not the shift because it is not allowed to change + int shift = CompressedKlassPointers::shift(); + assert(shift >= 0 && shift <= CompressedKlassPointers::max_shift(), "unexpected compressed klass shift!"); + if (dst != src) { + // we can load the base into dst then add the offset with a suitable shift + lea(dst, ExternalAddress(CompressedKlassPointers::base_addr())); + ldr(dst, dst); + add(dst, dst, src, LSL, shift); + } else { + // we need an extra register in order to load the coop base + Register tmp = pick_different_tmp(dst, src); + RegSet regs = RegSet::of(tmp); + push(regs, sp); + lea(tmp, ExternalAddress(CompressedKlassPointers::base_addr())); + ldr(tmp, tmp); + add(dst, tmp, src, LSL, shift); + pop(regs, sp); + } +} + void MacroAssembler::decode_klass_not_null(Register dst, Register src) { assert (UseCompressedClassPointers, "should only be used for compressed headers"); + if (AOTCodeCache::is_on_for_dump()) { + decode_klass_not_null_for_aot(dst, src); + return; + } + switch (klass_decode_mode()) { case KlassDecodeZero: if (CompressedKlassPointers::shift() != 0) { @@ -5520,9 +5588,8 @@ void MacroAssembler::movoop(Register dst, jobject obj) { mov(dst, Address((address)obj, rspec)); } else { address dummy = address(uintptr_t(pc()) & -wordSize); // A nearby aligned address - ldr_constant(dst, Address(dummy, rspec)); + ldr(dst, Address(dummy, rspec)); } - } // Move a metadata address into a register. @@ -6648,7 +6715,7 @@ void MacroAssembler::get_thread(Register dst) { protect_return_address(); push(saved_regs, sp); - mov(lr, CAST_FROM_FN_PTR(address, JavaThread::aarch64_get_thread_helper)); + mov(lr, ExternalAddress(CAST_FROM_FN_PTR(address, JavaThread::aarch64_get_thread_helper))); blr(lr); if (dst != c_rarg0) { mov(dst, c_rarg0); @@ -7034,10 +7101,17 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe ldr(mark, Address(obj, oopDesc::mark_offset_in_bytes())); if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. str(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())))); } + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(t1, obj); + ldrb(t1, Address(t1, Klass::misc_flags_offset())); + tst(t1, KlassFlags::_misc_is_value_based_class); + br(Assembler::NE, slow); + } + // Check if the lock-stack is full. ldrw(top, Address(rthread, JavaThread::lock_stack_top_offset())); cmpw(top, (unsigned)LockStack::end_offset()); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 11d1985e50b..d77bc92875f 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2024, 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 "code/aotCodeCache.hpp" #include "code/vmreg.hpp" #include "metaprogramming/enableIf.hpp" #include "oops/compressedOops.hpp" @@ -322,6 +323,27 @@ class MacroAssembler: public Assembler { extr(Rd, Rn, Rn, imm); } + inline void rolw(Register Rd, Register Rn, unsigned imm) { + extrw(Rd, Rn, Rn, (32 - imm)); + } + + inline void rol(Register Rd, Register Rn, unsigned imm) { + extr(Rd, Rn, Rn, (64 - imm)); + } + + using Assembler::rax1; + using Assembler::eor3; + + inline void rax1(Register Rd, Register Rn, Register Rm) { + eor(Rd, Rn, Rm, ROR, 63); // Rd = Rn ^ rol(Rm, 1) + } + + inline void eor3(Register Rd, Register Rn, Register Rm, Register Rk) { + assert(Rd != Rn, "Use tmp register"); + eor(Rd, Rm, Rk); + eor(Rd, Rd, Rn); + } + inline void sxtbw(Register Rd, Register Rn) { sbfmw(Rd, Rn, 0, 7); } @@ -934,6 +956,8 @@ class MacroAssembler: public Assembler { void set_narrow_oop(Register dst, jobject obj); + void decode_klass_not_null_for_aot(Register dst, Register src); + void encode_klass_not_null_for_aot(Register dst, Register src); void encode_klass_not_null(Register r); void decode_klass_not_null(Register r); void encode_klass_not_null(Register dst, Register src); @@ -1315,6 +1339,10 @@ class MacroAssembler: public Assembler { // Check if branches to the non nmethod section require a far jump static bool codestub_branch_needs_far_jump() { + if (AOTCodeCache::is_on_for_dump()) { + // To calculate far_codestub_branch_size correctly. + return true; + } return CodeCache::max_distance_to_non_nmethod() > branch_range; } @@ -1472,16 +1500,6 @@ class MacroAssembler: public Assembler { public: - void ldr_constant(Register dest, const Address &const_addr) { - if (NearCpool) { - ldr(dest, const_addr); - } else { - uint64_t offset; - adrp(dest, InternalAddress(const_addr.target()), offset); - ldr(dest, Address(dest, offset)); - } - } - address read_polling_page(Register r, relocInfo::relocType rtype); void get_polling_page(Register dest, relocInfo::relocType rtype); @@ -1611,11 +1629,15 @@ class MacroAssembler: public Assembler { void aes_round(FloatRegister input, FloatRegister subkey); // ChaCha20 functions support block - void cc20_quarter_round(FloatRegister aVec, FloatRegister bVec, - FloatRegister cVec, FloatRegister dVec, FloatRegister scratch, - FloatRegister tbl); - void cc20_shift_lane_org(FloatRegister bVec, FloatRegister cVec, - FloatRegister dVec, bool colToDiag); + void cc20_qr_add4(FloatRegister (&addFirst)[4], + FloatRegister (&addSecond)[4]); + void cc20_qr_xor4(FloatRegister (&firstElem)[4], + FloatRegister (&secondElem)[4], FloatRegister (&result)[4]); + void cc20_qr_lrot4(FloatRegister (&sourceReg)[4], + FloatRegister (&destReg)[4], int bits, FloatRegister table); + void cc20_set_qr_registers(FloatRegister (&vectorSet)[4], + const FloatRegister (&stateVectors)[16], int idx1, int idx2, + int idx3, int idx4); // Place an ISB after code may have been modified due to a safepoint. void safepoint_isb(); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_chacha.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64_chacha.cpp index 1f7bb8f46f6..083e81af5d9 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64_chacha.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64_chacha.cpp @@ -28,60 +28,119 @@ #include "runtime/stubRoutines.hpp" /** - * Perform the quarter round calculations on values contained within - * four SIMD registers. + * Perform the vectorized add for a group of 4 quarter round operations. + * In the ChaCha20 quarter round, there are two add ops: a += b and c += d. + * Each parameter is a set of 4 registers representing the 4 registers + * for the each addend in the add operation for each of the quarter rounds. + * (e.g. for "a" it would consist of v0/v1/v2/v3). The result of the add + * is placed into the vectors in the "addFirst" array. * - * @param aVec the SIMD register containing only the "a" values - * @param bVec the SIMD register containing only the "b" values - * @param cVec the SIMD register containing only the "c" values - * @param dVec the SIMD register containing only the "d" values - * @param scratch scratch SIMD register used for 12 and 7 bit left rotations - * @param table the SIMD register used as a table for 8 bit left rotations + * @param addFirst array of SIMD registers representing the first addend. + * @param addSecond array of SIMD registers representing the second addend. */ -void MacroAssembler::cc20_quarter_round(FloatRegister aVec, FloatRegister bVec, - FloatRegister cVec, FloatRegister dVec, FloatRegister scratch, - FloatRegister table) { +void MacroAssembler::cc20_qr_add4(FloatRegister (&addFirst)[4], + FloatRegister (&addSecond)[4]) { + for (int i = 0; i < 4; i++) { + addv(addFirst[i], T4S, addFirst[i], addSecond[i]); + } +} + + +/** + * Perform the vectorized XOR for a group of 4 quarter round operations. + * In the ChaCha20 quarter round, there are two XOR ops: d ^= a and b ^= c + * Each parameter is a set of 4 registers representing the 4 registers + * for the each element in the xor operation for each of the quarter rounds. + * (e.g. for "a" it would consist of v0/v1/v2/v3) + * Note: because the b ^= c ops precede a non-byte-aligned left-rotation, + * there is a third parameter which can take a set of scratch registers + * for the result, which facilitates doing the subsequent operations for + * the left rotation. + * + * @param firstElem array of SIMD registers representing the first element. + * @param secondElem array of SIMD registers representing the second element. + * @param result array of SIMD registers representing the destination. + * May be the same as firstElem or secondElem, or a separate array. + */ +void MacroAssembler::cc20_qr_xor4(FloatRegister (&firstElem)[4], + FloatRegister (&secondElem)[4], FloatRegister (&result)[4]) { + for (int i = 0; i < 4; i++) { + eor(result[i], T16B, firstElem[i], secondElem[i]); + } +} + +/** + * Perform the vectorized left-rotation on 32-bit lanes for a group of + * 4 quarter round operations. + * Each parameter is a set of 4 registers representing the 4 registers + * for the each element in the source and destination for each of the quarter + * rounds (e.g. for "d" it would consist of v12/v13/v14/v15 on columns and + * v15/v12/v13/v14 on diagonal alignments). + * + * @param sourceReg array of SIMD registers representing the source + * @param destReg array of SIMD registers representing the destination + * @param bits the distance of the rotation in bits, must be 16/12/8/7 per + * the ChaCha20 specification. + */ +void MacroAssembler::cc20_qr_lrot4(FloatRegister (&sourceReg)[4], + FloatRegister (&destReg)[4], int bits, FloatRegister table) { + switch (bits) { + case 16: // reg <<<= 16, in-place swap of half-words + for (int i = 0; i < 4; i++) { + rev32(destReg[i], T8H, sourceReg[i]); + } + break; - // a += b, d ^= a, d <<<= 16 - addv(aVec, T4S, aVec, bVec); - eor(dVec, T16B, dVec, aVec); - rev32(dVec, T8H, dVec); + case 7: // reg <<<= (12 || 7) + case 12: // r-shift src -> dest, l-shift src & ins to dest + for (int i = 0; i < 4; i++) { + ushr(destReg[i], T4S, sourceReg[i], 32 - bits); + } - // c += d, b ^= c, b <<<= 12 - addv(cVec, T4S, cVec, dVec); - eor(scratch, T16B, bVec, cVec); - ushr(bVec, T4S, scratch, 20); - sli(bVec, T4S, scratch, 12); + for (int i = 0; i < 4; i++) { + sli(destReg[i], T4S, sourceReg[i], bits); + } + break; - // a += b, d ^= a, d <<<= 8 - addv(aVec, T4S, aVec, bVec); - eor(dVec, T16B, dVec, aVec); - tbl(dVec, T16B, dVec, 1, table); + case 8: // reg <<<= 8, simulate left rotation with table reorg + for (int i = 0; i < 4; i++) { + tbl(destReg[i], T16B, sourceReg[i], 1, table); + } + break; - // c += d, b ^= c, b <<<= 7 - addv(cVec, T4S, cVec, dVec); - eor(scratch, T16B, bVec, cVec); - ushr(bVec, T4S, scratch, 25); - sli(bVec, T4S, scratch, 7); + default: + // The caller shouldn't be sending bit rotation values outside + // of the 16/12/8/7 as defined in the specification. + ShouldNotReachHere(); + } } /** - * Shift the b, c, and d vectors between columnar and diagonal representations. - * Note that the "a" vector does not shift. + * Set the FloatRegisters for a 4-vector register set. These will be used + * during various quarter round transformations (adds, xors and left-rotations). + * This method itself does not result in the output of any assembly + * instructions. It just organizes the vectors so they can be in columnar or + * diagonal alignments. * - * @param bVec the SIMD register containing only the "b" values - * @param cVec the SIMD register containing only the "c" values - * @param dVec the SIMD register containing only the "d" values - * @param colToDiag true if moving columnar to diagonal, false if - * moving diagonal back to columnar. + * @param vectorSet a 4-vector array to be altered into a new alignment + * @param stateVectors the 16-vector array that represents the current + * working state. The indices of this array match up with the + * organization of the ChaCha20 state per RFC 7539 (e.g. stateVectors[12] + * would contain the vector that holds the 32-bit counter, etc.) + * @param idx1 the index of the stateVectors array to be assigned to the + * first vectorSet element. + * @param idx2 the index of the stateVectors array to be assigned to the + * second vectorSet element. + * @param idx3 the index of the stateVectors array to be assigned to the + * third vectorSet element. + * @param idx4 the index of the stateVectors array to be assigned to the + * fourth vectorSet element. */ -void MacroAssembler::cc20_shift_lane_org(FloatRegister bVec, FloatRegister cVec, - FloatRegister dVec, bool colToDiag) { - int bShift = colToDiag ? 4 : 12; - int cShift = 8; - int dShift = colToDiag ? 12 : 4; - - ext(bVec, T16B, bVec, bVec, bShift); - ext(cVec, T16B, cVec, cVec, cShift); - ext(dVec, T16B, dVec, dVec, dShift); +void MacroAssembler::cc20_set_qr_registers(FloatRegister (&vectorSet)[4], + const FloatRegister (&stateVectors)[16], int idx1, int idx2, + int idx3, int idx4) { + vectorSet[0] = stateVectors[idx1]; + vectorSet[1] = stateVectors[idx2]; + vectorSet[2] = stateVectors[idx3]; + vectorSet[3] = stateVectors[idx4]; } diff --git a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp index a6cd0557758..0fbc2ef141e 100644 --- a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,4 +200,8 @@ return false; } + // Is FEAT_FP16 supported for this CPU? + static bool is_feat_fp16_supported() { + return (VM_Version::supports_fphp() && VM_Version::supports_asimdhp()); + } #endif // CPU_AARCH64_MATCHER_AARCH64_HPP diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp index 588b8898d2d..cdf67e3423f 100644 --- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/methodHandles_aarch64.cpp @@ -93,14 +93,60 @@ void MethodHandles::verify_klass(MacroAssembler* _masm, void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) { } +void MethodHandles::verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) { + BLOCK_COMMENT("verify_method {"); + __ verify_method_ptr(method); + if (VerifyMethodHandles) { + Label L_ok; + assert_different_registers(method, rscratch1, rscratch2); + const Register method_holder = rscratch1; + __ load_method_holder(method_holder, method); + + switch (iid) { + case vmIntrinsicID::_invokeBasic: + // Require compiled LambdaForm class to be fully initialized. + __ lea(rscratch2, Address(method_holder, InstanceKlass::init_state_offset())); + __ ldarb(rscratch2, rscratch2); + __ cmp(rscratch2, InstanceKlass::fully_initialized); + __ br(Assembler::EQ, L_ok); + break; + + case vmIntrinsicID::_linkToStatic: + __ clinit_barrier(method_holder, rscratch2, &L_ok); + break; + + case vmIntrinsicID::_linkToVirtual: + case vmIntrinsicID::_linkToSpecial: + case vmIntrinsicID::_linkToInterface: + // Class initialization check is too strong here. Just ensure that class initialization has been initiated. + __ lea(rscratch2, Address(method_holder, InstanceKlass::init_state_offset())); + __ ldarb(rscratch2, rscratch2); + __ cmp(rscratch2, InstanceKlass::being_initialized); + __ br(Assembler::GE, L_ok); + + // init_state check failed, but it may be an abstract interface method + __ ldrh(rscratch2, Address(method, Method::access_flags_offset())); + __ tbnz(rscratch2, exact_log2(JVM_ACC_ABSTRACT), L_ok); + break; + + default: + fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid)); + } + + // Method holder init state check failed for a concrete method. + __ stop("Method holder klass is not initialized"); + __ bind(L_ok); + } + BLOCK_COMMENT("} verify_method"); +} #endif //ASSERT void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, - bool for_compiler_entry) { + bool for_compiler_entry, vmIntrinsics::ID iid) { assert(method == rmethod, "interpreter calling convention"); Label L_no_such_method; __ cbz(rmethod, L_no_such_method); - __ verify_method_ptr(method); + verify_method(_masm, method, iid); if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { Label run_compiled_code; @@ -160,7 +206,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, __ BIND(L); } - jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry); + jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry, vmIntrinsics::_invokeBasic); BLOCK_COMMENT("} jump_to_lambda_form"); } @@ -447,8 +493,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, // After figuring out which concrete method to call, jump into it. // Note that this works in the interpreter with no data motion. // But the compiled version will require that r2_recv be shifted out. - __ verify_method_ptr(rmethod); - jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry); + jump_from_method_handle(_masm, rmethod, temp1, for_compiler_entry, iid); if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); diff --git a/src/hotspot/cpu/aarch64/methodHandles_aarch64.hpp b/src/hotspot/cpu/aarch64/methodHandles_aarch64.hpp index bd36f3e84c2..e82f4d6237e 100644 --- a/src/hotspot/cpu/aarch64/methodHandles_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/methodHandles_aarch64.hpp @@ -39,6 +39,8 @@ enum /* platform_dependent_constants */ { Register obj, vmClassID klass_id, const char* error_message = "wrong klass") NOT_DEBUG_RETURN; + static void verify_method(MacroAssembler* _masm, Register method, vmIntrinsics::ID iid) NOT_DEBUG_RETURN; + static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) { verify_klass(_masm, mh_reg, VM_CLASS_ID(java_lang_invoke_MethodHandle), "reference is a MH"); @@ -49,7 +51,7 @@ enum /* platform_dependent_constants */ { // Similar to InterpreterMacroAssembler::jump_from_interpreted. // Takes care of special dispatch from single stepping too. static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, - bool for_compiler_entry); + bool for_compiler_entry, vmIntrinsics::ID iid); static void jump_to_lambda_form(MacroAssembler* _masm, Register recv, Register method_temp, diff --git a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp index 83e43c3ebd2..3fcb0e70b57 100644 --- a/src/hotspot/cpu/aarch64/runtime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/runtime_aarch64.cpp @@ -26,6 +26,7 @@ #ifdef COMPILER2 #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/aotCodeCache.hpp" #include "code/vmreg.hpp" #include "interpreter/interpreter.hpp" #include "opto/runtime.hpp" @@ -60,11 +61,19 @@ class SimpleRuntimeFrame { //------------------------------generate_uncommon_trap_blob-------------------- UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { + const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::C2Blob, (uint)OptoStubId::uncommon_trap_id, name); + if (blob != nullptr) { + return blob->as_uncommon_trap_blob(); + } + // Allocate space for the code ResourceMark rm; // Setup code generation tools - const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); @@ -243,8 +252,10 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Make sure all code is generated masm->flush(); - return UncommonTrapBlob::create(&buffer, oop_maps, - SimpleRuntimeFrame::framesize >> 1); + UncommonTrapBlob *ut_blob = UncommonTrapBlob::create(&buffer, oop_maps, + SimpleRuntimeFrame::framesize >> 1); + AOTCodeCache::store_code_blob(*ut_blob, AOTCodeEntry::C2Blob, (uint)OptoStubId::uncommon_trap_id, name); + return ut_blob; } //------------------------------generate_exception_blob--------------------------- @@ -280,11 +291,19 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::C2Blob, (uint)OptoStubId::exception_id, name); + if (blob != nullptr) { + return blob->as_exception_blob(); + } + // Allocate space for the code ResourceMark rm; // Setup code generation tools - const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); // TODO check various assumptions made here @@ -378,7 +397,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { masm->flush(); // Set exception blob - return ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); + ExceptionBlob* ex_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); + AOTCodeCache::store_code_blob(*ex_blob, AOTCodeEntry::C2Blob, (uint)OptoStubId::exception_id, name); + return ex_blob; } #endif // COMPILER2 diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 967984b8821..51f18cb1bbe 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -26,6 +26,7 @@ #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/aotCodeCache.hpp" #include "code/codeCache.hpp" #include "code/compiledIC.hpp" #include "code/debugInfoRec.hpp" @@ -557,40 +558,6 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, // If this happens, control eventually transfers back to the compiled // caller, but with an uncorrected stack, causing delayed havoc. - if (VerifyAdapterCalls && - (Interpreter::code() != nullptr || StubRoutines::final_stubs_code() != nullptr)) { -#if 0 - // So, let's test for cascading c2i/i2c adapters right now. - // assert(Interpreter::contains($return_addr) || - // StubRoutines::contains($return_addr), - // "i2c adapter must return to an interpreter frame"); - __ block_comment("verify_i2c { "); - Label L_ok; - if (Interpreter::code() != nullptr) { - range_check(masm, rax, r11, - Interpreter::code()->code_start(), Interpreter::code()->code_end(), - L_ok); - } - if (StubRoutines::initial_stubs_code() != nullptr) { - range_check(masm, rax, r11, - StubRoutines::initial_stubs_code()->code_begin(), - StubRoutines::initial_stubs_code()->code_end(), - L_ok); - } - if (StubRoutines::final_stubs_code() != nullptr) { - range_check(masm, rax, r11, - StubRoutines::final_stubs_code()->code_begin(), - StubRoutines::final_stubs_code()->code_end(), - L_ok); - } - const char* msg = "i2c adapter must return to an interpreter frame"; - __ block_comment(msg); - __ stop(msg); - __ bind(L_ok); - __ block_comment("} verify_i2ce "); -#endif - } - // Cut-out for having no stack args. int comp_words_on_stack = align_up(comp_args_on_stack*VMRegImpl::stack_slot_size, wordSize)>>LogBytesPerWord; if (comp_args_on_stack) { @@ -711,12 +678,12 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, } // --------------------------------------------------------------- -AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs, - AdapterFingerPrint* fingerprint) { +void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + AdapterHandlerEntry* handler) { address i2c_entry = __ pc(); gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); @@ -777,7 +744,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); - return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); + handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); + return; } static int c_calling_convention_priv(const BasicType *sig_bt, @@ -2017,6 +1985,23 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ leave(); + #if INCLUDE_JFR + // We need to do a poll test after unwind in case the sampler + // managed to sample the native frame after returning to Java. + Label L_return; + __ ldr(rscratch1, Address(rthread, JavaThread::polling_word_offset())); + address poll_test_pc = __ pc(); + __ relocate(relocInfo::poll_return_type); + __ tbz(rscratch1, log2i_exact(SafepointMechanism::poll_bit()), L_return); + assert(SharedRuntime::polling_page_return_handler_blob() != nullptr, + "polling page return stub not created yet"); + address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point(); + __ adr(rscratch1, InternalAddress(poll_test_pc)); + __ str(rscratch1, Address(rthread, JavaThread::saved_exception_pc_offset())); + __ far_jump(RuntimeAddress(stub)); + __ bind(L_return); +#endif // INCLUDE_JFR + // Any exception pending? __ ldr(rscratch1, Address(rthread, in_bytes(Thread::pending_exception_offset()))); __ cbnz(rscratch1, exception_pending); @@ -2217,6 +2202,12 @@ void SharedRuntime::generate_deopt_blob() { } #endif const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, (uint)SharedStubId::deopt_id, name); + if (blob != nullptr) { + _deopt_blob = blob->as_deoptimization_blob(); + return; + } + CodeBuffer buffer(name, 2048+pad, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; @@ -2580,6 +2571,8 @@ void SharedRuntime::generate_deopt_blob() { _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); } #endif + + AOTCodeCache::store_code_blob(*_deopt_blob, AOTCodeEntry::SharedBlob, (uint)SharedStubId::deopt_id, name); } // Number of stack slots between incoming argument block and the start of @@ -2608,12 +2601,16 @@ VMReg SharedRuntime::thread_register() { SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address call_ptr) { assert(is_polling_page_id(id), "expected a polling page stub id"); + // Allocate space for the code. Setup code generation tools. + const char* name = SharedRuntime::stub_name(id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, (uint)id, name); + if (blob != nullptr) { + return blob->as_safepoint_blob(); + } + ResourceMark rm; OopMapSet *oop_maps = new OopMapSet(); OopMap* map; - - // Allocate space for the code. Setup code generation tools. - const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 2048, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); @@ -2722,7 +2719,10 @@ SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address cal masm->flush(); // Fill-out other meta info - return SafepointBlob::create(&buffer, oop_maps, frame_size_in_words); + SafepointBlob* sp_blob = SafepointBlob::create(&buffer, oop_maps, frame_size_in_words); + + AOTCodeCache::store_code_blob(*sp_blob, AOTCodeEntry::SharedBlob, (uint)id, name); + return sp_blob; } // @@ -2737,10 +2737,14 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); assert(is_resolve_id(id), "expected a resolve stub id"); + const char* name = SharedRuntime::stub_name(id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, (uint)id, name); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + // allocate space for the code ResourceMark rm; - - const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 1000, 512); MacroAssembler* masm = new MacroAssembler(&buffer); @@ -2813,7 +2817,10 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti // return the blob // frame_size_words or bytes?? - return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); + RuntimeStub* rs_blob = RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); + + AOTCodeCache::store_code_blob(*rs_blob, AOTCodeEntry::SharedBlob, (uint)id, name); + return rs_blob; } // Continuation point for throwing of implicit exceptions that are @@ -2853,10 +2860,15 @@ RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address ru int insts_size = 512; int locs_size = 64; - ResourceMark rm; const char* timer_msg = "SharedRuntime generate_throw_exception"; TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, (uint)id, name); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + + ResourceMark rm; CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -2883,7 +2895,7 @@ RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address ru __ mov(c_rarg0, rthread); BLOCK_COMMENT("call runtime_entry"); - __ mov(rscratch1, runtime_entry); + __ lea(rscratch1, RuntimeAddress(runtime_entry)); __ blr(rscratch1); // Generate oop map @@ -2916,6 +2928,8 @@ RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address ru frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); + AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, (uint)id, name); + return stub; } diff --git a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp index c8b215b6eb4..e0ca01ba6ce 100644 --- a/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubDeclarations_aarch64.hpp @@ -44,7 +44,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 65000 ZGC_ONLY(+5000)) \ + do_arch_blob(compiler, 70000) \ do_stub(compiler, vector_iota_indices) \ do_arch_entry(aarch64, compiler, vector_iota_indices, \ vector_iota_indices, vector_iota_indices) \ @@ -109,7 +109,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(final, 20000 ZGC_ONLY(+60000)) \ + do_arch_blob(final, 20000 ZGC_ONLY(+85000)) \ do_stub(final, copy_byte_f) \ do_arch_entry(aarch64, final, copy_byte_f, copy_byte_f, \ copy_byte_f) \ diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 467505ed337..a0d1e22ff96 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -1162,7 +1162,7 @@ class StubGenerator: public StubCodeGenerator { void copy_memory_small(DecoratorSet decorators, BasicType type, Register s, Register d, Register count, int step) { bool is_backwards = step < 0; - size_t granularity = uabs(step); + size_t granularity = g_uabs(step); int direction = is_backwards ? -1 : 1; Label Lword, Lint, Lshort, Lbyte; @@ -1221,7 +1221,7 @@ class StubGenerator: public StubCodeGenerator { Register s, Register d, Register count, int step) { copy_direction direction = step < 0 ? copy_backwards : copy_forwards; bool is_backwards = step < 0; - unsigned int granularity = uabs(step); + unsigned int granularity = g_uabs(step); const Register t0 = r3, t1 = r4; // <= 80 (or 96 for SIMD) bytes do inline. Direction doesn't matter because we always @@ -2566,6 +2566,123 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_unsafecopy_common_error_exit() { + address start_pc = __ pc(); + __ leave(); + __ mov(r0, 0); + __ ret(lr); + return start_pc; + } + + // + // Generate 'unsafe' set memory stub + // Though just as safe as the other stubs, it takes an unscaled + // size_t (# bytes) argument instead of an element count. + // + // This fill operation is atomicity preserving: as long as the + // address supplied is sufficiently aligned, all writes of up to 64 + // bits in size are single-copy atomic. + // + // Input: + // c_rarg0 - destination array address + // c_rarg1 - byte count (size_t) + // c_rarg2 - byte value + // + address generate_unsafe_setmemory() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, StubGenStubId::unsafe_setmemory_id); + address start = __ pc(); + + Register dest = c_rarg0, count = c_rarg1, value = c_rarg2; + Label tail; + + UnsafeMemoryAccessMark umam(this, true, false); + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + __ dup(v0, __ T16B, value); + + if (AvoidUnalignedAccesses) { + __ cmp(count, (u1)16); + __ br(__ LO, tail); + + __ mov(rscratch1, 16); + __ andr(rscratch2, dest, 15); + __ sub(rscratch1, rscratch1, rscratch2); // Bytes needed to 16-align dest + __ strq(v0, Address(dest)); + __ sub(count, count, rscratch1); + __ add(dest, dest, rscratch1); + } + + __ subs(count, count, (u1)64); + __ br(__ LO, tail); + { + Label again; + __ bind(again); + __ stpq(v0, v0, Address(dest)); + __ stpq(v0, v0, Address(dest, 32)); + + __ subs(count, count, 64); + __ add(dest, dest, 64); + __ br(__ HS, again); + } + + __ bind(tail); + // The count of bytes is off by 64, but we don't need to correct + // it because we're only going to use the least-significant few + // count bits from here on. + // __ add(count, count, 64); + + { + Label dont; + __ tbz(count, exact_log2(32), dont); + __ stpq(v0, v0, __ post(dest, 32)); + __ bind(dont); + } + { + Label dont; + __ tbz(count, exact_log2(16), dont); + __ strq(v0, __ post(dest, 16)); + __ bind(dont); + } + { + Label dont; + __ tbz(count, exact_log2(8), dont); + __ strd(v0, __ post(dest, 8)); + __ bind(dont); + } + + Label finished; + __ tst(count, 7); + __ br(__ EQ, finished); + + { + Label dont; + __ tbz(count, exact_log2(4), dont); + __ strs(v0, __ post(dest, 4)); + __ bind(dont); + } + { + Label dont; + __ tbz(count, exact_log2(2), dont); + __ bfi(value, value, 8, 8); + __ strh(value, __ post(dest, 2)); + __ bind(dont); + } + { + Label dont; + __ tbz(count, exact_log2(1), dont); + __ strb(value, Address(dest)); + __ bind(dont); + } + + __ bind(finished); + __ leave(); + __ ret(lr); + + return start; + } + address generate_data_cache_writeback() { const Register line = c_rarg0; // address of line to write back @@ -2615,6 +2732,9 @@ class StubGenerator: public StubCodeGenerator { address entry_jlong_arraycopy; address entry_checkcast_arraycopy; + address ucm_common_error_exit = generate_unsafecopy_common_error_exit(); + UnsafeMemoryAccess::set_common_exit_stub_pc(ucm_common_error_exit); + generate_copy_longs(StubGenStubId::copy_byte_f_id, IN_HEAP | IS_ARRAY, copy_f, r0, r1, r15); generate_copy_longs(StubGenStubId::copy_byte_b_id, IN_HEAP | IS_ARRAY, copy_b, r0, r1, r15); @@ -4405,89 +4525,44 @@ class StubGenerator: public StubCodeGenerator { return start; } - /** - * Arguments: - * - * Inputs: - * c_rarg0 - int crc - * c_rarg1 - byte* buf - * c_rarg2 - int length - * - * Output: - * rax - int crc result - */ - address generate_updateBytesCRC32() { - assert(UseCRC32Intrinsics, "what are we doing here?"); - - __ align(CodeEntryAlignment); - StubGenStubId stub_id = StubGenStubId::updateBytesCRC32_id; - StubCodeMark mark(this, stub_id); - - address start = __ pc(); - - const Register crc = c_rarg0; // crc - const Register buf = c_rarg1; // source java byte array address - const Register len = c_rarg2; // length - const Register table0 = c_rarg3; // crc_table address - const Register table1 = c_rarg4; - const Register table2 = c_rarg5; - const Register table3 = c_rarg6; - const Register tmp3 = c_rarg7; - - BLOCK_COMMENT("Entry:"); - __ enter(); // required for proper stackwalking of RuntimeStub frame - - __ kernel_crc32(crc, buf, len, - table0, table1, table2, table3, rscratch1, rscratch2, tmp3); - - __ leave(); // required for proper stackwalking of RuntimeStub frame - __ ret(lr); - - return start; - } - - // ChaCha20 block function. This version parallelizes 4 quarter - // round operations at a time. It uses 16 SIMD registers to - // produce 4 blocks of key stream. + // ChaCha20 block function. This version parallelizes the 32-bit + // state elements on each of 16 vectors, producing 4 blocks of + // keystream at a time. // // state (int[16]) = c_rarg0 // keystream (byte[256]) = c_rarg1 - // return - number of bytes of keystream (always 256) - // - // In this approach, we load the 512-bit start state sequentially into - // 4 128-bit vectors. We then make 4 4-vector copies of that starting - // state, with each successive set of 4 vectors having a +1 added into - // the first 32-bit lane of the 4th vector in that group (the counter). - // By doing this, we can perform the block function on 4 512-bit blocks - // within one run of this intrinsic. - // The alignment of the data across the 4-vector group is such that at - // the start it is already aligned for the first round of each two-round - // loop iteration. In other words, the corresponding lanes of each vector - // will contain the values needed for that quarter round operation (e.g. - // elements 0/4/8/12, 1/5/9/13, 2/6/10/14, etc.). - // In between each full round, a lane shift must occur. Within a loop - // iteration, between the first and second rounds, the 2nd, 3rd, and 4th - // vectors are rotated left 32, 64 and 96 bits, respectively. The result - // is effectively a diagonal orientation in columnar form. After the - // second full round, those registers are left-rotated again, this time - // 96, 64, and 32 bits - returning the vectors to their columnar organization. - // After all 10 iterations, the original state is added to each 4-vector - // working state along with the add mask, and the 4 vector groups are - // sequentially written to the memory dedicated for the output key stream. + // return - number of bytes of produced keystream (always 256) // - // For a more detailed explanation, see Goll and Gueron, "Vectorization of - // ChaCha Stream Cipher", 2014 11th Int. Conf. on Information Technology: - // New Generations, Las Vegas, NV, USA, April 2014, DOI: 10.1109/ITNG.2014.33 - address generate_chacha20Block_qrpar() { - Label L_Q_twoRounds, L_Q_cc20_const; + // This implementation takes each 32-bit integer from the state + // array and broadcasts it across all 4 32-bit lanes of a vector register + // (e.g. state[0] is replicated on all 4 lanes of v4, state[1] to all 4 lanes + // of v5, etc.). Once all 16 elements have been broadcast onto 16 vectors, + // the quarter round schedule is implemented as outlined in RFC 7539 section + // 2.3. However, instead of sequentially processing the 3 quarter round + // operations represented by one QUARTERROUND function, we instead stack all + // the adds, xors and left-rotations from the first 4 quarter rounds together + // and then do the same for the second set of 4 quarter rounds. This removes + // some latency that would otherwise be incurred by waiting for an add to + // complete before performing an xor (which depends on the result of the + // add), etc. An adjustment happens between the first and second groups of 4 + // quarter rounds, but this is done only in the inputs to the macro functions + // that generate the assembly instructions - these adjustments themselves are + // not part of the resulting assembly. + // The 4 registers v0-v3 are used during the quarter round operations as + // scratch registers. Once the 20 rounds are complete, these 4 scratch + // registers become the vectors involved in adding the start state back onto + // the post-QR working state. After the adds are complete, each of the 16 + // vectors write their first lane back to the keystream buffer, followed + // by the second lane from all vectors and so on. + address generate_chacha20Block_blockpar() { + Label L_twoRounds, L_cc20_const; // The constant data is broken into two 128-bit segments to be loaded - // onto SIMD registers. The first 128 bits are a counter add overlay - // that adds +1/+0/+0/+0 to the vectors holding replicated state[12]. + // onto FloatRegisters. The first 128 bits are a counter add overlay + // that adds +0/+1/+2/+3 to the vector holding replicated state[12]. // The second 128-bits is a table constant used for 8-bit left rotations. - // on 32-bit lanes within a SIMD register. - __ BIND(L_Q_cc20_const); - __ emit_int64(0x0000000000000001UL); - __ emit_int64(0x0000000000000000UL); + __ BIND(L_cc20_const); + __ emit_int64(0x0000000100000000UL); + __ emit_int64(0x0000000300000002UL); __ emit_int64(0x0605040702010003UL); __ emit_int64(0x0E0D0C0F0A09080BUL); @@ -4497,144 +4572,142 @@ class StubGenerator: public StubCodeGenerator { address start = __ pc(); __ enter(); + int i, j; const Register state = c_rarg0; const Register keystream = c_rarg1; const Register loopCtr = r10; const Register tmpAddr = r11; + const FloatRegister ctrAddOverlay = v28; + const FloatRegister lrot8Tbl = v29; + + // Organize SIMD registers in an array that facilitates + // putting repetitive opcodes into loop structures. It is + // important that each grouping of 4 registers is monotonically + // increasing to support the requirements of multi-register + // instructions (e.g. ld4r, st4, etc.) + const FloatRegister workSt[16] = { + v4, v5, v6, v7, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27 + }; - const FloatRegister aState = v0; - const FloatRegister bState = v1; - const FloatRegister cState = v2; - const FloatRegister dState = v3; - const FloatRegister a1Vec = v4; - const FloatRegister b1Vec = v5; - const FloatRegister c1Vec = v6; - const FloatRegister d1Vec = v7; - // Skip the callee-saved registers v8 - v15 - const FloatRegister a2Vec = v16; - const FloatRegister b2Vec = v17; - const FloatRegister c2Vec = v18; - const FloatRegister d2Vec = v19; - const FloatRegister a3Vec = v20; - const FloatRegister b3Vec = v21; - const FloatRegister c3Vec = v22; - const FloatRegister d3Vec = v23; - const FloatRegister a4Vec = v24; - const FloatRegister b4Vec = v25; - const FloatRegister c4Vec = v26; - const FloatRegister d4Vec = v27; - const FloatRegister scratch = v28; - const FloatRegister addMask = v29; - const FloatRegister lrot8Tbl = v30; - - // Load the initial state in the first 4 quadword registers, - // then copy the initial state into the next 4 quadword registers - // that will be used for the working state. - __ ld1(aState, bState, cState, dState, __ T16B, Address(state)); - - // Load the index register for 2 constant 128-bit data fields. - // The first represents the +1/+0/+0/+0 add mask. The second is - // the 8-bit left rotation. - __ adr(tmpAddr, L_Q_cc20_const); - __ ldpq(addMask, lrot8Tbl, Address(tmpAddr)); - - __ mov(a1Vec, __ T16B, aState); - __ mov(b1Vec, __ T16B, bState); - __ mov(c1Vec, __ T16B, cState); - __ mov(d1Vec, __ T16B, dState); - - __ mov(a2Vec, __ T16B, aState); - __ mov(b2Vec, __ T16B, bState); - __ mov(c2Vec, __ T16B, cState); - __ addv(d2Vec, __ T4S, d1Vec, addMask); - - __ mov(a3Vec, __ T16B, aState); - __ mov(b3Vec, __ T16B, bState); - __ mov(c3Vec, __ T16B, cState); - __ addv(d3Vec, __ T4S, d2Vec, addMask); - - __ mov(a4Vec, __ T16B, aState); - __ mov(b4Vec, __ T16B, bState); - __ mov(c4Vec, __ T16B, cState); - __ addv(d4Vec, __ T4S, d3Vec, addMask); - - // Set up the 10 iteration loop + // Pull in constant data. The first 16 bytes are the add overlay + // which is applied to the vector holding the counter (state[12]). + // The second 16 bytes is the index register for the 8-bit left + // rotation tbl instruction. + __ adr(tmpAddr, L_cc20_const); + __ ldpq(ctrAddOverlay, lrot8Tbl, Address(tmpAddr)); + + // Load from memory and interlace across 16 SIMD registers, + // With each word from memory being broadcast to all lanes of + // each successive SIMD register. + // Addr(0) -> All lanes in workSt[i] + // Addr(4) -> All lanes workSt[i + 1], etc. + __ mov(tmpAddr, state); + for (i = 0; i < 16; i += 4) { + __ ld4r(workSt[i], workSt[i + 1], workSt[i + 2], workSt[i + 3], __ T4S, + __ post(tmpAddr, 16)); + } + __ addv(workSt[12], __ T4S, workSt[12], ctrAddOverlay); // Add ctr overlay + + // Before entering the loop, create 5 4-register arrays. These + // will hold the 4 registers that represent the a/b/c/d fields + // in the quarter round operation. For instance the "b" field + // for the first 4 quarter round operations is the set of v16/v17/v18/v19, + // but in the second 4 quarter rounds it gets adjusted to v17/v18/v19/v16 + // since it is part of a diagonal organization. The aSet and scratch + // register sets are defined at declaration time because they do not change + // organization at any point during the 20-round processing. + FloatRegister aSet[4] = { v4, v5, v6, v7 }; + FloatRegister bSet[4]; + FloatRegister cSet[4]; + FloatRegister dSet[4]; + FloatRegister scratch[4] = { v0, v1, v2, v3 }; + + // Set up the 10 iteration loop and perform all 8 quarter round ops __ mov(loopCtr, 10); - __ BIND(L_Q_twoRounds); - - // The first set of operations on the vectors covers the first 4 quarter - // round operations: - // Qround(state, 0, 4, 8,12) - // Qround(state, 1, 5, 9,13) - // Qround(state, 2, 6,10,14) - // Qround(state, 3, 7,11,15) - __ cc20_quarter_round(a1Vec, b1Vec, c1Vec, d1Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a2Vec, b2Vec, c2Vec, d2Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a3Vec, b3Vec, c3Vec, d3Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a4Vec, b4Vec, c4Vec, d4Vec, scratch, lrot8Tbl); - - // Shuffle the b1Vec/c1Vec/d1Vec to reorganize the state vectors to - // diagonals. The a1Vec does not need to change orientation. - __ cc20_shift_lane_org(b1Vec, c1Vec, d1Vec, true); - __ cc20_shift_lane_org(b2Vec, c2Vec, d2Vec, true); - __ cc20_shift_lane_org(b3Vec, c3Vec, d3Vec, true); - __ cc20_shift_lane_org(b4Vec, c4Vec, d4Vec, true); - - // The second set of operations on the vectors covers the second 4 quarter - // round operations, now acting on the diagonals: - // Qround(state, 0, 5,10,15) - // Qround(state, 1, 6,11,12) - // Qround(state, 2, 7, 8,13) - // Qround(state, 3, 4, 9,14) - __ cc20_quarter_round(a1Vec, b1Vec, c1Vec, d1Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a2Vec, b2Vec, c2Vec, d2Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a3Vec, b3Vec, c3Vec, d3Vec, scratch, lrot8Tbl); - __ cc20_quarter_round(a4Vec, b4Vec, c4Vec, d4Vec, scratch, lrot8Tbl); - - // Before we start the next iteration, we need to perform shuffles - // on the b/c/d vectors to move them back to columnar organizations - // from their current diagonal orientation. - __ cc20_shift_lane_org(b1Vec, c1Vec, d1Vec, false); - __ cc20_shift_lane_org(b2Vec, c2Vec, d2Vec, false); - __ cc20_shift_lane_org(b3Vec, c3Vec, d3Vec, false); - __ cc20_shift_lane_org(b4Vec, c4Vec, d4Vec, false); + __ BIND(L_twoRounds); + + // Set to columnar organization and do the following 4 quarter-rounds: + // QUARTERROUND(0, 4, 8, 12) + // QUARTERROUND(1, 5, 9, 13) + // QUARTERROUND(2, 6, 10, 14) + // QUARTERROUND(3, 7, 11, 15) + __ cc20_set_qr_registers(bSet, workSt, 4, 5, 6, 7); + __ cc20_set_qr_registers(cSet, workSt, 8, 9, 10, 11); + __ cc20_set_qr_registers(dSet, workSt, 12, 13, 14, 15); + + __ cc20_qr_add4(aSet, bSet); // a += b + __ cc20_qr_xor4(dSet, aSet, dSet); // d ^= a + __ cc20_qr_lrot4(dSet, dSet, 16, lrot8Tbl); // d <<<= 16 + + __ cc20_qr_add4(cSet, dSet); // c += d + __ cc20_qr_xor4(bSet, cSet, scratch); // b ^= c (scratch) + __ cc20_qr_lrot4(scratch, bSet, 12, lrot8Tbl); // b <<<= 12 + + __ cc20_qr_add4(aSet, bSet); // a += b + __ cc20_qr_xor4(dSet, aSet, dSet); // d ^= a + __ cc20_qr_lrot4(dSet, dSet, 8, lrot8Tbl); // d <<<= 8 + + __ cc20_qr_add4(cSet, dSet); // c += d + __ cc20_qr_xor4(bSet, cSet, scratch); // b ^= c (scratch) + __ cc20_qr_lrot4(scratch, bSet, 7, lrot8Tbl); // b <<<= 12 + + // Set to diagonal organization and do the next 4 quarter-rounds: + // QUARTERROUND(0, 5, 10, 15) + // QUARTERROUND(1, 6, 11, 12) + // QUARTERROUND(2, 7, 8, 13) + // QUARTERROUND(3, 4, 9, 14) + __ cc20_set_qr_registers(bSet, workSt, 5, 6, 7, 4); + __ cc20_set_qr_registers(cSet, workSt, 10, 11, 8, 9); + __ cc20_set_qr_registers(dSet, workSt, 15, 12, 13, 14); + + __ cc20_qr_add4(aSet, bSet); // a += b + __ cc20_qr_xor4(dSet, aSet, dSet); // d ^= a + __ cc20_qr_lrot4(dSet, dSet, 16, lrot8Tbl); // d <<<= 16 + + __ cc20_qr_add4(cSet, dSet); // c += d + __ cc20_qr_xor4(bSet, cSet, scratch); // b ^= c (scratch) + __ cc20_qr_lrot4(scratch, bSet, 12, lrot8Tbl); // b <<<= 12 + + __ cc20_qr_add4(aSet, bSet); // a += b + __ cc20_qr_xor4(dSet, aSet, dSet); // d ^= a + __ cc20_qr_lrot4(dSet, dSet, 8, lrot8Tbl); // d <<<= 8 + + __ cc20_qr_add4(cSet, dSet); // c += d + __ cc20_qr_xor4(bSet, cSet, scratch); // b ^= c (scratch) + __ cc20_qr_lrot4(scratch, bSet, 7, lrot8Tbl); // b <<<= 12 // Decrement and iterate __ sub(loopCtr, loopCtr, 1); - __ cbnz(loopCtr, L_Q_twoRounds); - - // Once the counter reaches zero, we fall out of the loop - // and need to add the initial state back into the working state - // represented by the a/b/c/d1Vec registers. This is destructive - // on the dState register but we no longer will need it. - __ addv(a1Vec, __ T4S, a1Vec, aState); - __ addv(b1Vec, __ T4S, b1Vec, bState); - __ addv(c1Vec, __ T4S, c1Vec, cState); - __ addv(d1Vec, __ T4S, d1Vec, dState); - - __ addv(a2Vec, __ T4S, a2Vec, aState); - __ addv(b2Vec, __ T4S, b2Vec, bState); - __ addv(c2Vec, __ T4S, c2Vec, cState); - __ addv(dState, __ T4S, dState, addMask); - __ addv(d2Vec, __ T4S, d2Vec, dState); - - __ addv(a3Vec, __ T4S, a3Vec, aState); - __ addv(b3Vec, __ T4S, b3Vec, bState); - __ addv(c3Vec, __ T4S, c3Vec, cState); - __ addv(dState, __ T4S, dState, addMask); - __ addv(d3Vec, __ T4S, d3Vec, dState); - - __ addv(a4Vec, __ T4S, a4Vec, aState); - __ addv(b4Vec, __ T4S, b4Vec, bState); - __ addv(c4Vec, __ T4S, c4Vec, cState); - __ addv(dState, __ T4S, dState, addMask); - __ addv(d4Vec, __ T4S, d4Vec, dState); - - // Write the final state back to the result buffer - __ st1(a1Vec, b1Vec, c1Vec, d1Vec, __ T16B, __ post(keystream, 64)); - __ st1(a2Vec, b2Vec, c2Vec, d2Vec, __ T16B, __ post(keystream, 64)); - __ st1(a3Vec, b3Vec, c3Vec, d3Vec, __ T16B, __ post(keystream, 64)); - __ st1(a4Vec, b4Vec, c4Vec, d4Vec, __ T16B, __ post(keystream, 64)); + __ cbnz(loopCtr, L_twoRounds); + + __ mov(tmpAddr, state); + + // Add the starting state back to the post-loop keystream + // state. We read/interlace the state array from memory into + // 4 registers similar to what we did in the beginning. Then + // add the counter overlay onto workSt[12] at the end. + for (i = 0; i < 16; i += 4) { + __ ld4r(v0, v1, v2, v3, __ T4S, __ post(tmpAddr, 16)); + __ addv(workSt[i], __ T4S, workSt[i], v0); + __ addv(workSt[i + 1], __ T4S, workSt[i + 1], v1); + __ addv(workSt[i + 2], __ T4S, workSt[i + 2], v2); + __ addv(workSt[i + 3], __ T4S, workSt[i + 3], v3); + } + __ addv(workSt[12], __ T4S, workSt[12], ctrAddOverlay); // Add ctr overlay + + // Write working state into the keystream buffer. This is accomplished + // by taking the lane "i" from each of the four vectors and writing + // it to consecutive 4-byte offsets, then post-incrementing by 16 and + // repeating with the next 4 vectors until all 16 vectors have been used. + // Then move to the next lane and repeat the process until all lanes have + // been written. + for (i = 0; i < 4; i++) { + for (j = 0; j < 16; j += 4) { + __ st4(workSt[j], workSt[j + 1], workSt[j + 2], workSt[j + 3], __ S, i, + __ post(keystream, 16)); + } + } __ mov(r0, 256); // Return length of output keystream __ leave(); @@ -7008,6 +7081,407 @@ class StubGenerator: public StubCodeGenerator { return start; } + void bcax5(Register a0, Register a1, Register a2, Register a3, Register a4, + Register tmp0, Register tmp1, Register tmp2) { + __ bic(tmp0, a2, a1); // for a0 + __ bic(tmp1, a3, a2); // for a1 + __ bic(tmp2, a4, a3); // for a2 + __ eor(a2, a2, tmp2); + __ bic(tmp2, a0, a4); // for a3 + __ eor(a3, a3, tmp2); + __ bic(tmp2, a1, a0); // for a4 + __ eor(a0, a0, tmp0); + __ eor(a1, a1, tmp1); + __ eor(a4, a4, tmp2); + } + + void keccak_round_gpr(bool can_use_fp, bool can_use_r18, Register rc, + Register a0, Register a1, Register a2, Register a3, Register a4, + Register a5, Register a6, Register a7, Register a8, Register a9, + Register a10, Register a11, Register a12, Register a13, Register a14, + Register a15, Register a16, Register a17, Register a18, Register a19, + Register a20, Register a21, Register a22, Register a23, Register a24, + Register tmp0, Register tmp1, Register tmp2) { + __ eor3(tmp1, a4, a9, a14); + __ eor3(tmp0, tmp1, a19, a24); // tmp0 = a4^a9^a14^a19^a24 = c4 + __ eor3(tmp2, a1, a6, a11); + __ eor3(tmp1, tmp2, a16, a21); // tmp1 = a1^a6^a11^a16^a21 = c1 + __ rax1(tmp2, tmp0, tmp1); // d0 + { + + Register tmp3, tmp4; + if (can_use_fp && can_use_r18) { + tmp3 = rfp; + tmp4 = r18_tls; + } else { + tmp3 = a4; + tmp4 = a9; + __ stp(tmp3, tmp4, __ pre(sp, -16)); + } + + __ eor3(tmp3, a0, a5, a10); + __ eor3(tmp4, tmp3, a15, a20); // tmp4 = a0^a5^a10^a15^a20 = c0 + __ eor(a0, a0, tmp2); + __ eor(a5, a5, tmp2); + __ eor(a10, a10, tmp2); + __ eor(a15, a15, tmp2); + __ eor(a20, a20, tmp2); // d0(tmp2) + __ eor3(tmp3, a2, a7, a12); + __ eor3(tmp2, tmp3, a17, a22); // tmp2 = a2^a7^a12^a17^a22 = c2 + __ rax1(tmp3, tmp4, tmp2); // d1 + __ eor(a1, a1, tmp3); + __ eor(a6, a6, tmp3); + __ eor(a11, a11, tmp3); + __ eor(a16, a16, tmp3); + __ eor(a21, a21, tmp3); // d1(tmp3) + __ rax1(tmp3, tmp2, tmp0); // d3 + __ eor3(tmp2, a3, a8, a13); + __ eor3(tmp0, tmp2, a18, a23); // tmp0 = a3^a8^a13^a18^a23 = c3 + __ eor(a3, a3, tmp3); + __ eor(a8, a8, tmp3); + __ eor(a13, a13, tmp3); + __ eor(a18, a18, tmp3); + __ eor(a23, a23, tmp3); + __ rax1(tmp2, tmp1, tmp0); // d2 + __ eor(a2, a2, tmp2); + __ eor(a7, a7, tmp2); + __ eor(a12, a12, tmp2); + __ rax1(tmp0, tmp0, tmp4); // d4 + if (!can_use_fp || !can_use_r18) { + __ ldp(tmp3, tmp4, __ post(sp, 16)); + } + __ eor(a17, a17, tmp2); + __ eor(a22, a22, tmp2); + __ eor(a4, a4, tmp0); + __ eor(a9, a9, tmp0); + __ eor(a14, a14, tmp0); + __ eor(a19, a19, tmp0); + __ eor(a24, a24, tmp0); + } + + __ rol(tmp0, a10, 3); + __ rol(a10, a1, 1); + __ rol(a1, a6, 44); + __ rol(a6, a9, 20); + __ rol(a9, a22, 61); + __ rol(a22, a14, 39); + __ rol(a14, a20, 18); + __ rol(a20, a2, 62); + __ rol(a2, a12, 43); + __ rol(a12, a13, 25); + __ rol(a13, a19, 8) ; + __ rol(a19, a23, 56); + __ rol(a23, a15, 41); + __ rol(a15, a4, 27); + __ rol(a4, a24, 14); + __ rol(a24, a21, 2); + __ rol(a21, a8, 55); + __ rol(a8, a16, 45); + __ rol(a16, a5, 36); + __ rol(a5, a3, 28); + __ rol(a3, a18, 21); + __ rol(a18, a17, 15); + __ rol(a17, a11, 10); + __ rol(a11, a7, 6); + __ mov(a7, tmp0); + + bcax5(a0, a1, a2, a3, a4, tmp0, tmp1, tmp2); + bcax5(a5, a6, a7, a8, a9, tmp0, tmp1, tmp2); + bcax5(a10, a11, a12, a13, a14, tmp0, tmp1, tmp2); + bcax5(a15, a16, a17, a18, a19, tmp0, tmp1, tmp2); + bcax5(a20, a21, a22, a23, a24, tmp0, tmp1, tmp2); + + __ ldr(tmp1, __ post(rc, 8)); + __ eor(a0, a0, tmp1); + + } + + // Arguments: + // + // Inputs: + // c_rarg0 - byte[] source+offset + // c_rarg1 - byte[] SHA.state + // c_rarg2 - int block_size + // c_rarg3 - int offset + // c_rarg4 - int limit + // + address generate_sha3_implCompress_gpr(StubGenStubId stub_id) { + bool multi_block; + switch (stub_id) { + case sha3_implCompress_id: + multi_block = false; + break; + case sha3_implCompressMB_id: + multi_block = true; + break; + default: + ShouldNotReachHere(); + } + + static const uint64_t round_consts[24] = { + 0x0000000000000001L, 0x0000000000008082L, 0x800000000000808AL, + 0x8000000080008000L, 0x000000000000808BL, 0x0000000080000001L, + 0x8000000080008081L, 0x8000000000008009L, 0x000000000000008AL, + 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000AL, + 0x000000008000808BL, 0x800000000000008BL, 0x8000000000008089L, + 0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, + 0x000000000000800AL, 0x800000008000000AL, 0x8000000080008081L, + 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L + }; + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, stub_id); + address start = __ pc(); + + Register buf = c_rarg0; + Register state = c_rarg1; + Register block_size = c_rarg2; + Register ofs = c_rarg3; + Register limit = c_rarg4; + + // use r3.r17,r19..r28 to keep a0..a24. + // a0..a24 are respective locals from SHA3.java + Register a0 = r25, + a1 = r26, + a2 = r27, + a3 = r3, + a4 = r4, + a5 = r5, + a6 = r6, + a7 = r7, + a8 = rscratch1, // r8 + a9 = rscratch2, // r9 + a10 = r10, + a11 = r11, + a12 = r12, + a13 = r13, + a14 = r14, + a15 = r15, + a16 = r16, + a17 = r17, + a18 = r28, + a19 = r19, + a20 = r20, + a21 = r21, + a22 = r22, + a23 = r23, + a24 = r24; + + Register tmp0 = block_size, tmp1 = buf, tmp2 = state, tmp3 = r30; + + Label sha3_loop, rounds24_preloop, loop_body; + Label sha3_512_or_sha3_384, shake128; + + bool can_use_r18 = false; +#ifndef R18_RESERVED + can_use_r18 = true; +#endif + bool can_use_fp = !PreserveFramePointer; + + __ enter(); + + // save almost all yet unsaved gpr registers on stack + __ str(block_size, __ pre(sp, -128)); + if (multi_block) { + __ stpw(ofs, limit, Address(sp, 8)); + } + // 8 bytes at sp+16 will be used to keep buf + __ stp(r19, r20, Address(sp, 32)); + __ stp(r21, r22, Address(sp, 48)); + __ stp(r23, r24, Address(sp, 64)); + __ stp(r25, r26, Address(sp, 80)); + __ stp(r27, r28, Address(sp, 96)); + if (can_use_r18 && can_use_fp) { + __ stp(r18_tls, state, Address(sp, 112)); + } else { + __ str(state, Address(sp, 112)); + } + + // begin sha3 calculations: loading a0..a24 from state arrary + __ ldp(a0, a1, state); + __ ldp(a2, a3, Address(state, 16)); + __ ldp(a4, a5, Address(state, 32)); + __ ldp(a6, a7, Address(state, 48)); + __ ldp(a8, a9, Address(state, 64)); + __ ldp(a10, a11, Address(state, 80)); + __ ldp(a12, a13, Address(state, 96)); + __ ldp(a14, a15, Address(state, 112)); + __ ldp(a16, a17, Address(state, 128)); + __ ldp(a18, a19, Address(state, 144)); + __ ldp(a20, a21, Address(state, 160)); + __ ldp(a22, a23, Address(state, 176)); + __ ldr(a24, Address(state, 192)); + + __ BIND(sha3_loop); + + // load input + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a0, a0, tmp3); + __ eor(a1, a1, tmp2); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a2, a2, tmp3); + __ eor(a3, a3, tmp2); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a4, a4, tmp3); + __ eor(a5, a5, tmp2); + __ ldr(tmp3, __ post(buf, 8)); + __ eor(a6, a6, tmp3); + + // block_size == 72, SHA3-512; block_size == 104, SHA3-384 + __ tbz(block_size, 7, sha3_512_or_sha3_384); + + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a7, a7, tmp3); + __ eor(a8, a8, tmp2); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a9, a9, tmp3); + __ eor(a10, a10, tmp2); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a11, a11, tmp3); + __ eor(a12, a12, tmp2); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a13, a13, tmp3); + __ eor(a14, a14, tmp2); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a15, a15, tmp3); + __ eor(a16, a16, tmp2); + + // block_size == 136, bit4 == 0 and bit5 == 0, SHA3-256 or SHAKE256 + __ andw(tmp2, block_size, 48); + __ cbzw(tmp2, rounds24_preloop); + __ tbnz(block_size, 5, shake128); + // block_size == 144, bit5 == 0, SHA3-244 + __ ldr(tmp3, __ post(buf, 8)); + __ eor(a17, a17, tmp3); + __ b(rounds24_preloop); + + __ BIND(shake128); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a17, a17, tmp3); + __ eor(a18, a18, tmp2); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a19, a19, tmp3); + __ eor(a20, a20, tmp2); + __ b(rounds24_preloop); // block_size == 168, SHAKE128 + + __ BIND(sha3_512_or_sha3_384); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a7, a7, tmp3); + __ eor(a8, a8, tmp2); + __ tbz(block_size, 5, rounds24_preloop); // SHA3-512 + + // SHA3-384 + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a9, a9, tmp3); + __ eor(a10, a10, tmp2); + __ ldp(tmp3, tmp2, __ post(buf, 16)); + __ eor(a11, a11, tmp3); + __ eor(a12, a12, tmp2); + + __ BIND(rounds24_preloop); + __ fmovs(v0, 24.0); // float loop counter, + __ fmovs(v1, 1.0); // exact representation + + __ str(buf, Address(sp, 16)); + __ lea(tmp3, ExternalAddress((address) round_consts)); + + __ BIND(loop_body); + keccak_round_gpr(can_use_fp, can_use_r18, tmp3, + a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, + tmp0, tmp1, tmp2); + __ fsubs(v0, v0, v1); + __ fcmps(v0, 0.0); + __ br(__ NE, loop_body); + + if (multi_block) { + __ ldrw(block_size, sp); // block_size + __ ldpw(tmp2, tmp1, Address(sp, 8)); // offset, limit + __ addw(tmp2, tmp2, block_size); + __ cmpw(tmp2, tmp1); + __ strw(tmp2, Address(sp, 8)); // store offset in case we're jumping + __ ldr(buf, Address(sp, 16)); // restore buf in case we're jumping + __ br(Assembler::LE, sha3_loop); + __ movw(c_rarg0, tmp2); // return offset + } + if (can_use_fp && can_use_r18) { + __ ldp(r18_tls, state, Address(sp, 112)); + } else { + __ ldr(state, Address(sp, 112)); + } + // save calculated sha3 state + __ stp(a0, a1, Address(state)); + __ stp(a2, a3, Address(state, 16)); + __ stp(a4, a5, Address(state, 32)); + __ stp(a6, a7, Address(state, 48)); + __ stp(a8, a9, Address(state, 64)); + __ stp(a10, a11, Address(state, 80)); + __ stp(a12, a13, Address(state, 96)); + __ stp(a14, a15, Address(state, 112)); + __ stp(a16, a17, Address(state, 128)); + __ stp(a18, a19, Address(state, 144)); + __ stp(a20, a21, Address(state, 160)); + __ stp(a22, a23, Address(state, 176)); + __ str(a24, Address(state, 192)); + + // restore required registers from stack + __ ldp(r19, r20, Address(sp, 32)); + __ ldp(r21, r22, Address(sp, 48)); + __ ldp(r23, r24, Address(sp, 64)); + __ ldp(r25, r26, Address(sp, 80)); + __ ldp(r27, r28, Address(sp, 96)); + if (can_use_fp && can_use_r18) { + __ add(rfp, sp, 128); // leave() will copy rfp to sp below + } // else no need to recalculate rfp, since it wasn't changed + + __ leave(); + + __ ret(lr); + + return start; + } + + /** + * Arguments: + * + * Inputs: + * c_rarg0 - int crc + * c_rarg1 - byte* buf + * c_rarg2 - int length + * + * Output: + * rax - int crc result + */ + address generate_updateBytesCRC32() { + assert(UseCRC32Intrinsics, "what are we doing here?"); + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::updateBytesCRC32_id; + StubCodeMark mark(this, stub_id); + + address start = __ pc(); + + const Register crc = c_rarg0; // crc + const Register buf = c_rarg1; // source java byte array address + const Register len = c_rarg2; // length + const Register table0 = c_rarg3; // crc_table address + const Register table1 = c_rarg4; + const Register table2 = c_rarg5; + const Register table3 = c_rarg6; + const Register tmp3 = c_rarg7; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + + __ kernel_crc32(crc, buf, len, + table0, table1, table2, table3, rscratch1, rscratch2, tmp3); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(lr); + + return start; + } + /** * Arguments: * @@ -8115,7 +8589,8 @@ class StubGenerator: public StubCodeGenerator { __ andr(rscratch2, cnt, vf - 1); __ bind(TAIL_SHORTCUT); __ adr(rscratch1, BR_BASE); - __ sub(rscratch1, rscratch1, rscratch2, ext::uxtw, 3); + // For Cortex-A53 offset is 4 because 2 nops are generated. + __ sub(rscratch1, rscratch1, rscratch2, ext::uxtw, VM_Version::supports_a53mac() ? 4 : 3); __ movw(rscratch2, 0x1f); __ br(rscratch1); @@ -8123,6 +8598,11 @@ class StubGenerator: public StubCodeGenerator { __ load(rscratch1, Address(__ post(ary, type2aelembytes(eltype))), eltype); __ maddw(result, result, rscratch2, rscratch1); + // maddw generates an extra nop for Cortex-A53 (see maddw definition in macroAssembler). + // Generate 2nd nop to have 4 instructions per iteration. + if (VM_Version::supports_a53mac()) { + __ nop(); + } } __ bind(BR_BASE); @@ -11172,79 +11652,6 @@ class StubGenerator: public StubCodeGenerator { // } }; - void generate_vector_math_stubs() { - // Get native vector math stub routine addresses - void* libsleef = nullptr; - char ebuf[1024]; - char dll_name[JVM_MAXPATHLEN]; - if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "sleef")) { - libsleef = os::dll_load(dll_name, ebuf, sizeof ebuf); - } - if (libsleef == nullptr) { - log_info(library)("Failed to load native vector math library, %s!", ebuf); - return; - } - // Method naming convention - // All the methods are named as _ - // Where: - // is the operation name, e.g. sin - // is optional to indicate float/double - // "f/d" for vector float/double operation - // is the number of elements in the vector - // "2/4" for neon, and "x" for sve - // is the precision level - // "u10/u05" represents 1.0/0.5 ULP error bounds - // We use "u10" for all operations by default - // But for those functions do not have u10 support, we use "u05" instead - // indicates neon/sve - // "sve/advsimd" for sve/neon implementations - // e.g. sinfx_u10sve is the method for computing vector float sin using SVE instructions - // cosd2_u10advsimd is the method for computing 2 elements vector double cos using NEON instructions - // - log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "sleef" JNI_LIB_SUFFIX, p2i(libsleef)); - - // Math vector stubs implemented with SVE for scalable vector size. - if (UseSVE > 0) { - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - // Skip "tanh" because there is performance regression - if (vop == VectorSupport::VECTOR_OP_TANH) { - continue; - } - - // The native library does not support u10 level of "hypot". - const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10"; - - snprintf(ebuf, sizeof(ebuf), "%sfx_%ssve", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); - - snprintf(ebuf, sizeof(ebuf), "%sdx_%ssve", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); - } - } - - // Math vector stubs implemented with NEON for 64/128 bits vector size. - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - // Skip "tanh" because there is performance regression - if (vop == VectorSupport::VECTOR_OP_TANH) { - continue; - } - - // The native library does not support u10 level of "hypot". - const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10"; - - snprintf(ebuf, sizeof(ebuf), "%sf4_%sadvsimd", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libsleef, ebuf); - - snprintf(ebuf, sizeof(ebuf), "%sf4_%sadvsimd", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libsleef, ebuf); - - snprintf(ebuf, sizeof(ebuf), "%sd2_%sadvsimd", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libsleef, ebuf); - } - } - // Initialization void generate_initial_stubs() { // Generate initial stubs and initializes the entry points @@ -11332,6 +11739,8 @@ class StubGenerator: public StubCodeGenerator { } #endif + StubRoutines::_unsafe_setmemory = generate_unsafe_setmemory(); + StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated } @@ -11398,12 +11807,10 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_montgomerySquare = g.generate_multiply(); } - generate_vector_math_stubs(); - #endif // COMPILER2 if (UseChaCha20Intrinsics) { - StubRoutines::_chacha20Block = generate_chacha20Block_qrpar(); + StubRoutines::_chacha20Block = generate_chacha20Block_blockpar(); } if (UseKyberIntrinsics) { @@ -11465,9 +11872,15 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_sha512_implCompressMB = generate_sha512_implCompress(StubGenStubId::sha512_implCompressMB_id); } if (UseSHA3Intrinsics) { - StubRoutines::_sha3_implCompress = generate_sha3_implCompress(StubGenStubId::sha3_implCompress_id); + StubRoutines::_double_keccak = generate_double_keccak(); - StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(StubGenStubId::sha3_implCompressMB_id); + if (UseSIMDForSHA3Intrinsic) { + StubRoutines::_sha3_implCompress = generate_sha3_implCompress(StubGenStubId::sha3_implCompress_id); + StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress(StubGenStubId::sha3_implCompressMB_id); + } else { + StubRoutines::_sha3_implCompress = generate_sha3_implCompress_gpr(StubGenStubId::sha3_implCompress_id); + StubRoutines::_sha3_implCompressMB = generate_sha3_implCompress_gpr(StubGenStubId::sha3_implCompressMB_id); + } } if (UsePoly1305Intrinsics) { diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index 2db3b435abb..710970d1ea2 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -865,6 +865,10 @@ void TemplateInterpreterGenerator::lock_method() { // rcpool: cp cache // stack_pointer: previous sp void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { + // Save ConstMethod* in r5_const_method for later use to avoid loading multiple times + Register r5_const_method = r5; + __ ldr(r5_const_method, Address(rmethod, Method::const_offset())); + // initialize fixed part of activation frame if (native_call) { __ sub(esp, sp, 14 * wordSize); @@ -875,8 +879,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ stp(zr, zr, Address(sp, 12 * wordSize)); } else { __ sub(esp, sp, 12 * wordSize); - __ ldr(rscratch1, Address(rmethod, Method::const_offset())); // get ConstMethod - __ add(rbcp, rscratch1, in_bytes(ConstMethod::codes_offset())); // get codebase + __ add(rbcp, r5_const_method, in_bytes(ConstMethod::codes_offset())); // get codebase __ mov(rscratch1, frame::interpreter_frame_initial_sp_offset); __ stp(rscratch1, rbcp, Address(__ pre(sp, -12 * wordSize))); } @@ -896,9 +899,10 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ stp(rfp, lr, Address(sp, 10 * wordSize)); __ lea(rfp, Address(sp, 10 * wordSize)); - __ ldr(rcpool, Address(rmethod, Method::const_offset())); - __ ldr(rcpool, Address(rcpool, ConstMethod::constants_offset())); - __ ldr(rcpool, Address(rcpool, ConstantPool::cache_offset())); + // Save ConstantPool* in r11_constants for later use to avoid loading multiple times + Register r11_constants = r11; + __ ldr(r11_constants, Address(r5_const_method, ConstMethod::constants_offset())); + __ ldr(rcpool, Address(r11_constants, ConstantPool::cache_offset())); __ sub(rscratch1, rlocals, rfp); __ lsr(rscratch1, rscratch1, Interpreter::logStackElementSize); // rscratch1 = rlocals - fp(); // Store relativized rlocals, see frame::interpreter_frame_locals(). @@ -908,11 +912,12 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // leave last_sp as null __ stp(zr, r19_sender_sp, Address(sp, 8 * wordSize)); - // Get mirror - __ load_mirror(r10, rmethod, r5, rscratch2); + // Get mirror. Resolve ConstantPool* -> InstanceKlass* -> Java mirror. + __ ldr(r10, Address(r11_constants, ConstantPool::pool_holder_offset())); + __ ldr(r10, Address(r10, in_bytes(Klass::java_mirror_offset()))); + __ resolve_oop_handle(r10, rscratch1, rscratch2); if (! native_call) { - __ ldr(rscratch1, Address(rmethod, Method::const_offset())); - __ ldrh(rscratch1, Address(rscratch1, ConstMethod::max_stack_offset())); + __ ldrh(rscratch1, Address(r5_const_method, ConstMethod::max_stack_offset())); __ add(rscratch1, rscratch1, MAX2(3, Method::extra_stack_entries())); __ sub(rscratch1, sp, rscratch1, ext::uxtw, 3); __ andr(rscratch1, rscratch1, -16); @@ -1593,6 +1598,30 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ bind(L); } + #if INCLUDE_JFR + __ enter_jfr_critical_section(); + + // This poll test is to uphold the invariant that a JFR sampled frame + // must not return to its caller without a prior safepoint poll check. + // The earlier poll check in this routine is insufficient for this purpose + // because the thread has transitioned back to Java. + + Label slow_path; + Label fast_path; + __ safepoint_poll(slow_path, true /* at_return */, false /* acquire */, false /* in_nmethod */); + __ br(Assembler::AL, fast_path); + __ bind(slow_path); + __ push(dtos); + __ push(ltos); + __ set_last_Java_frame(esp, rfp, __ pc(), rscratch1); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), rthread); + __ reset_last_Java_frame(true); + __ pop(ltos); + __ pop(dtos); + __ bind(fast_path); + +#endif // INCLUDE_JFR + // jvmti support // Note: This must happen _after_ handling/throwing any exceptions since // the exception handler code notifies the runtime of method exits @@ -1615,6 +1644,8 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { // remove frame anchor __ leave(); + JFR_ONLY(__ leave_jfr_critical_section();) + // restore sender sp __ mov(sp, esp); @@ -1862,6 +1893,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { Interpreter::_remove_activation_preserving_args_entry = __ pc(); __ empty_expression_stack(); + __ restore_bcp(); // We could have returned from deoptimizing this frame, so restore rbcp. // Set the popframe_processing bit in pending_popframe_condition // indicating that we are currently handling popframe, so that // call_VMs that may happen later do not trigger new popframe diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index 2cc9b39983a..fcfe153a9a5 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -1144,6 +1144,7 @@ void TemplateTable::aastore() { // Get the value we will store __ ldr(r0, at_tos()); // Now store using the appropriate barrier + // Clobbers: r10, r11, r3 do_oop_store(_masm, element_address, r0, IS_ARRAY); __ b(done); @@ -1152,6 +1153,7 @@ void TemplateTable::aastore() { __ profile_null_seen(r2); // Store a null + // Clobbers: r10, r11, r3 do_oop_store(_masm, element_address, noreg, IS_ARRAY); // Pop stack arguments @@ -1890,6 +1892,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) __ mov(r19, r0); // save the nmethod + JFR_ONLY(__ enter_jfr_critical_section();) + call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin)); // r0 is OSR buffer, move it to expected parameter location @@ -1901,6 +1905,9 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) Address(rfp, frame::interpreter_frame_sender_sp_offset * wordSize)); // remove frame anchor __ leave(); + + JFR_ONLY(__ leave_jfr_critical_section();) + // Ensure compiled code always sees stack at proper alignment __ andr(sp, esp, -16); @@ -2877,6 +2884,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr __ pop(atos); if (!is_static) pop_and_check_object(obj); // Store into the field + // Clobbers: r10, r11, r3 do_oop_store(_masm, field, r0, IN_HEAP); if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_aputfield, bc, r1, true, byte_no); @@ -3072,12 +3080,12 @@ void TemplateTable::fast_storefield(TosState state) // access constant pool cache __ load_field_entry(r2, r1); - // R1: field offset, R2: field holder, R3: flags - load_resolved_field_entry(r2, r2, noreg, r1, r3); + // R1: field offset, R2: field holder, R5: flags + load_resolved_field_entry(r2, r2, noreg, r1, r5); { Label notVolatile; - __ tbz(r3, ResolvedFieldEntry::is_volatile_shift, notVolatile); + __ tbz(r5, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::StoreStore | MacroAssembler::LoadStore); __ bind(notVolatile); } @@ -3093,6 +3101,7 @@ void TemplateTable::fast_storefield(TosState state) // access field switch (bytecode()) { case Bytecodes::_fast_aputfield: + // Clobbers: r10, r11, r3 do_oop_store(_masm, field, r0, IN_HEAP); break; case Bytecodes::_fast_lputfield: @@ -3125,7 +3134,7 @@ void TemplateTable::fast_storefield(TosState state) { Label notVolatile; - __ tbz(r3, ResolvedFieldEntry::is_volatile_shift, notVolatile); + __ tbz(r5, ResolvedFieldEntry::is_volatile_shift, notVolatile); __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore); __ bind(notVolatile); } diff --git a/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp b/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp index bf9c965213c..2ec901f6a2e 100644 --- a/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vmStructs_aarch64.hpp @@ -35,8 +35,7 @@ static_field(VM_Version, _rop_protection, bool) \ static_field(VM_Version, _pac_mask, uintptr_t) -#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \ - declare_toplevel_type(VM_Version) +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) #define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index c555e393ca5..941cb254532 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -161,6 +161,9 @@ void VM_Version::initialize() { (_model == CPU_MODEL_AMPERE_1A || _model == CPU_MODEL_AMPERE_1B)) { FLAG_SET_DEFAULT(CodeEntryAlignment, 32); } + if (FLAG_IS_DEFAULT(AlwaysMergeDMB)) { + FLAG_SET_DEFAULT(AlwaysMergeDMB, false); + } } // ThunderX @@ -376,7 +379,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA3Intrinsics, true); } } - } else if (UseSHA3Intrinsics) { + } else if (UseSHA3Intrinsics && UseSIMDForSHA3Intrinsic) { warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } @@ -639,6 +642,7 @@ void VM_Version::initialize() { if (_model2) { os::snprintf_checked(buf + buf_used_len, sizeof(buf) - buf_used_len, "(0x%03x)", _model2); } + size_t features_offset = strnlen(buf, sizeof(buf)); #define ADD_FEATURE_IF_SUPPORTED(id, name, bit) \ do { \ if (VM_Version::supports_##name()) strcat(buf, ", " #name); \ @@ -646,7 +650,11 @@ void VM_Version::initialize() { CPU_FEATURE_FLAGS(ADD_FEATURE_IF_SUPPORTED) #undef ADD_FEATURE_IF_SUPPORTED - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); + + _features_string = extract_features_string(_cpu_info_string, + strnlen(_cpu_info_string, sizeof(buf)), + features_offset); } #if defined(LINUX) @@ -713,7 +721,7 @@ void VM_Version::initialize_cpu_information(void) { 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); + snprintf(_cpu_desc + desc_len, CPU_DETAILED_DESC_BUF_SIZE - desc_len, " %s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 04cf9c9c2a0..373f8da5405 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -125,6 +125,8 @@ enum Ampere_CPU_Model { decl(SHA2, sha256, 6) \ decl(CRC32, crc32, 7) \ decl(LSE, lse, 8) \ + decl(FPHP, fphp, 9) \ + decl(ASIMDHP, asimdhp, 10) \ decl(DCPOP, dcpop, 16) \ decl(SHA3, sha3, 17) \ decl(SHA512, sha512, 21) \ diff --git a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp index 11ea02621d7..714904ab3df 100644 --- a/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vtableStubs_aarch64.cpp @@ -25,6 +25,7 @@ #include "asm/assembler.inline.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "code/vtableStubs.hpp" #include "interp_masm_aarch64.hpp" @@ -196,7 +197,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { temp_reg, temp_reg2, itable_index, L_no_such_interface); // Reduce "estimate" such that "padding" does not drop below 8. - const ptrdiff_t estimate = 144; + const ptrdiff_t estimate = AOTCodeCache::is_on_for_dump() ? 148 : 144; const ptrdiff_t codesize = __ pc() - start_pc; slop_delta = (int)(estimate - codesize); slop_bytes += slop_delta; diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index f3b97d23ad3..4a0b557968c 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -1238,11 +1238,11 @@ encode %{ enc_class save_last_PC %{ // preserve mark address mark = __ inst_mark(); - debug_only(int off0 = __ offset()); + DEBUG_ONLY(int off0 = __ offset()); int ret_addr_offset = as_MachCall()->ret_addr_offset(); __ adr(LR, mark + ret_addr_offset); __ str(LR, Address(Rthread, JavaThread::last_Java_pc_offset())); - debug_only(int off1 = __ offset()); + DEBUG_ONLY(int off1 = __ offset()); assert(off1 - off0 == 2 * Assembler::InstructionSize, "correct size prediction"); // restore mark __ set_inst_mark(mark); @@ -1251,11 +1251,11 @@ encode %{ enc_class preserve_SP %{ // preserve mark address mark = __ inst_mark(); - debug_only(int off0 = __ offset()); + DEBUG_ONLY(int off0 = __ offset()); // FP is preserved across all calls, even compiled calls. // Use it to preserve SP in places where the callee might change the SP. __ mov(Rmh_SP_save, SP); - debug_only(int off1 = __ offset()); + DEBUG_ONLY(int off1 = __ offset()); assert(off1 - off0 == 4, "correct size prediction"); // restore mark __ set_inst_mark(mark); diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp index bca6c7ca30c..5683bc59d5c 100644 --- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp +++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp @@ -59,7 +59,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ call(Runtime1::entry_for(C1StubId::predicate_failed_trap_id), relocInfo::runtime_call_type); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } // Pass the array index on stack because all registers must be preserved @@ -91,7 +91,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ call(Runtime1::entry_for(C1StubId::predicate_failed_trap_id), relocInfo::runtime_call_type); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void DivByZeroStub::emit_code(LIR_Assembler* ce) { diff --git a/src/hotspot/cpu/arm/frame_arm.hpp b/src/hotspot/cpu/arm/frame_arm.hpp index dee005b8d75..dec27554a47 100644 --- a/src/hotspot/cpu/arm/frame_arm.hpp +++ b/src/hotspot/cpu/arm/frame_arm.hpp @@ -108,6 +108,9 @@ frame(intptr_t* sp, intptr_t* fp); + frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, bool allow_cb_null = false); + + void setup(address pc); void init(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc); // accessors for the instance variables diff --git a/src/hotspot/cpu/arm/frame_arm.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp index 92a48f22f8c..4be190f0504 100644 --- a/src/hotspot/cpu/arm/frame_arm.inline.hpp +++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp @@ -27,9 +27,58 @@ #include "code/codeCache.hpp" #include "code/vmreg.inline.hpp" +#include "runtime/sharedRuntime.hpp" // Inline functions for ARM frames: +#if INCLUDE_JFR + +// Static helper routines + +inline address frame::interpreter_bcp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (fp[frame::interpreter_frame_bcp_offset]); +} + +inline address frame::interpreter_return_address(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (fp[frame::return_addr_offset]); +} + +inline intptr_t* frame::interpreter_sender_sp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(fp[frame::interpreter_frame_sender_sp_offset]); +} + +inline bool frame::is_interpreter_frame_setup_at(const intptr_t* fp, const void* sp) { + assert(fp != nullptr, "invariant"); + assert(sp != nullptr, "invariant"); + return sp <= fp + frame::interpreter_frame_initial_sp_offset; +} + +inline intptr_t* frame::sender_sp(intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return fp + frame::sender_sp_offset; +} + +inline intptr_t* frame::link(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(fp[frame::link_offset]); +} + +inline address frame::return_address(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast
          (sp[-1]); +} + +inline intptr_t* frame::fp(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast(sp[-2]); +} + +#endif // INCLUDE_JFR + + // Constructors: inline frame::frame() { @@ -54,21 +103,30 @@ inline void frame::init(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, add _fp = fp; _pc = pc; assert(pc != nullptr, "no pc?"); + _on_heap = false; + _oop_map = nullptr; _cb = CodeCache::find_blob(pc); - adjust_unextended_sp(); DEBUG_ONLY(_frame_index = -1;) + setup(pc); +} + +inline void frame::setup(address pc) { + adjust_unextended_sp(); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; - assert(_cb->as_nmethod()->insts_contains_inclusive(_pc), - "original PC must be in the main code section of the compiled method (or must be immediately following it)"); _deopt_state = is_deoptimized; + assert(_cb == nullptr || _cb->as_nmethod()->insts_contains_inclusive(_pc), + "original PC must be in the main code section of the compiled method (or must be immediately following it)"); } else { - _deopt_state = not_deoptimized; + if (_cb == SharedRuntime::deopt_blob()) { + _deopt_state = is_deoptimized; + } else { + _deopt_state = not_deoptimized; + } } - _on_heap = false; - _oop_map = nullptr; } inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) { @@ -85,6 +143,22 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) { init(sp, sp, fp, pc); } +inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, bool allow_cb_null) { + intptr_t a = intptr_t(sp); + intptr_t b = intptr_t(fp); + _sp = sp; + _unextended_sp = unextended_sp; + _fp = fp; + _pc = pc; + assert(pc != nullptr, "no pc?"); + _cb = cb; + _oop_map = nullptr; + assert(_cb != nullptr || allow_cb_null, "pc: " INTPTR_FORMAT, p2i(pc)); + _on_heap = false; + DEBUG_ONLY(_frame_index = -1;) + + setup(pc); +} // Accessors diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp index 466dcc8fe66..049477cda76 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp @@ -26,7 +26,6 @@ #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp" #include "gc/g1/g1BarrierSetRuntime.hpp" -#include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1ThreadLocalData.hpp" diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp index 224a499ff54..52d71ca65c2 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp @@ -29,8 +29,8 @@ #include "memory/resourceArea.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" -#include "runtime/sharedRuntime.hpp" #include "runtime/registerMap.hpp" +#include "runtime/sharedRuntime.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" @@ -72,7 +72,7 @@ void NativeNMethodBarrier::verify() const { static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) { address barrier_address = nm->code_begin() + nm->frame_complete_offset() - entry_barrier_bytes; NativeNMethodBarrier* barrier = reinterpret_cast(barrier_address); - debug_only(barrier->verify()); + DEBUG_ONLY(barrier->verify()); return barrier; } diff --git a/src/hotspot/cpu/arm/runtime_arm.cpp b/src/hotspot/cpu/arm/runtime_arm.cpp index 20c1bc199d3..615a63eac19 100644 --- a/src/hotspot/cpu/arm/runtime_arm.cpp +++ b/src/hotspot/cpu/arm/runtime_arm.cpp @@ -54,6 +54,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Measured 8/7/03 at 660 in 32bit debug build CodeBuffer buffer(name, 2000, 512); #endif + if (buffer.blob() == nullptr) { + return nullptr; + } // bypassed when code generation useless MacroAssembler* masm = new MacroAssembler(&buffer); const Register Rublock = R6; @@ -209,6 +212,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Measured 8/7/03 at 256 in 32bit debug build const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 600, 512); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); int framesize_in_words = 2; // FP + LR diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 6dde82daaf9..8ba847e7e32 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -612,12 +612,12 @@ static void gen_c2i_adapter(MacroAssembler *masm, } -AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs, - AdapterFingerPrint* fingerprint) { +void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + AdapterHandlerEntry* handler) { address i2c_entry = __ pc(); gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); @@ -637,7 +637,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm address c2i_entry = __ pc(); gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); - return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); + handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, nullptr); + return; } diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index 30d88a4db91..db4a5c8625c 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -175,6 +175,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M case Interpreter::java_lang_math_fmaD: case Interpreter::java_lang_math_fmaF: case Interpreter::java_lang_math_tanh: + case Interpreter::java_lang_math_cbrt: // TODO: Implement intrinsic break; default: diff --git a/src/hotspot/cpu/arm/vm_version_arm_32.cpp b/src/hotspot/cpu/arm/vm_version_arm_32.cpp index 148786a55da..d0941936035 100644 --- a/src/hotspot/cpu/arm/vm_version_arm_32.cpp +++ b/src/hotspot/cpu/arm/vm_version_arm_32.cpp @@ -295,7 +295,7 @@ void VM_Version::initialize() { (has_multiprocessing_extensions() ? ", mp_ext" : "")); // buf is started with ", " or is empty - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); if (has_simd()) { if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { @@ -363,6 +363,6 @@ void VM_Version::initialize_cpu_information(void) { _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); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index b38c4ac5bae..314517fd56a 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2024 SAP SE. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -535,8 +535,12 @@ class Assembler : public AbstractAssembler { // Vector-Scalar (VSX) instruction support. LXV_OPCODE = (61u << OPCODE_SHIFT | 1u ), - LXVL_OPCODE = (31u << OPCODE_SHIFT | 269u << 1), STXV_OPCODE = (61u << OPCODE_SHIFT | 5u ), + LXVX_OPCODE = (31u << OPCODE_SHIFT | 4u << 7 | 12u << 1), + STXVX_OPCODE = (31u << OPCODE_SHIFT | 396u << 1), + LXVP_OPCODE = ( 6u << OPCODE_SHIFT ), + STXVP_OPCODE = ( 6u << OPCODE_SHIFT | 1u ), + LXVL_OPCODE = (31u << OPCODE_SHIFT | 269u << 1), STXVL_OPCODE = (31u << OPCODE_SHIFT | 397u << 1), LXVD2X_OPCODE = (31u << OPCODE_SHIFT | 844u << 1), STXVD2X_OPCODE = (31u << OPCODE_SHIFT | 972u << 1), @@ -587,6 +591,10 @@ class Assembler : public AbstractAssembler { XVRDPIC_OPCODE = (60u << OPCODE_SHIFT | 235u << 2), XVRDPIM_OPCODE = (60u << OPCODE_SHIFT | 249u << 2), XVRDPIP_OPCODE = (60u << OPCODE_SHIFT | 233u << 2), + XVMINSP_OPCODE = (60u << OPCODE_SHIFT | 200u << 3), + XVMINDP_OPCODE = (60u << OPCODE_SHIFT | 232u << 3), + XVMAXSP_OPCODE = (60u << OPCODE_SHIFT | 192u << 3), + XVMAXDP_OPCODE = (60u << OPCODE_SHIFT | 224u << 3), // Deliver A Random Number (introduced with POWER9) DARN_OPCODE = (31u << OPCODE_SHIFT | 755u << 1), @@ -695,15 +703,19 @@ class Assembler : public AbstractAssembler { VMAXSB_OPCODE = (4u << OPCODE_SHIFT | 258u ), VMAXSW_OPCODE = (4u << OPCODE_SHIFT | 386u ), VMAXSH_OPCODE = (4u << OPCODE_SHIFT | 322u ), + VMAXSD_OPCODE = (4u << OPCODE_SHIFT | 450u ), VMAXUB_OPCODE = (4u << OPCODE_SHIFT | 2u ), VMAXUW_OPCODE = (4u << OPCODE_SHIFT | 130u ), VMAXUH_OPCODE = (4u << OPCODE_SHIFT | 66u ), + VMAXUD_OPCODE = (4u << OPCODE_SHIFT | 194u ), VMINSB_OPCODE = (4u << OPCODE_SHIFT | 770u ), VMINSW_OPCODE = (4u << OPCODE_SHIFT | 898u ), VMINSH_OPCODE = (4u << OPCODE_SHIFT | 834u ), + VMINSD_OPCODE = (4u << OPCODE_SHIFT | 962u ), VMINUB_OPCODE = (4u << OPCODE_SHIFT | 514u ), VMINUW_OPCODE = (4u << OPCODE_SHIFT | 642u ), VMINUH_OPCODE = (4u << OPCODE_SHIFT | 578u ), + VMINUD_OPCODE = (4u << OPCODE_SHIFT | 706u ), VCMPEQUB_OPCODE= (4u << OPCODE_SHIFT | 6u ), VCMPEQUH_OPCODE= (4u << OPCODE_SHIFT | 70u ), @@ -1243,6 +1255,11 @@ class Assembler : public AbstractAssembler { static int vsdm( int x) { return opp_u_field(x, 23, 22); } static int vsrs_dq( int x) { return opp_u_field(x & 0x1F, 10, 6) | opp_u_field((x & 0x20) >> 5, 28, 28); } static int vsrt_dq( int x) { return vsrs_dq(x); } + static int vsrtp( int x) { + assert((x & 1) == 0, "must be even"); + return opp_u_field((x & 0x1F) >> 1, 9, 6) | opp_u_field((x & 0x20) >> 5, 10, 10); + } + static int vsrsp( int x) { return vsrtp(x); } static int vsra( VectorSRegister r) { return vsra(r->encoding());} static int vsrb( VectorSRegister r) { return vsrb(r->encoding());} @@ -1251,6 +1268,8 @@ class Assembler : public AbstractAssembler { static int vsrt( VectorSRegister r) { return vsrt(r->encoding());} static int vsrs_dq(VectorSRegister r) { return vsrs_dq(r->encoding());} static int vsrt_dq(VectorSRegister r) { return vsrt_dq(r->encoding());} + static int vsrtp( VectorSRegister r) { return vsrtp(r->encoding());} + static int vsrsp( VectorSRegister r) { return vsrsp(r->encoding());} static int vsplt_uim( int x) { return opp_u_field(x, 15, 12); } // for vsplt* instructions static int vsplti_sim(int x) { return opp_u_field(x, 15, 11); } // for vsplti* instructions @@ -1997,7 +2016,7 @@ class Assembler : public AbstractAssembler { // Wait instructions for polling. Attention: May result in SIGILL. inline void wait(); - inline void waitrsv(); // >=Power7 + inline void waitrsv(); // atomics inline void lbarx_unchecked(Register d, Register a, Register b, int eh1 = 0); // >=Power 8 @@ -2005,7 +2024,6 @@ class Assembler : public AbstractAssembler { inline void lwarx_unchecked(Register d, Register a, Register b, int eh1 = 0); inline void ldarx_unchecked(Register d, Register a, Register b, int eh1 = 0); inline void lqarx_unchecked(Register d, Register a, Register b, int eh1 = 0); // >=Power 8 - inline bool lxarx_hint_exclusive_access(); inline void lbarx( Register d, Register a, Register b, bool hint_exclusive_access = false); inline void lharx( Register d, Register a, Register b, bool hint_exclusive_access = false); inline void lwarx( Register d, Register a, Register b, bool hint_exclusive_access = false); @@ -2028,7 +2046,6 @@ class Assembler : public AbstractAssembler { inline void smt_prio_low(); inline void smt_prio_medium_low(); inline void smt_prio_medium(); - // >= Power7 inline void smt_yield(); inline void smt_mdoio(); inline void smt_mdoom(); @@ -2293,15 +2310,19 @@ class Assembler : public AbstractAssembler { inline void vmaxsb( VectorRegister d, VectorRegister a, VectorRegister b); inline void vmaxsw( VectorRegister d, VectorRegister a, VectorRegister b); inline void vmaxsh( VectorRegister d, VectorRegister a, VectorRegister b); + inline void vmaxsd( VectorRegister d, VectorRegister a, VectorRegister b); inline void vmaxub( VectorRegister d, VectorRegister a, VectorRegister b); inline void vmaxuw( VectorRegister d, VectorRegister a, VectorRegister b); inline void vmaxuh( VectorRegister d, VectorRegister a, VectorRegister b); + inline void vmaxud( VectorRegister d, VectorRegister a, VectorRegister b); inline void vminsb( VectorRegister d, VectorRegister a, VectorRegister b); inline void vminsw( VectorRegister d, VectorRegister a, VectorRegister b); inline void vminsh( VectorRegister d, VectorRegister a, VectorRegister b); + inline void vminsd( VectorRegister d, VectorRegister a, VectorRegister b); inline void vminub( VectorRegister d, VectorRegister a, VectorRegister b); inline void vminuw( VectorRegister d, VectorRegister a, VectorRegister b); inline void vminuh( VectorRegister d, VectorRegister a, VectorRegister b); + inline void vminud( VectorRegister d, VectorRegister a, VectorRegister b); inline void vcmpequb( VectorRegister d, VectorRegister a, VectorRegister b); inline void vcmpequh( VectorRegister d, VectorRegister a, VectorRegister b); inline void vcmpequw( VectorRegister d, VectorRegister a, VectorRegister b); @@ -2356,14 +2377,24 @@ class Assembler : public AbstractAssembler { inline void mfvscr( VectorRegister d); // Vector-Scalar (VSX) instructions. - inline void lxv( VectorSRegister d, int si16, Register a); - inline void stxv( VectorSRegister d, int si16, Register a); - inline void lxvl( VectorSRegister d, Register a, Register b); - inline void stxvl( VectorSRegister d, Register a, Register b); + // Power8 inline void lxvd2x( VectorSRegister d, Register a); inline void lxvd2x( VectorSRegister d, Register a, Register b); inline void stxvd2x( VectorSRegister d, Register a); inline void stxvd2x( VectorSRegister d, Register a, Register b); + + // Power9 + inline void lxv( VectorSRegister d, int si16, Register a); + inline void stxv( VectorSRegister d, int si16, Register a); + inline void lxvx( VectorSRegister d, Register a, Register b); + inline void stxvx( VectorSRegister d, Register a, Register b); + inline void lxvl( VectorSRegister d, Register a, Register b); + inline void stxvl( VectorSRegister d, Register a, Register b); + + // Power10 + inline void lxvp( VectorSRegister d, int si16, Register a); + inline void stxvp( VectorSRegister d, int si16, Register a); + inline void mtvrwz( VectorRegister d, Register a); inline void mfvrwz( Register a, VectorRegister d); inline void mtvrd( VectorRegister d, Register a); @@ -2416,6 +2447,12 @@ class Assembler : public AbstractAssembler { inline void xvrdpim( VectorSRegister d, VectorSRegister b); inline void xvrdpip( VectorSRegister d, VectorSRegister b); + // The following functions do not match exactly the Java.math semantics. + inline void xvminsp( VectorSRegister d, VectorSRegister a, VectorSRegister b); + inline void xvmindp( VectorSRegister d, VectorSRegister a, VectorSRegister b); + inline void xvmaxsp( VectorSRegister d, VectorSRegister a, VectorSRegister b); + inline void xvmaxdp( VectorSRegister d, VectorSRegister a, VectorSRegister b); + // VSX Extended Mnemonics inline void xxspltd( VectorSRegister d, VectorSRegister a, int x); inline void xxmrghd( VectorSRegister d, VectorSRegister a, VectorSRegister b); @@ -2480,6 +2517,9 @@ class Assembler : public AbstractAssembler { inline void std( Register d, int si16); inline void stdbrx( Register d, Register s2); + inline void lxvx( VectorSRegister d, Register b); + inline void stxvx(VectorSRegister d, Register b); + // PPC 2, section 3.2.1 Instruction Cache Instructions inline void icbi( Register s2); // PPC 2, section 3.2.2 Data Cache Instructions diff --git a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp index 4fb8c5c4198..792e5d6d5ad 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp @@ -208,8 +208,7 @@ inline void Assembler::cmpldi(ConditionRegister crx, Register a, int ui16) { A inline void Assembler::cmplw( ConditionRegister crx, Register a, Register b) { Assembler::cmpl( crx, 0, a, b); } inline void Assembler::cmpld( ConditionRegister crx, Register a, Register b) { Assembler::cmpl( crx, 1, a, b); } -inline void Assembler::isel(Register d, Register a, Register b, int c) { guarantee(VM_Version::has_isel(), "opcode not supported on this hardware"); - emit_int32(ISEL_OPCODE | rt(d) | ra(a) | rb(b) | bc(c)); } +inline void Assembler::isel(Register d, Register a, Register b, int c) { emit_int32(ISEL_OPCODE | rt(d) | ra(a) | rb(b) | bc(c)); } // PPC 1, section 3.3.11, Fixed-Point Logical Instructions inline void Assembler::andi_( Register a, Register s, int ui16) { emit_int32(ANDI_OPCODE | rta(a) | rs(s) | uimm(ui16, 16)); } @@ -701,12 +700,11 @@ inline void Assembler::lharx_unchecked(Register d, Register a, Register b, int e inline void Assembler::lwarx_unchecked(Register d, Register a, Register b, int eh1) { emit_int32( LWARX_OPCODE | rt(d) | ra0mem(a) | rb(b) | eh(eh1)); } inline void Assembler::ldarx_unchecked(Register d, Register a, Register b, int eh1) { emit_int32( LDARX_OPCODE | rt(d) | ra0mem(a) | rb(b) | eh(eh1)); } inline void Assembler::lqarx_unchecked(Register d, Register a, Register b, int eh1) { emit_int32( LQARX_OPCODE | rt(d) | ra0mem(a) | rb(b) | eh(eh1)); } -inline bool Assembler::lxarx_hint_exclusive_access() { return VM_Version::has_lxarxeh(); } -inline void Assembler::lbarx( Register d, Register a, Register b, bool hint_exclusive_access) { lbarx_unchecked(d, a, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } -inline void Assembler::lharx( Register d, Register a, Register b, bool hint_exclusive_access) { lharx_unchecked(d, a, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } -inline void Assembler::lwarx( Register d, Register a, Register b, bool hint_exclusive_access) { lwarx_unchecked(d, a, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } -inline void Assembler::ldarx( Register d, Register a, Register b, bool hint_exclusive_access) { ldarx_unchecked(d, a, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } -inline void Assembler::lqarx( Register d, Register a, Register b, bool hint_exclusive_access) { lqarx_unchecked(d, a, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lbarx( Register d, Register a, Register b, bool hint_exclusive_access) { lbarx_unchecked(d, a, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lharx( Register d, Register a, Register b, bool hint_exclusive_access) { lharx_unchecked(d, a, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lwarx( Register d, Register a, Register b, bool hint_exclusive_access) { lwarx_unchecked(d, a, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::ldarx( Register d, Register a, Register b, bool hint_exclusive_access) { ldarx_unchecked(d, a, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lqarx( Register d, Register a, Register b, bool hint_exclusive_access) { lqarx_unchecked(d, a, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } inline void Assembler::stbcx_(Register s, Register a, Register b) { emit_int32( STBCX_OPCODE | rs(s) | ra0mem(a) | rb(b) | rc(1)); } inline void Assembler::sthcx_(Register s, Register a, Register b) { emit_int32( STHCX_OPCODE | rs(s) | ra0mem(a) | rb(b) | rc(1)); } inline void Assembler::stwcx_(Register s, Register a, Register b) { emit_int32( STWCX_OPCODE | rs(s) | ra0mem(a) | rb(b) | rc(1)); } @@ -775,12 +773,9 @@ inline void Assembler::frim( FloatRegister d, FloatRegister b) { emit_int32( FRI //inline void Assembler::mffgpr( FloatRegister d, Register b) { emit_int32( MFFGPR_OPCODE | frt(d) | rb(b) | rc(0)); } //inline void Assembler::mftgpr( Register d, FloatRegister b) { emit_int32( MFTGPR_OPCODE | rt(d) | frb(b) | rc(0)); } // add cmpb and popcntb to detect ppc power version. -inline void Assembler::cmpb( Register a, Register s, Register b) { guarantee(VM_Version::has_cmpb(), "opcode not supported on this hardware"); - emit_int32( CMPB_OPCODE | rta(a) | rs(s) | rb(b) | rc(0)); } -inline void Assembler::popcntb(Register a, Register s) { guarantee(VM_Version::has_popcntb(), "opcode not supported on this hardware"); - emit_int32( POPCNTB_OPCODE | rta(a) | rs(s)); }; -inline void Assembler::popcntw(Register a, Register s) { guarantee(VM_Version::has_popcntw(), "opcode not supported on this hardware"); - emit_int32( POPCNTW_OPCODE | rta(a) | rs(s)); }; +inline void Assembler::cmpb( Register a, Register s, Register b) { emit_int32( CMPB_OPCODE | rta(a) | rs(s) | rb(b) | rc(0)); } +inline void Assembler::popcntb(Register a, Register s) { emit_int32( POPCNTB_OPCODE | rta(a) | rs(s)); }; +inline void Assembler::popcntw(Register a, Register s) { emit_int32( POPCNTW_OPCODE | rta(a) | rs(s)); }; inline void Assembler::popcntd(Register a, Register s) { emit_int32( POPCNTD_OPCODE | rta(a) | rs(s)); }; inline void Assembler::fneg( FloatRegister d, FloatRegister b) { emit_int32( FNEG_OPCODE | frt(d) | frb(b) | rc(0)); } @@ -835,17 +830,14 @@ inline void Assembler::fctidz(FloatRegister d, FloatRegister b) { emit_int32( FC inline void Assembler::fctiw( FloatRegister d, FloatRegister b) { emit_int32( FCTIW_OPCODE | frt(d) | frb(b) | rc(0)); } inline void Assembler::fctiwz(FloatRegister d, FloatRegister b) { emit_int32( FCTIWZ_OPCODE | frt(d) | frb(b) | rc(0)); } inline void Assembler::fcfid( FloatRegister d, FloatRegister b) { emit_int32( FCFID_OPCODE | frt(d) | frb(b) | rc(0)); } -inline void Assembler::fcfids(FloatRegister d, FloatRegister b) { guarantee(VM_Version::has_fcfids(), "opcode not supported on this hardware"); - emit_int32( FCFIDS_OPCODE | frt(d) | frb(b) | rc(0)); } +inline void Assembler::fcfids(FloatRegister d, FloatRegister b) { emit_int32( FCFIDS_OPCODE | frt(d) | frb(b) | rc(0)); } // PPC 1, section 4.6.7 Floating-Point Compare Instructions inline void Assembler::fcmpu( ConditionRegister crx, FloatRegister a, FloatRegister b) { emit_int32( FCMPU_OPCODE | bf(crx) | fra(a) | frb(b)); } // PPC 1, section 5.2.1 Floating-Point Arithmetic Instructions -inline void Assembler::fsqrt( FloatRegister d, FloatRegister b) { guarantee(VM_Version::has_fsqrt(), "opcode not supported on this hardware"); - emit_int32( FSQRT_OPCODE | frt(d) | frb(b) | rc(0)); } -inline void Assembler::fsqrts(FloatRegister d, FloatRegister b) { guarantee(VM_Version::has_fsqrts(), "opcode not supported on this hardware"); - emit_int32( FSQRTS_OPCODE | frt(d) | frb(b) | rc(0)); } +inline void Assembler::fsqrt( FloatRegister d, FloatRegister b) { emit_int32( FSQRT_OPCODE | frt(d) | frb(b) | rc(0)); } +inline void Assembler::fsqrts(FloatRegister d, FloatRegister b) { emit_int32( FSQRTS_OPCODE | frt(d) | frb(b) | rc(0)); } // Vector instructions for >= Power6. inline void Assembler::lvebx( VectorRegister d, Register s1, Register s2) { emit_int32( LVEBX_OPCODE | vrt(d) | ra0mem(s1) | rb(s2)); } @@ -862,8 +854,12 @@ inline void Assembler::lvsl( VectorRegister d, Register s1, Register s2) { emit inline void Assembler::lvsr( VectorRegister d, Register s1, Register s2) { emit_int32( LVSR_OPCODE | vrt(d) | ra0mem(s1) | rb(s2)); } // Vector-Scalar (VSX) instructions. -inline void Assembler::lxv( VectorSRegister d, int ui16, Register a) { assert(is_aligned(ui16, 16), "displacement must be a multiple of 16"); emit_int32( LXV_OPCODE | vsrt_dq(d) | ra0mem(a) | uimm(ui16, 16)); } -inline void Assembler::stxv( VectorSRegister d, int ui16, Register a) { assert(is_aligned(ui16, 16), "displacement must be a multiple of 16"); emit_int32( STXV_OPCODE | vsrs_dq(d) | ra0mem(a) | uimm(ui16, 16)); } +inline void Assembler::lxv( VectorSRegister d, int si16, Register a) { assert(is_aligned(si16, 16), "displacement must be a multiple of 16"); emit_int32( LXV_OPCODE | vsrt_dq(d) | ra0mem(a) | simm(si16, 16)); } +inline void Assembler::stxv( VectorSRegister d, int si16, Register a) { assert(is_aligned(si16, 16), "displacement must be a multiple of 16"); emit_int32( STXV_OPCODE | vsrs_dq(d) | ra0mem(a) | simm(si16, 16)); } +inline void Assembler::lxvx( VectorSRegister d, Register a, Register b) { emit_int32( LXVX_OPCODE | vsrt(d) | ra0mem(a) | rb(b)); } +inline void Assembler::stxvx( VectorSRegister d, Register a, Register b) { emit_int32( STXVX_OPCODE | vsrs(d) | ra0mem(a) | rb(b)); } +inline void Assembler::lxvp( VectorSRegister d, int si16, Register a) { assert(is_aligned(si16, 16), "displacement must be a multiple of 16"); emit_int32( LXVP_OPCODE | vsrtp(d) | ra0mem(a) | simm(si16, 16)); } +inline void Assembler::stxvp( VectorSRegister d, int si16, Register a) { assert(is_aligned(si16, 16), "displacement must be a multiple of 16"); emit_int32( STXVP_OPCODE | vsrsp(d) | ra0mem(a) | simm(si16, 16)); } inline void Assembler::lxvl( VectorSRegister d, Register s1, Register b) { emit_int32( LXVL_OPCODE | vsrt(d) | ra0mem(s1) | rb(b)); } inline void Assembler::stxvl( VectorSRegister d, Register s1, Register b) { emit_int32( STXVL_OPCODE | vsrt(d) | ra0mem(s1) | rb(b)); } inline void Assembler::lxvd2x( VectorSRegister d, Register s1) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra(0) | rb(s1)); } @@ -912,6 +908,11 @@ inline void Assembler::xvrdpic( VectorSRegister d, VectorSRegister b) inline void Assembler::xvrdpim( VectorSRegister d, VectorSRegister b) { emit_int32( XVRDPIM_OPCODE | vsrt(d) | vsrb(b)); } inline void Assembler::xvrdpip( VectorSRegister d, VectorSRegister b) { emit_int32( XVRDPIP_OPCODE | vsrt(d) | vsrb(b)); } +inline void Assembler::xvminsp(VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XVMINSP_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); } +inline void Assembler::xvmindp(VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XVMINDP_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); } +inline void Assembler::xvmaxsp(VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XVMAXSP_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); } +inline void Assembler::xvmaxdp(VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XVMAXDP_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); } + inline void Assembler::mtvrd( VectorRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); } inline void Assembler::mfvrd( Register a, VectorRegister d) { emit_int32( MFVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); } inline void Assembler::mtvrwz( VectorRegister d, Register a) { emit_int32( MTVSRWZ_OPCODE | vsrt(d->to_vsr()) | ra(a)); } @@ -1026,15 +1027,19 @@ inline void Assembler::vavguh( VectorRegister d, VectorRegister a, VectorRegist inline void Assembler::vmaxsb( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMAXSB_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vmaxsw( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMAXSW_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vmaxsh( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMAXSH_OPCODE | vrt(d) | vra(a) | vrb(b)); } +inline void Assembler::vmaxsd( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMAXSD_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vmaxub( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMAXUB_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vmaxuw( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMAXUW_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vmaxuh( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMAXUH_OPCODE | vrt(d) | vra(a) | vrb(b)); } +inline void Assembler::vmaxud( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMAXUD_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vminsb( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMINSB_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vminsw( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMINSW_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vminsh( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMINSH_OPCODE | vrt(d) | vra(a) | vrb(b)); } +inline void Assembler::vminsd( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMINSD_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vminub( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMINUB_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vminuw( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMINUW_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vminuh( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMINUH_OPCODE | vrt(d) | vra(a) | vrb(b)); } +inline void Assembler::vminud( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VMINUD_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vcmpequb(VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VCMPEQUB_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(0)); } inline void Assembler::vcmpequh(VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VCMPEQUH_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(0)); } inline void Assembler::vcmpequw(VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VCMPEQUW_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(0)); } @@ -1053,8 +1058,7 @@ inline void Assembler::vcmpgtsw_(VectorRegister d,VectorRegister a, VectorRegist inline void Assembler::vcmpgtub_(VectorRegister d,VectorRegister a, VectorRegister b) { emit_int32( VCMPGTUB_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(1)); } inline void Assembler::vcmpgtuh_(VectorRegister d,VectorRegister a, VectorRegister b) { emit_int32( VCMPGTUH_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(1)); } inline void Assembler::vcmpgtuw_(VectorRegister d,VectorRegister a, VectorRegister b) { emit_int32( VCMPGTUW_OPCODE | vrt(d) | vra(a) | vrb(b) | vcmp_rc(1)); } -inline void Assembler::vand( VectorRegister d, VectorRegister a, VectorRegister b) { guarantee(VM_Version::has_vand(), "opcode not supported on this hardware"); - emit_int32( VAND_OPCODE | vrt(d) | vra(a) | vrb(b)); } +inline void Assembler::vand( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VAND_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vandc( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VANDC_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vnor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VNOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } inline void Assembler::vor( VectorRegister d, VectorRegister a, VectorRegister b) { emit_int32( VOR_OPCODE | vrt(d) | vra(a) | vrb(b)); } @@ -1140,6 +1144,10 @@ inline void Assembler::std( Register d, int si16 ) { emit_int32( STD_OPCODE inline void Assembler::stdx( Register d, Register s2) { emit_int32( STDX_OPCODE | rs(d) | rb(s2));} inline void Assembler::stdbrx(Register d, Register s2){ emit_int32(STDBRX_OPCODE| rs(d) | rb(s2));} +inline void Assembler::lxvx( VectorSRegister d, Register b) { emit_int32( LXVX_OPCODE | vsrt(d) | rb(b)); } +inline void Assembler::stxvx(VectorSRegister d, Register b) { emit_int32( STXVX_OPCODE | vsrs(d) | rb(b)); } + + // ra0 version inline void Assembler::icbi( Register s2) { emit_int32( ICBI_OPCODE | rb(s2) ); } //inline void Assembler::dcba( Register s2) { emit_int32( DCBA_OPCODE | rb(s2) ); } @@ -1158,11 +1166,11 @@ inline void Assembler::lharx_unchecked(Register d, Register b, int eh1) inline void Assembler::lwarx_unchecked(Register d, Register b, int eh1) { emit_int32( LWARX_OPCODE | rt(d) | rb(b) | eh(eh1)); } inline void Assembler::ldarx_unchecked(Register d, Register b, int eh1) { emit_int32( LDARX_OPCODE | rt(d) | rb(b) | eh(eh1)); } inline void Assembler::lqarx_unchecked(Register d, Register b, int eh1) { emit_int32( LQARX_OPCODE | rt(d) | rb(b) | eh(eh1)); } -inline void Assembler::lbarx( Register d, Register b, bool hint_exclusive_access){ lbarx_unchecked(d, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } -inline void Assembler::lharx( Register d, Register b, bool hint_exclusive_access){ lharx_unchecked(d, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } -inline void Assembler::lwarx( Register d, Register b, bool hint_exclusive_access){ lwarx_unchecked(d, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } -inline void Assembler::ldarx( Register d, Register b, bool hint_exclusive_access){ ldarx_unchecked(d, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } -inline void Assembler::lqarx( Register d, Register b, bool hint_exclusive_access){ lqarx_unchecked(d, b, (hint_exclusive_access && lxarx_hint_exclusive_access() && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lbarx( Register d, Register b, bool hint_exclusive_access){ lbarx_unchecked(d, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lharx( Register d, Register b, bool hint_exclusive_access){ lharx_unchecked(d, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lwarx( Register d, Register b, bool hint_exclusive_access){ lwarx_unchecked(d, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::ldarx( Register d, Register b, bool hint_exclusive_access){ ldarx_unchecked(d, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } +inline void Assembler::lqarx( Register d, Register b, bool hint_exclusive_access){ lqarx_unchecked(d, b, (hint_exclusive_access && UseExtendedLoadAndReserveInstructionsPPC64) ? 1 : 0); } inline void Assembler::stbcx_(Register s, Register b) { emit_int32( STBCX_OPCODE | rs(s) | rb(b) | rc(1)); } inline void Assembler::sthcx_(Register s, Register b) { emit_int32( STHCX_OPCODE | rs(s) | rb(b) | rc(1)); } inline void Assembler::stwcx_(Register s, Register b) { emit_int32( STWCX_OPCODE | rs(s) | rb(b) | rc(1)); } diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp index d4f5faa29a8..b1cdf38daf3 100644 --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -41,25 +41,8 @@ void C1SafepointPollStub::emit_code(LIR_Assembler* ce) { if (UseSIGTRAP) { DEBUG_ONLY( __ should_not_reach_here("C1SafepointPollStub::emit_code"); ) } else { - assert(SharedRuntime::polling_page_return_handler_blob() != nullptr, - "polling page return stub not created yet"); - address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point(); - __ bind(_entry); - // Using pc relative address computation. - { - Label next_pc; - __ bl(next_pc); - __ bind(next_pc); - } - int current_offset = __ offset(); - __ mflr(R12); - __ add_const_optimized(R12, R12, safepoint_offset() - current_offset); - __ std(R12, in_bytes(JavaThread::saved_exception_pc_offset()), R16_thread); - - __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); - __ mtctr(R0); - __ bctr(); + __ jump_to_polling_page_return_handler_blob(safepoint_offset()); } } @@ -74,7 +57,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); return; } @@ -98,7 +81,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } @@ -115,7 +98,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } @@ -156,7 +139,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } @@ -179,7 +162,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { __ bctrl(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } @@ -193,7 +176,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { __ mtctr(R0); __ bctrl(); ce->add_call_info_here(_info); - debug_only( __ illtrap(); ) + DEBUG_ONLY( __ illtrap(); ) } @@ -441,7 +424,7 @@ void DeoptimizeStub::emit_code(LIR_Assembler* ce) { __ load_const_optimized(R0, _trap_request); // Pass trap request in R0. __ bctrl(); ce->add_call_info_here(_info); - debug_only(__ illtrap()); + DEBUG_ONLY(__ illtrap()); } diff --git a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp index e4684613e25..8ce324a570b 100644 --- a/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_FrameMap_ppc.cpp @@ -189,7 +189,7 @@ LIR_Opr FrameMap::_caller_save_fpu_regs[] = {}; FloatRegister FrameMap::nr2floatreg (int rnr) { assert(_init_done, "tables not initialized"); - debug_only(fpu_range_check(rnr);) + DEBUG_ONLY(fpu_range_check(rnr);) return _fpu_regs[rnr]; } diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index c678f409c49..7dfde40364e 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -538,48 +538,32 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { __ extsh(dst->as_register(), src->as_register()); break; } - case Bytecodes::_i2d: + case Bytecodes::_i2d:{ + FloatRegister rdst = dst->as_double_reg(); + // move src to dst register + __ mtfprwa(rdst, src->as_register()); + __ fcfid(rdst, rdst); + break; + } case Bytecodes::_l2d: { - bool src_in_memory = !VM_Version::has_mtfprd(); FloatRegister rdst = dst->as_double_reg(); - FloatRegister rsrc; - if (src_in_memory) { - rsrc = src->as_double_reg(); // via mem - } else { - // move src to dst register - if (code == Bytecodes::_i2d) { - __ mtfprwa(rdst, src->as_register()); - } else { - __ mtfprd(rdst, src->as_register_lo()); - } - rsrc = rdst; - } - __ fcfid(rdst, rsrc); + // move src to dst register + __ mtfprd(rdst, src->as_register_lo()); + __ fcfid(rdst, rdst); + break; + } + case Bytecodes::_i2f:{ + FloatRegister rdst = dst->as_float_reg(); + // move src to dst register + __ mtfprwa(rdst, src->as_register()); + __ fcfids(rdst, rdst); break; } - case Bytecodes::_i2f: case Bytecodes::_l2f: { - bool src_in_memory = !VM_Version::has_mtfprd(); FloatRegister rdst = dst->as_float_reg(); - FloatRegister rsrc; - if (src_in_memory) { - rsrc = src->as_double_reg(); // via mem - } else { - // move src to dst register - if (code == Bytecodes::_i2f) { - __ mtfprwa(rdst, src->as_register()); - } else { - __ mtfprd(rdst, src->as_register_lo()); - } - rsrc = rdst; - } - if (VM_Version::has_fcfids()) { - __ fcfids(rdst, rsrc); - } else { - assert(code == Bytecodes::_i2f, "fcfid+frsp needs fixup code to avoid rounding incompatibility"); - __ fcfid(rdst, rsrc); - __ frsp(rdst, rdst); - } + // move src to dst register + __ mtfprd(rdst, src->as_register_lo()); + __ fcfids(rdst, rdst); break; } case Bytecodes::_f2d: { @@ -592,49 +576,27 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { } case Bytecodes::_d2i: case Bytecodes::_f2i: { - bool dst_in_memory = !VM_Version::has_mtfprd(); FloatRegister rsrc = (code == Bytecodes::_d2i) ? src->as_double_reg() : src->as_float_reg(); - Address addr = dst_in_memory ? frame_map()->address_for_slot(dst->double_stack_ix()) : Address(); Label L; // Result must be 0 if value is NaN; test by comparing value to itself. __ fcmpu(CR0, rsrc, rsrc); - if (dst_in_memory) { - __ li(R0, 0); // 0 in case of NAN - __ std(R0, addr); - } else { - __ li(dst->as_register(), 0); - } + __ li(dst->as_register(), 0); __ bso(CR0, L); __ fctiwz(rsrc, rsrc); // USE_KILL - if (dst_in_memory) { - __ stfd(rsrc, addr.disp(), addr.base()); - } else { - __ mffprd(dst->as_register(), rsrc); - } + __ mffprd(dst->as_register(), rsrc); __ bind(L); break; } case Bytecodes::_d2l: case Bytecodes::_f2l: { - bool dst_in_memory = !VM_Version::has_mtfprd(); FloatRegister rsrc = (code == Bytecodes::_d2l) ? src->as_double_reg() : src->as_float_reg(); - Address addr = dst_in_memory ? frame_map()->address_for_slot(dst->double_stack_ix()) : Address(); Label L; // Result must be 0 if value is NaN; test by comparing value to itself. __ fcmpu(CR0, rsrc, rsrc); - if (dst_in_memory) { - __ li(R0, 0); // 0 in case of NAN - __ std(R0, addr); - } else { - __ li(dst->as_register_lo(), 0); - } + __ li(dst->as_register_lo(), 0); __ bso(CR0, L); __ fctidz(rsrc, rsrc); // USE_KILL - if (dst_in_memory) { - __ stfd(rsrc, addr.disp(), addr.base()); - } else { - __ mffprd(dst->as_register_lo(), rsrc); - } + __ mffprd(dst->as_register_lo(), rsrc); __ bind(L); break; } @@ -1581,8 +1543,7 @@ void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, L default: ShouldNotReachHere(); } - // Try to use isel on >=Power7. - if (VM_Version::has_isel() && result->is_cpu_register()) { + if (result->is_cpu_register()) { bool o1_is_reg = opr1->is_cpu_register(), o2_is_reg = opr2->is_cpu_register(); const Register result_reg = result->is_single_cpu() ? result->as_register() : result->as_register_lo(); diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index b9c8ced8ef1..815e5c83a1b 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -714,14 +714,12 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { } case vmIntrinsics::_dsqrt: case vmIntrinsics::_dsqrt_strict: { - if (VM_Version::has_fsqrt()) { - assert(x->number_of_arguments() == 1, "wrong type"); - LIRItem value(x->argument_at(0), this); - value.load_item(); - LIR_Opr dst = rlock_result(x); - __ sqrt(value.result(), dst, LIR_OprFact::illegalOpr); - break; - } // else fallthru + assert(x->number_of_arguments() == 1, "wrong type"); + LIRItem value(x->argument_at(0), this); + value.load_item(); + LIR_Opr dst = rlock_result(x); + __ sqrt(value.result(), dst, LIR_OprFact::illegalOpr); + break; } case vmIntrinsics::_dsin: // fall through case vmIntrinsics::_dcos: // fall through @@ -733,10 +731,6 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { address runtime_entry = nullptr; switch (x->id()) { - case vmIntrinsics::_dsqrt: - case vmIntrinsics::_dsqrt_strict: - runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); - break; case vmIntrinsics::_dsin: runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); break; @@ -819,78 +813,6 @@ void LIRGenerator::do_ArrayCopy(Intrinsic* x) { // _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f // _i2b, _i2c, _i2s void LIRGenerator::do_Convert(Convert* x) { - if (!VM_Version::has_mtfprd()) { - switch (x->op()) { - - // int -> float: force spill - case Bytecodes::_l2f: { - if (!VM_Version::has_fcfids()) { // fcfids is >= Power7 only - // fcfid+frsp needs fixup code to avoid rounding incompatibility. - address entry = CAST_FROM_FN_PTR(address, SharedRuntime::l2f); - LIR_Opr result = call_runtime(x->value(), entry, x->type(), nullptr); - set_result(x, result); - return; - } // else fallthru - } - case Bytecodes::_l2d: { - LIRItem value(x->value(), this); - LIR_Opr reg = rlock_result(x); - value.load_item(); - LIR_Opr tmp = force_to_spill(value.result(), T_DOUBLE); - __ convert(x->op(), tmp, reg); - return; - } - case Bytecodes::_i2f: - case Bytecodes::_i2d: { - LIRItem value(x->value(), this); - LIR_Opr reg = rlock_result(x); - value.load_item(); - // Convert i2l first. - LIR_Opr tmp1 = new_register(T_LONG); - __ convert(Bytecodes::_i2l, value.result(), tmp1); - LIR_Opr tmp2 = force_to_spill(tmp1, T_DOUBLE); - __ convert(x->op(), tmp2, reg); - return; - } - - // float -> int: result will be stored - case Bytecodes::_f2l: - case Bytecodes::_d2l: { - LIRItem value(x->value(), this); - LIR_Opr reg = rlock_result(x); - value.set_destroys_register(); // USE_KILL - value.load_item(); - set_vreg_flag(reg, must_start_in_memory); - __ convert(x->op(), value.result(), reg); - return; - } - case Bytecodes::_f2i: - case Bytecodes::_d2i: { - LIRItem value(x->value(), this); - LIR_Opr reg = rlock_result(x); - value.set_destroys_register(); // USE_KILL - value.load_item(); - // Convert l2i afterwards. - LIR_Opr tmp1 = new_register(T_LONG); - set_vreg_flag(tmp1, must_start_in_memory); - __ convert(x->op(), value.result(), tmp1); - __ convert(Bytecodes::_l2i, tmp1, reg); - return; - } - - // Within same category: just register conversions. - case Bytecodes::_i2b: - case Bytecodes::_i2c: - case Bytecodes::_i2s: - case Bytecodes::_i2l: - case Bytecodes::_l2i: - case Bytecodes::_f2d: - case Bytecodes::_d2f: - break; - - default: ShouldNotReachHere(); - } - } // Register conversion. LIRItem value(x->value(), this); diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index ac9c5984de0..77d3653aefd 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -83,16 +83,17 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox // Save object being locked into the BasicObjectLock... std(Roop, in_bytes(BasicObjectLock::obj_offset()), Rbox); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(Rscratch, Roop); - lbz(Rscratch, in_bytes(Klass::misc_flags_offset()), Rscratch); - testbitdi(CR0, R0, Rscratch, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(CR0, slow_int); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(Rscratch, Roop); + lbz(Rscratch, in_bytes(Klass::misc_flags_offset()), Rscratch); + testbitdi(CR0, R0, Rscratch, exact_log2(KlassFlags::_misc_is_value_based_class)); + bne(CR0, slow_int); + } + // ... and mark it unlocked. ori(Rmark, Rmark, markWord::unlocked_value); diff --git a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp index 79b129c08ae..f1afbdd3a1d 100644 --- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp @@ -162,8 +162,7 @@ static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { Register r = as_Register(i); if (FrameMap::reg_needs_save(r)) { int sp_offset = cpu_reg_save_offsets[i]; - oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset>>2), r->as_VMReg()); - oop_map->set_callee_saved(VMRegImpl::stack2reg((sp_offset>>2) + 1), r->as_VMReg()->next()); + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset >> 2), r->as_VMReg()); } } @@ -171,8 +170,7 @@ static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { for (i = 0; i < FrameMap::nof_fpu_regs; i++) { FloatRegister r = as_FloatRegister(i); int sp_offset = fpu_reg_save_offsets[i]; - oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset>>2), r->as_VMReg()); - oop_map->set_callee_saved(VMRegImpl::stack2reg((sp_offset>>2) + 1), r->as_VMReg()->next()); + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset >> 2), r->as_VMReg()); } } diff --git a/src/hotspot/cpu/ppc/c2_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c2_CodeStubs_ppc.cpp index 484e0fd0196..632ad87cd4c 100644 --- a/src/hotspot/cpu/ppc/c2_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c2_CodeStubs_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, 2022, SAP SE. All rights reserved. + * Copyright (c) 2021, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,26 +34,8 @@ int C2SafepointPollStub::max_size() const { } void C2SafepointPollStub::emit(C2_MacroAssembler& masm) { - assert(SharedRuntime::polling_page_return_handler_blob() != nullptr, - "polling page return stub not created yet"); - address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point(); - __ bind(entry()); - // Using pc relative address computation. - { - Label next_pc; - __ bl(next_pc); - __ bind(next_pc); - } - int current_offset = __ offset(); // Code size should not depend on offset: see _stub_size computation in output.cpp - __ load_const32(R12, _safepoint_offset - current_offset); - __ mflr(R0); - __ add(R12, R12, R0); - __ std(R12, in_bytes(JavaThread::saved_exception_pc_offset()), R16_thread); - - __ add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); - __ mtctr(R0); - __ bctr(); + __ jump_to_polling_page_return_handler_blob(_safepoint_offset, true); } #undef __ diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp index cddf08eceb1..eab3df03fde 100644 --- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp @@ -234,14 +234,7 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, // Save diff in case we need it for a tie-breaker. subf_(diff, cnt2, cnt1); // diff = cnt1 - cnt2 // if (diff > 0) { cnt1 = cnt2; } - if (VM_Version::has_isel()) { - isel(cnt1, CR0, Assembler::greater, /*invert*/ false, cnt2); - } else { - Label Lskip; - blt(CR0, Lskip); - mr(cnt1, cnt2); - bind(Lskip); - } + isel(cnt1, CR0, Assembler::greater, /*invert*/ false, cnt2); // Rename registers Register chr1 = result; @@ -626,3 +619,48 @@ void C2_MacroAssembler::count_positives(Register src, Register cnt, Register res bind(Ldone); subf(result, src, result); // Result is offset from src. } + +void C2_MacroAssembler::reduceI(int opcode, Register dst, Register iSrc, VectorRegister vSrc, + VectorRegister vTmp1, VectorRegister vTmp2) { + + auto fn_vec_op = [this](int opcode, const VectorRegister &dst, const VectorRegister &a, const VectorRegister &b) { + switch(opcode) { + case Op_AddReductionVI: vadduwm(dst, a, b); break; + case Op_MulReductionVI: vmuluwm(dst, a , b); break; + case Op_AndReductionV: vand(dst, a, b); break; + case Op_OrReductionV: vor(dst, a, b); break; + case Op_XorReductionV: vxor(dst, a, b); break; + case Op_MinReductionV: vminsw(dst, a, b); break; + case Op_MaxReductionV: vmaxsw(dst, a, b); break; + default: assert(false, "wrong opcode"); + } + }; + + auto fn_scalar_op = [this](int opcode, const Register &dst, const Register &a, const Register &b) { + switch (opcode) { + case Op_AddReductionVI: add(dst, a, b); break; + case Op_MulReductionVI: mullw(dst, a, b); break; + case Op_AndReductionV: andr(dst, a, b); break; + case Op_OrReductionV: orr(dst, a, b); break; + case Op_XorReductionV: xorr(dst, a, b); break; + case Op_MinReductionV: + cmpw(CR0, a, b); + isel(dst, CR0, Assembler::less, /*invert*/false, a, b); + break; + case Op_MaxReductionV: + cmpw(CR0, a, b); + isel(dst, CR0, Assembler::greater, /*invert*/false, a, b); + break; + default: assert(false, "wrong opcode"); + } + }; + + // vSrc = [i0,i1,i2,i3] + vsldoi(vTmp1, vSrc, vSrc, 8); // vTmp1 <- [i2,i3,i0,i1] + fn_vec_op(opcode, vTmp2, vSrc, vTmp1); // vTmp2 <- [op(i0,i2), op(i1,i3), op(i2,i0), op(i3,i1)] + vsldoi(vTmp1, vTmp2, vTmp2, 4); // vTmp1 <- [op(i1,i3), op(i2,i0), op(i3,i1), op(i0,i2)] + fn_vec_op(opcode, vTmp1, vTmp1, vTmp2); // vTmp1 <- [op(i0,i1,i2,i3), op(i0,i1,i2,i3), op(i0,i1,i2,i3), op(i0,i1,i2,i3)] + mfvsrwz(R0, vTmp1.to_vsr()); // R0 <- op(i0,i1,i2,i3) + fn_scalar_op(opcode, dst, iSrc, R0); // dst <- op(iSrc, R0) +} + diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp index 345d5a6350d..16b6d1935ba 100644 --- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp @@ -73,4 +73,6 @@ void count_positives(Register src, Register cnt, Register result, Register tmp1, Register tmp2); + void reduceI(int opcode, Register dst, Register iSrc, VectorRegister vSrc, VectorRegister vTmp1, VectorRegister vTmp2); + #endif // CPU_PPC_C2_MACROASSEMBLER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp b/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp index 4d98b763078..c74cd3781a2 100644 --- a/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp +++ b/src/hotspot/cpu/ppc/foreignGlobals_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, SAP SE. All rights reserved. + * Copyright (c) 2020, 2025, SAP SE. All rights reserved. * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -35,16 +35,6 @@ #define __ masm-> -bool ABIDescriptor::is_volatile_reg(Register reg) const { - return _integer_argument_registers.contains(reg) - || _integer_additional_volatile_registers.contains(reg); -} - -bool ABIDescriptor::is_volatile_reg(FloatRegister reg) const { - return _float_argument_registers.contains(reg) - || _float_additional_volatile_registers.contains(reg); -} - bool ForeignGlobals::is_foreign_linker_supported() { return true; } @@ -62,10 +52,6 @@ const ABIDescriptor ForeignGlobals::parse_abi_descriptor(jobject jabi) { parse_register_array(outputStorage, StorageType::INTEGER, abi._integer_return_registers, as_Register); parse_register_array(outputStorage, StorageType::FLOAT, abi._float_return_registers, as_FloatRegister); - objArrayOop volatileStorage = jdk_internal_foreign_abi_ABIDescriptor::volatileStorage(abi_oop); - parse_register_array(volatileStorage, StorageType::INTEGER, abi._integer_additional_volatile_registers, as_Register); - parse_register_array(volatileStorage, StorageType::FLOAT, abi._float_additional_volatile_registers, as_FloatRegister); - abi._stack_alignment_bytes = jdk_internal_foreign_abi_ABIDescriptor::stackAlignment(abi_oop); abi._shadow_space_bytes = jdk_internal_foreign_abi_ABIDescriptor::shadowSpace(abi_oop); @@ -126,12 +112,7 @@ static void move_reg64(MacroAssembler* masm, int out_stk_bias, __ stw(as_Register(from_reg), -8, R1_SP); __ lfs(as_FloatRegister(to_reg), -8, R1_SP); // convert to double precision format } else { - if (VM_Version::has_mtfprd()) { - __ mtfprd(as_FloatRegister(to_reg), as_Register(from_reg)); - } else { - __ std(as_Register(from_reg), -8, R1_SP); - __ lfd(as_FloatRegister(to_reg), -8, R1_SP); - } + __ mtfprd(as_FloatRegister(to_reg), as_Register(from_reg)); } break; case StorageType::STACK: @@ -164,12 +145,7 @@ static void move_float(MacroAssembler* masm, int out_stk_bias, __ stfs(as_FloatRegister(from_reg), -8, R1_SP); // convert to single precision format __ lwa(as_Register(to_reg), -8, R1_SP); } else { - if (VM_Version::has_mtfprd()) { - __ mffprd(as_Register(to_reg), as_FloatRegister(from_reg)); - } else { - __ stfd(as_FloatRegister(from_reg), -8, R1_SP); - __ ld(as_Register(to_reg), -8, R1_SP); - } + __ mffprd(as_Register(to_reg), as_FloatRegister(from_reg)); } break; case StorageType::FLOAT: diff --git a/src/hotspot/cpu/ppc/foreignGlobals_ppc.hpp b/src/hotspot/cpu/ppc/foreignGlobals_ppc.hpp index baccdf2c9bb..b25ee28f192 100644 --- a/src/hotspot/cpu/ppc/foreignGlobals_ppc.hpp +++ b/src/hotspot/cpu/ppc/foreignGlobals_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023 SAP SE. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,9 +34,6 @@ struct ABIDescriptor { GrowableArray _float_argument_registers; GrowableArray _float_return_registers; - GrowableArray _integer_additional_volatile_registers; - GrowableArray _float_additional_volatile_registers; - int32_t _stack_alignment_bytes; int32_t _shadow_space_bytes; diff --git a/src/hotspot/cpu/ppc/frame_ppc.hpp b/src/hotspot/cpu/ppc/frame_ppc.hpp index 560615089fe..188015f5cd9 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2024 SAP SE. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -134,56 +134,6 @@ #define _native_abi_reg_args_spill(_component) \ (offset_of(frame::native_abi_reg_args_spill, _component)) - // non-volatile GPRs: - - struct spill_nonvolatiles { - uint64_t r14; - uint64_t r15; //_16 - uint64_t r16; - uint64_t r17; //_16 - uint64_t r18; - uint64_t r19; //_16 - uint64_t r20; - uint64_t r21; //_16 - uint64_t r22; - uint64_t r23; //_16 - uint64_t r24; - uint64_t r25; //_16 - uint64_t r26; - uint64_t r27; //_16 - uint64_t r28; - uint64_t r29; //_16 - uint64_t r30; - uint64_t r31; //_16 - - double f14; - double f15; - double f16; - double f17; - double f18; - double f19; - double f20; - double f21; - double f22; - double f23; - double f24; - double f25; - double f26; - double f27; - double f28; - double f29; - double f30; - double f31; - - // aligned to frame::alignment_in_bytes (16) - }; - - enum { - spill_nonvolatiles_size = sizeof(spill_nonvolatiles) - }; - - #define _spill_nonvolatiles_neg(_component) \ - (int)(-frame::spill_nonvolatiles_size + offset_of(frame::spill_nonvolatiles, _component)) // Frame layout for the Java template interpreter on PPC64. // @@ -230,6 +180,7 @@ // [callee's Java result] // [callee's locals w/o arguments] // [outgoing arguments] + // [non-volatiles] // [ENTRY_FRAME_LOCALS] // ABI for every Java frame, compiled and interpreted @@ -292,7 +243,6 @@ uint64_t result_type; uint64_t arguments_tos_address; //_16 // aligned to frame::alignment_in_bytes (16) - uint64_t r[spill_nonvolatiles_size/sizeof(uint64_t)]; }; enum { @@ -413,7 +363,7 @@ inline frame(intptr_t* sp, intptr_t* fp, address pc); inline frame(intptr_t* sp, address pc, kind knd = kind::nmethod); inline frame(intptr_t* sp, address pc, intptr_t* unextended_sp, intptr_t* fp = nullptr, CodeBlob* cb = nullptr); - inline frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map); + inline frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map = nullptr); inline frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map, bool on_heap); private: diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index 19a90367353..bb711f2d053 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2024 SAP SE. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -391,4 +391,43 @@ void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) // Nothing to do. } +#if INCLUDE_JFR + +// Static helper routines +inline intptr_t* frame::sender_sp(intptr_t* fp) { return fp; } + +// Extract common_abi parts. +inline intptr_t* frame::fp(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast(((common_abi*)sp)->callers_sp); +} + +inline intptr_t* frame::link(const intptr_t* fp) { return frame::fp(fp); } + +inline address frame::return_address(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast
          (((common_abi*)sp)->lr); +} + +inline address frame::interpreter_return_address(const intptr_t* fp) { return frame::return_address(fp); } + +// Extract java interpreter state parts. +inline address frame::interpreter_bcp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (*(fp + ijava_idx(bcp))); +} + +inline intptr_t* frame::interpreter_sender_sp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(*(fp + ijava_idx(sender_sp))); +} + +inline bool frame::is_interpreter_frame_setup_at(const intptr_t* fp, const void* sp) { + assert(fp != nullptr, "invariant"); + assert(sp != nullptr, "invariant"); + return sp <= fp - ((frame::ijava_state_size + frame::top_ijava_frame_abi_size) >> LogBytesPerWord); +} + +#endif // INCLUDE_JFR + #endif // CPU_PPC_FRAME_PPC_INLINE_HPP diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index acf916c8c72..32a7011ac26 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -337,15 +337,24 @@ int SaveLiveRegisters::iterate_over_register_mask(IterationAction action, int of assert(SuperwordUseVSX, "or should not reach here"); VectorSRegister vs_reg = vm_reg->as_VectorSRegister(); if (vs_reg->encoding() >= VSR32->encoding() && vs_reg->encoding() <= VSR51->encoding()) { - reg_save_index += 2; + reg_save_index += (2 + (reg_save_index & 1)); // 2 slots + alignment if needed Register spill_addr = R0; + int spill_offset = offset - reg_save_index * BytesPerWord; if (action == ACTION_SAVE) { - _masm->addi(spill_addr, R1_SP, offset - reg_save_index * BytesPerWord); - _masm->stxvd2x(vs_reg, spill_addr); + if (PowerArchitecturePPC64 >= 9) { + _masm->stxv(vs_reg, spill_offset, R1_SP); + } else { + _masm->addi(spill_addr, R1_SP, spill_offset); + _masm->stxvd2x(vs_reg, spill_addr); + } } else if (action == ACTION_RESTORE) { - _masm->addi(spill_addr, R1_SP, offset - reg_save_index * BytesPerWord); - _masm->lxvd2x(vs_reg, spill_addr); + if (PowerArchitecturePPC64 >= 9) { + _masm->lxv(vs_reg, spill_offset, R1_SP); + } else { + _masm->addi(spill_addr, R1_SP, spill_offset); + _masm->lxvd2x(vs_reg, spill_addr); + } } else { assert(action == ACTION_COUNT_ONLY, "Sanity"); } diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp index 19084ed27c7..d3bb9cc3c04 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp @@ -23,8 +23,8 @@ */ #include "code/codeBlob.hpp" -#include "code/nmethod.hpp" #include "code/nativeInst.hpp" +#include "code/nmethod.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/barrierSetNMethod.hpp" @@ -108,7 +108,7 @@ static NativeNMethodBarrier* get_nmethod_barrier(nmethod* nm) { } auto barrier = reinterpret_cast(barrier_address); - debug_only(barrier->verify()); + DEBUG_ONLY(barrier->verify()); return barrier; } diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp index 48422bc6621..5b24259103f 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/c1/shenandoahBarrierSetC1_ppc.cpp @@ -26,9 +26,9 @@ #include "asm/macroAssembler.inline.hpp" #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" -#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #define __ masm->masm()-> diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp index 842201e1584..b7156144d8b 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp @@ -24,8 +24,10 @@ */ #include "asm/macroAssembler.inline.hpp" -#include "gc/shared/gcArguments.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcArguments.hpp" +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" @@ -34,8 +36,6 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "interpreter/interpreter.hpp" #include "macroAssembler_ppc.hpp" #include "runtime/javaThread.hpp" @@ -360,13 +360,8 @@ void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssemb 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, CR0, Assembler::equal, false, tmp1); - } else { - __ bne(CR0, done); - __ xori(dst, tmp1, markWord::lock_mask_in_place); - } + __ xori(tmp1, tmp1, markWord::lock_mask_in_place); + __ isel(dst, CR0, Assembler::equal, false, tmp1); __ bind(done); __ block_comment("} resolve_forward_pointer_not_null (shenandoahgc)"); diff --git a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp index 2e3eed8ec60..20d96f6e937 100644 --- a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp @@ -21,8 +21,8 @@ * questions. */ -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zGlobals.hpp" #include "runtime/globals.hpp" @@ -34,9 +34,11 @@ #include #endif // LINUX -// Default value if probing is not implemented for a certain platform: 128TB -static const size_t DEFAULT_MAX_ADDRESS_BIT = 47; -// Minimum value returned, if probing fails: 64GB +// Default value if probing is not implemented for a certain platform +// Max address bit is restricted by implicit assumptions in the code, for instance +// the bit layout of ZForwardingEntry or Partial array entry (see ZMarkStackEntry) in mark stack +static const size_t DEFAULT_MAX_ADDRESS_BIT = 46; +// Minimum value returned, if probing fail static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; static size_t probe_valid_max_address_bit() { @@ -91,10 +93,15 @@ static size_t probe_valid_max_address_bit() { size_t ZPlatformAddressOffsetBits() { static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; +#ifdef ADDRESS_SANITIZER + // The max supported value is 44 because of other internal data structures. + return MIN2(valid_max_address_offset_bits, (size_t)44); +#else const size_t min_address_offset_bits = max_address_offset_bits - 2; const size_t address_offset = ZGlobalsPointers::min_address_offset_request(); const size_t address_offset_bits = log2i_exact(address_offset); return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); +#endif } size_t ZPlatformAddressHeapBaseShift() { diff --git a/src/hotspot/cpu/ppc/globals_ppc.hpp b/src/hotspot/cpu/ppc/globals_ppc.hpp index 7fefc856a47..f944408fe29 100644 --- a/src/hotspot/cpu/ppc/globals_ppc.hpp +++ b/src/hotspot/cpu/ppc/globals_ppc.hpp @@ -116,7 +116,7 @@ define_pd_global(intx, InitArrayShortSize, 9*BytesPerLong); \ /* special instructions */ \ product(bool, SuperwordUseVSX, false, \ - "Use Power8 VSX instructions for superword optimization.") \ + "Use VSX instructions for superword optimization.") \ \ product(bool, UseByteReverseInstructions, false, DIAGNOSTIC, \ "Use byte reverse instructions.") \ diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp index 99ac037e4b7..d3969427db3 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc.hpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2023 SAP SE. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,7 +170,11 @@ class InterpreterMacroAssembler: public MacroAssembler { void remove_activation(TosState state, bool throw_monitor_exception = true, bool install_monitor_exception = true); - void merge_frames(Register Rtop_frame_sp, Register return_pc, Register Rscratch1, Register Rscratch2); // merge top frames + JFR_ONLY(void enter_jfr_critical_section();) + JFR_ONLY(void leave_jfr_critical_section();) + void load_fp(Register fp); + void remove_top_frame_given_fp(Register fp, Register sender_sp, Register sender_fp, Register return_pc, Register temp); + void merge_frames(Register sender_sp, Register return_pc, Register temp1, Register temp2); // merge top frames void add_monitor_to_stack(bool stack_is_empty, Register Rtemp1, Register Rtemp2); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index 7a75dfd3de1..29fb54250c2 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -308,21 +308,11 @@ void InterpreterMacroAssembler::push_2ptrs(Register first, Register second) { } void InterpreterMacroAssembler::move_l_to_d(Register l, FloatRegister d) { - if (VM_Version::has_mtfprd()) { - mtfprd(d, l); - } else { - std(l, 0, R15_esp); - lfd(d, 0, R15_esp); - } + mtfprd(d, l); } void InterpreterMacroAssembler::move_d_to_l(FloatRegister d, Register l) { - if (VM_Version::has_mtfprd()) { - mffprd(l, d); - } else { - stfd(d, 0, R15_esp); - ld(l, 0, R15_esp); - } + mffprd(l, d); } void InterpreterMacroAssembler::push(TosState state) { @@ -793,19 +783,27 @@ void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state, } // Support function for remove_activation & Co. -void InterpreterMacroAssembler::merge_frames(Register Rsender_sp, Register return_pc, - Register Rscratch1, Register Rscratch2) { - // Pop interpreter frame. - ld(Rscratch1, 0, R1_SP); // *SP - ld(Rsender_sp, _ijava_state_neg(sender_sp), Rscratch1); // top_frame_sp - ld(Rscratch2, 0, Rscratch1); // **SP - if (return_pc!=noreg) { - ld(return_pc, _abi0(lr), Rscratch1); // LR +void InterpreterMacroAssembler::load_fp(Register fp) { + ld(fp, _abi0(callers_sp), R1_SP); // *SP +} + +void InterpreterMacroAssembler::remove_top_frame_given_fp(Register fp, Register sender_sp, Register sender_fp, + Register return_pc, Register temp) { + assert_different_registers(sender_sp, sender_fp, return_pc, temp); + ld(sender_sp, _ijava_state_neg(sender_sp), fp); + ld(sender_fp, _abi0(callers_sp), fp); // **SP + if (return_pc != noreg) { + ld(return_pc, _abi0(lr), fp); // last usage of fp, register can be reused } + subf(temp, R1_SP, sender_sp); // sender_sp - SP + stdux(sender_fp, R1_SP, temp); // atomically set *(SP = sender_sp) = sender_fp +} - // Merge top frames. - subf(Rscratch1, R1_SP, Rsender_sp); // top_frame_sp - SP - stdux(Rscratch2, R1_SP, Rscratch1); // atomically set *(SP = top_frame_sp) = **SP +void InterpreterMacroAssembler::merge_frames(Register sender_sp, Register return_pc, + Register temp1, Register temp2) { + Register fp = temp1, sender_fp = temp2; + load_fp(fp); + remove_top_frame_given_fp(fp, sender_sp, sender_fp, return_pc, /* temp */ fp); } void InterpreterMacroAssembler::narrow(Register result) { @@ -864,11 +862,16 @@ void InterpreterMacroAssembler::remove_activation(TosState state, bool install_monitor_exception) { BLOCK_COMMENT("remove_activation {"); + unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception); + // The below poll is for the stack watermark barrier. It allows fixing up frames lazily, // that would normally not be safe to use. Such bad returns into unsafe territory of // the stack, will call InterpreterRuntime::at_unwind. - Label slow_path; - Label fast_path; + Label slow_path, fast_path; + Register fp = R22_tmp2; + load_fp(fp); + + JFR_ONLY(enter_jfr_critical_section();) safepoint_poll(slow_path, R11_scratch1, true /* at_return */, false /* in_nmethod */); b(fast_path); bind(slow_path); @@ -880,8 +883,6 @@ void InterpreterMacroAssembler::remove_activation(TosState state, align(32); bind(fast_path); - unlock_if_synchronized_method(state, throw_monitor_exception, install_monitor_exception); - // Save result (push state before jvmti call and pop it afterwards) and notify jvmti. notify_method_exit(false, state, NotifyJVMTI, true); @@ -901,10 +902,11 @@ void InterpreterMacroAssembler::remove_activation(TosState state, // call could have a smaller SP, so that this compare succeeds for an // inner call of the method annotated with ReservedStack. ld_ptr(R0, JavaThread::reserved_stack_activation_offset(), R16_thread); - ld_ptr(R11_scratch1, _abi0(callers_sp), R1_SP); // Load frame pointer. - cmpld(CR0, R11_scratch1, R0); + cmpld(CR0, fp, R0); blt_predict_taken(CR0, no_reserved_zone_enabling); + JFR_ONLY(leave_jfr_critical_section();) + // Enable reserved zone again, throw stack overflow exception. call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), R16_thread); call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_delayed_StackOverflowError)); @@ -916,12 +918,26 @@ void InterpreterMacroAssembler::remove_activation(TosState state, verify_oop(R17_tos, state); - merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + remove_top_frame_given_fp(fp, R21_sender_SP, R23_tmp3, /*return_pc*/ R0, R11_scratch1); mtlr(R0); pop_cont_fastpath(); + JFR_ONLY(leave_jfr_critical_section();) + BLOCK_COMMENT("} remove_activation"); } +#if INCLUDE_JFR +void InterpreterMacroAssembler::enter_jfr_critical_section() { + li(R0, 1); + stb(R0, in_bytes(SAMPLING_CRITICAL_SECTION_OFFSET_JFR), R16_thread); +} + +void InterpreterMacroAssembler::leave_jfr_critical_section() { + li(R0, 0); + stb(R0, in_bytes(SAMPLING_CRITICAL_SECTION_OFFSET_JFR), R16_thread); +} +#endif // INCLUDE_JFR + // Lock object // // Registers alive @@ -958,17 +974,18 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // markWord displaced_header = obj->mark().set_unlocked(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, object); - lbz(tmp, in_bytes(Klass::misc_flags_offset()), tmp); - testbitdi(CR0, R0, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(CR0, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(monitor, object, header, tmp, slow_case); b(done); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, object); + lbz(tmp, in_bytes(Klass::misc_flags_offset()), tmp); + testbitdi(CR0, R0, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); + bne(CR0, slow_case); + } + // Load markWord from object into header. ld(header, oopDesc::mark_offset_in_bytes(), object); diff --git a/src/hotspot/cpu/ppc/javaFrameAnchor_ppc.hpp b/src/hotspot/cpu/ppc/javaFrameAnchor_ppc.hpp index 8b539bc8101..00a6b4cbf95 100644 --- a/src/hotspot/cpu/ppc/javaFrameAnchor_ppc.hpp +++ b/src/hotspot/cpu/ppc/javaFrameAnchor_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2014 SAP SE. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -73,6 +73,8 @@ address last_Java_pc(void) { return _last_Java_pc; } + intptr_t* last_Java_fp() const { return *(intptr_t**)_last_Java_sp; } + void set_last_Java_sp(intptr_t* sp) { OrderAccess::release(); _last_Java_sp = sp; } #endif // CPU_PPC_JAVAFRAMEANCHOR_PPC_HPP diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index f82395b14fb..857911214c5 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -774,93 +774,82 @@ void MacroAssembler::clobber_carg_stack_slots(Register tmp) { } } -// Uses ordering which corresponds to ABI: -// _savegpr0_14: std r14,-144(r1) -// _savegpr0_15: std r15,-136(r1) -// _savegpr0_16: std r16,-128(r1) -void MacroAssembler::save_nonvolatile_gprs(Register dst, int offset) { - std(R14, offset, dst); offset += 8; - std(R15, offset, dst); offset += 8; - std(R16, offset, dst); offset += 8; - std(R17, offset, dst); offset += 8; - std(R18, offset, dst); offset += 8; - std(R19, offset, dst); offset += 8; - std(R20, offset, dst); offset += 8; - std(R21, offset, dst); offset += 8; - std(R22, offset, dst); offset += 8; - std(R23, offset, dst); offset += 8; - std(R24, offset, dst); offset += 8; - std(R25, offset, dst); offset += 8; - std(R26, offset, dst); offset += 8; - std(R27, offset, dst); offset += 8; - std(R28, offset, dst); offset += 8; - std(R29, offset, dst); offset += 8; - std(R30, offset, dst); offset += 8; - std(R31, offset, dst); offset += 8; - - stfd(F14, offset, dst); offset += 8; - stfd(F15, offset, dst); offset += 8; - stfd(F16, offset, dst); offset += 8; - stfd(F17, offset, dst); offset += 8; - stfd(F18, offset, dst); offset += 8; - stfd(F19, offset, dst); offset += 8; - stfd(F20, offset, dst); offset += 8; - stfd(F21, offset, dst); offset += 8; - stfd(F22, offset, dst); offset += 8; - stfd(F23, offset, dst); offset += 8; - stfd(F24, offset, dst); offset += 8; - stfd(F25, offset, dst); offset += 8; - stfd(F26, offset, dst); offset += 8; - stfd(F27, offset, dst); offset += 8; - stfd(F28, offset, dst); offset += 8; - stfd(F29, offset, dst); offset += 8; - stfd(F30, offset, dst); offset += 8; - stfd(F31, offset, dst); -} - -// Uses ordering which corresponds to ABI: -// _restgpr0_14: ld r14,-144(r1) -// _restgpr0_15: ld r15,-136(r1) -// _restgpr0_16: ld r16,-128(r1) -void MacroAssembler::restore_nonvolatile_gprs(Register src, int offset) { - ld(R14, offset, src); offset += 8; - ld(R15, offset, src); offset += 8; - ld(R16, offset, src); offset += 8; - ld(R17, offset, src); offset += 8; - ld(R18, offset, src); offset += 8; - ld(R19, offset, src); offset += 8; - ld(R20, offset, src); offset += 8; - ld(R21, offset, src); offset += 8; - ld(R22, offset, src); offset += 8; - ld(R23, offset, src); offset += 8; - ld(R24, offset, src); offset += 8; - ld(R25, offset, src); offset += 8; - ld(R26, offset, src); offset += 8; - ld(R27, offset, src); offset += 8; - ld(R28, offset, src); offset += 8; - ld(R29, offset, src); offset += 8; - ld(R30, offset, src); offset += 8; - ld(R31, offset, src); offset += 8; - - // FP registers - lfd(F14, offset, src); offset += 8; - lfd(F15, offset, src); offset += 8; - lfd(F16, offset, src); offset += 8; - lfd(F17, offset, src); offset += 8; - lfd(F18, offset, src); offset += 8; - lfd(F19, offset, src); offset += 8; - lfd(F20, offset, src); offset += 8; - lfd(F21, offset, src); offset += 8; - lfd(F22, offset, src); offset += 8; - lfd(F23, offset, src); offset += 8; - lfd(F24, offset, src); offset += 8; - lfd(F25, offset, src); offset += 8; - lfd(F26, offset, src); offset += 8; - lfd(F27, offset, src); offset += 8; - lfd(F28, offset, src); offset += 8; - lfd(F29, offset, src); offset += 8; - lfd(F30, offset, src); offset += 8; - lfd(F31, offset, src); +void MacroAssembler::save_nonvolatile_registers(Register dst, int offset, bool include_fp_regs, bool include_vector_regs) { + BLOCK_COMMENT("save_nonvolatile_registers {"); + + for (int i = 14; i < 32; i++) { + std(as_Register(i), offset, dst); + offset += 8; + } + + if (include_fp_regs) { + for (int i = 14; i < 32; i++) { + stfd(as_FloatRegister(i), offset, dst); + offset += 8; + } + } + + if (include_vector_regs) { + assert(is_aligned(offset, StackAlignmentInBytes), "should be"); + if (PowerArchitecturePPC64 >= 10) { + for (int i = 20; i < 32; i += 2) { + stxvp(as_VectorRegister(i)->to_vsr(), offset, dst); + offset += 32; + } + } else { + for (int i = 20; i < 32; i++) { + if (PowerArchitecturePPC64 >= 9) { + stxv(as_VectorRegister(i)->to_vsr(), offset, dst); + } else { + Register spill_addr = R0; + addi(spill_addr, dst, offset); + stxvd2x(as_VectorRegister(i)->to_vsr(), spill_addr); + } + offset += 16; + } + } + } + + BLOCK_COMMENT("} save_nonvolatile_registers "); +} + +void MacroAssembler::restore_nonvolatile_registers(Register src, int offset, bool include_fp_regs, bool include_vector_regs) { + BLOCK_COMMENT("restore_nonvolatile_registers {"); + + for (int i = 14; i < 32; i++) { + ld(as_Register(i), offset, src); + offset += 8; + } + + if (include_fp_regs) { + for (int i = 14; i < 32; i++) { + lfd(as_FloatRegister(i), offset, src); + offset += 8; + } + } + + if (include_vector_regs) { + assert(is_aligned(offset, StackAlignmentInBytes), "should be"); + if (PowerArchitecturePPC64 >= 10) { + for (int i = 20; i < 32; i += 2) { + lxvp(as_VectorRegister(i)->to_vsr(), offset, src); + offset += 32; + } + } else { + for (int i = 20; i < 32; i++) { + if (PowerArchitecturePPC64 >= 9) { + lxv(as_VectorRegister(i)->to_vsr(), offset, src); + } else { + Register spill_addr = R0; + addi(spill_addr, src, offset); + lxvd2x(as_VectorRegister(i)->to_vsr(), spill_addr); + } + offset += 16; + } + } + } + + BLOCK_COMMENT("} restore_nonvolatile_registers"); } // For verify_oops. @@ -1029,13 +1018,6 @@ void MacroAssembler::push_frame_reg_args(unsigned int bytes, Register tmp) { push_frame(bytes + frame::native_abi_reg_args_size, tmp); } -// Setup up a new C frame with a spill area for non-volatile GPRs and -// additional space for local variables. -void MacroAssembler::push_frame_reg_args_nonvolatiles(unsigned int bytes, - Register tmp) { - push_frame(bytes + frame::native_abi_reg_args_size + frame::spill_nonvolatiles_size, tmp); -} - // Pop current C frame. void MacroAssembler::pop_frame() { ld(R1_SP, _abi0(callers_sp), R1_SP); @@ -1570,57 +1552,27 @@ void MacroAssembler::atomic_get_and_modify_generic(Register dest_current_value, Register addr_base, Register tmp1, Register tmp2, Register tmp3, bool cmpxchgx_hint, bool is_add, int size) { // Sub-word instructions are available since Power 8. - // For older processors, instruction_type != size holds, and we - // emulate the sub-word instructions by constructing a 4-byte value - // that leaves the other bytes unchanged. - const int instruction_type = VM_Version::has_lqarx() ? size : 4; Label retry; Register shift_amount = noreg, val32 = dest_current_value, modval = is_add ? tmp1 : exchange_value; - if (instruction_type != size) { - assert_different_registers(tmp1, tmp2, tmp3, dest_current_value, exchange_value, addr_base); - modval = tmp1; - shift_amount = tmp2; - val32 = tmp3; - // Need some preparation: Compute shift amount, align address. Note: shorts must be 2 byte aligned. -#ifdef VM_LITTLE_ENDIAN - rldic(shift_amount, addr_base, 3, 64-5); // (dest & 3) * 8; - clrrdi(addr_base, addr_base, 2); -#else - xori(shift_amount, addr_base, (size == 1) ? 3 : 2); - clrrdi(addr_base, addr_base, 2); - rldic(shift_amount, shift_amount, 3, 64-5); // byte: ((3-dest) & 3) * 8; short: ((1-dest/2) & 1) * 16; -#endif - } // atomic emulation loop bind(retry); - switch (instruction_type) { + switch (size) { case 4: lwarx(val32, addr_base, cmpxchgx_hint); break; case 2: lharx(val32, addr_base, cmpxchgx_hint); break; case 1: lbarx(val32, addr_base, cmpxchgx_hint); break; default: ShouldNotReachHere(); } - if (instruction_type != size) { - srw(dest_current_value, val32, shift_amount); - } - if (is_add) { add(modval, dest_current_value, exchange_value); } - if (instruction_type != size) { - // Transform exchange value such that the replacement can be done by one xor instruction. - xorr(modval, dest_current_value, is_add ? modval : exchange_value); - clrldi(modval, modval, (size == 1) ? 56 : 48); - slw(modval, modval, shift_amount); - xorr(modval, val32, modval); - } - switch (instruction_type) { + switch (size) { case 4: stwcx_(modval, addr_base); break; case 2: sthcx_(modval, addr_base); break; case 1: stbcx_(modval, addr_base); break; @@ -1645,51 +1597,22 @@ void MacroAssembler::atomic_get_and_modify_generic(Register dest_current_value, // Only signed types are supported with size < 4. void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_current_value, RegisterOrConstant compare_value, Register exchange_value, - Register addr_base, Register tmp1, Register tmp2, - Label &retry, Label &failed, bool cmpxchgx_hint, int size) { + Register addr_base, Label &retry, Label &failed, bool cmpxchgx_hint, int size) { // Sub-word instructions are available since Power 8. - // For older processors, instruction_type != size holds, and we - // emulate the sub-word instructions by constructing a 4-byte value - // that leaves the other bytes unchanged. - const int instruction_type = VM_Version::has_lqarx() ? size : 4; - Register shift_amount = noreg, val32 = dest_current_value, modval = exchange_value; - if (instruction_type != size) { - assert_different_registers(tmp1, tmp2, dest_current_value, compare_value.register_or_noreg(), exchange_value, addr_base); - shift_amount = tmp1; - val32 = tmp2; - modval = tmp2; - // Need some preparation: Compute shift amount, align address. Note: shorts must be 2 byte aligned. -#ifdef VM_LITTLE_ENDIAN - rldic(shift_amount, addr_base, 3, 64-5); // (dest & 3) * 8; - clrrdi(addr_base, addr_base, 2); -#else - xori(shift_amount, addr_base, (size == 1) ? 3 : 2); - clrrdi(addr_base, addr_base, 2); - rldic(shift_amount, shift_amount, 3, 64-5); // byte: ((3-dest) & 3) * 8; short: ((1-dest/2) & 1) * 16; -#endif - // Transform exchange value such that the replacement can be done by one xor instruction. - xorr(exchange_value, compare_value, exchange_value); - clrldi(exchange_value, exchange_value, (size == 1) ? 56 : 48); - slw(exchange_value, exchange_value, shift_amount); - } - // atomic emulation loop bind(retry); - switch (instruction_type) { + switch (size) { case 4: lwarx(val32, addr_base, cmpxchgx_hint); break; case 2: lharx(val32, addr_base, cmpxchgx_hint); break; case 1: lbarx(val32, addr_base, cmpxchgx_hint); break; default: ShouldNotReachHere(); } - if (instruction_type != size) { - srw(dest_current_value, val32, shift_amount); - } if (size == 1) { extsb(dest_current_value, dest_current_value); } else if (size == 2) { @@ -1705,11 +1628,7 @@ void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_cur // branch to done => (flag == ne), (dest_current_value != compare_value) // fall through => (flag == eq), (dest_current_value == compare_value) - if (instruction_type != size) { - xorr(modval, val32, exchange_value); - } - - switch (instruction_type) { + switch (size) { case 4: stwcx_(modval, addr_base); break; case 2: sthcx_(modval, addr_base); break; case 1: stbcx_(modval, addr_base); break; @@ -1720,8 +1639,7 @@ void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_cur // CmpxchgX sets condition register to cmpX(current, compare). void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_current_value, RegisterOrConstant compare_value, Register exchange_value, - Register addr_base, Register tmp1, Register tmp2, - int semantics, bool cmpxchgx_hint, Register int_flag_success, + Register addr_base, int semantics, bool cmpxchgx_hint, Register int_flag_success, Label* failed_ext, bool contention_hint, bool weak, int size) { Label retry; Label failed_int; @@ -1732,8 +1650,7 @@ void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_curre // result register is different from the other ones. bool use_result_reg = (int_flag_success != noreg); bool preset_result_reg = (int_flag_success != dest_current_value && int_flag_success != compare_value.register_or_noreg() && - int_flag_success != exchange_value && int_flag_success != addr_base && - int_flag_success != tmp1 && int_flag_success != tmp2); + int_flag_success != exchange_value && int_flag_success != addr_base); assert(!weak || flag == CR0, "weak only supported with CR0"); assert(int_flag_success == noreg || failed_ext == nullptr, "cannot have both"); assert(size == 1 || size == 2 || size == 4, "unsupported"); @@ -1759,7 +1676,7 @@ void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_curre release(); } - cmpxchg_loop_body(flag, dest_current_value, compare_value, exchange_value, addr_base, tmp1, tmp2, + cmpxchg_loop_body(flag, dest_current_value, compare_value, exchange_value, addr_base, retry, failed, cmpxchgx_hint, size); if (!weak || use_result_reg || failed_ext) { if (UseStaticBranchPredictionInCompareAndSwapPPC64) { @@ -3000,7 +2917,7 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla Label slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. li(tmp1, 0); std(tmp1, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box); } @@ -3360,6 +3277,35 @@ void MacroAssembler::safepoint_poll(Label& slow_path, Register temp, bool at_ret } } +void MacroAssembler::jump_to_polling_page_return_handler_blob(int safepoint_offset, bool fixed_size) { + assert(SharedRuntime::polling_page_return_handler_blob() != nullptr, + "polling page return stub not created yet"); + address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point(); + + // Determine saved exception pc using pc relative address computation. + { + Label next_pc; + bl(next_pc); + bind(next_pc); + } + int current_offset = offset(); + + if (fixed_size) { + // Code size must not depend on offsets. + load_const32(R12, safepoint_offset - current_offset); + mflr(R0); + add(R12, R12, R0); + } else { + mflr(R12); + add_const_optimized(R12, R12, safepoint_offset - current_offset); + } + std(R12, in_bytes(JavaThread::saved_exception_pc_offset()), R16_thread); + + add_const_optimized(R0, R29_TOC, MacroAssembler::offset_to_global_toc(stub)); + mtctr(R0); + bctr(); +} + void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp2, MacroAssembler::PreservationLevel preservation_level) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); @@ -3735,7 +3681,6 @@ void MacroAssembler::load_reverse_32(Register dst, Register src) { // Due to register shortage, setting tc3 may overwrite table. With the return offset // at hand, the original table address can be easily reconstructed. int MacroAssembler::crc32_table_columns(Register table, Register tc0, Register tc1, Register tc2, Register tc3) { - assert(!VM_Version::has_vpmsumb(), "Vector version should be used instead!"); // Point to 4 byte folding tables (byte-reversed version for Big Endian) // Layout: See StubRoutines::ppc::generate_crc_constants. @@ -3868,103 +3813,6 @@ void MacroAssembler::update_1word_crc32(Register crc, Register buf, Register tab xorr(crc, t0, t2); // Now crc contains the final checksum value. } -/** - * @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 register pointing to CRC table - * - * uses R9..R12 as work register. Must be saved/restored by caller! - */ -void MacroAssembler::kernel_crc32_1word(Register crc, Register buf, Register len, Register table, - Register t0, Register t1, Register t2, Register t3, - Register tc0, Register tc1, Register tc2, Register tc3, - bool invertCRC) { - assert_different_registers(crc, buf, len, table); - - Label L_mainLoop, L_tail; - Register tmp = t0; - Register data = t0; - Register tmp2 = t1; - const int mainLoop_stepping = 4; - const int tailLoop_stepping = 1; - const int log_stepping = exact_log2(mainLoop_stepping); - const int mainLoop_alignment = 32; // InputForNewCode > 4 ? InputForNewCode : 32; - const int complexThreshold = 2*mainLoop_stepping; - - // Don't test for len <= 0 here. This pathological case should not occur anyway. - // Optimizing for it by adding a test and a branch seems to be a waste of CPU cycles - // for all well-behaved cases. The situation itself is detected and handled correctly - // within update_byteLoop_crc32. - assert(tailLoop_stepping == 1, "check tailLoop_stepping!"); - - BLOCK_COMMENT("kernel_crc32_1word {"); - - if (invertCRC) { - nand(crc, crc, crc); // 1s complement of crc - } - - // Check for short ( mainLoop_stepping) { - sub(len, len, tmp2); // Remaining bytes for main loop (>=mainLoop_stepping is guaranteed). - } else { - sub(tmp, len, tmp2); // Remaining bytes for main loop. - cmpdi(CR0, tmp, mainLoop_stepping); - blt(CR0, L_tail); // For less than one mainloop_stepping left, do only tail processing - mr(len, tmp); // remaining bytes for main loop (>=mainLoop_stepping is guaranteed). - } - update_byteLoop_crc32(crc, buf, tmp2, table, data, false); - } - - srdi(tmp2, len, log_stepping); // #iterations for mainLoop - andi(len, len, mainLoop_stepping-1); // remaining bytes for tailLoop - mtctr(tmp2); - -#ifdef VM_LITTLE_ENDIAN - Register crc_rv = crc; -#else - Register crc_rv = tmp; // Load_reverse needs separate registers to work on. - // Occupies tmp, but frees up crc. - load_reverse_32(crc_rv, crc); // Revert byte order because we are dealing with big-endian data. - tmp = crc; -#endif - - int reconstructTableOffset = crc32_table_columns(table, tc0, tc1, tc2, tc3); - - align(mainLoop_alignment); // Octoword-aligned loop address. Shows 2% improvement. - BIND(L_mainLoop); - update_1word_crc32(crc_rv, buf, table, 0, mainLoop_stepping, crc_rv, t1, t2, t3, tc0, tc1, tc2, tc3); - bdnz(L_mainLoop); - -#ifndef VM_LITTLE_ENDIAN - load_reverse_32(crc, crc_rv); // Revert byte order because we are dealing with big-endian data. - tmp = crc_rv; // Tmp uses it's original register again. -#endif - - // Restore original table address for tailLoop. - if (reconstructTableOffset != 0) { - addi(table, table, -reconstructTableOffset); - } - - // Process last few (= Power7). // fcfid + frsp showed rounding problem when result should be 0x3f800001. - return VM_Version::has_fcfids(); + return true; } // Implements a variant of EncodeISOArrayNode that encode ASCII only diff --git a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp index 13fb8ef79d6..803bb6bfe69 100644 --- a/src/hotspot/cpu/ppc/methodHandles_ppc.cpp +++ b/src/hotspot/cpu/ppc/methodHandles_ppc.cpp @@ -359,7 +359,9 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, ? -1 // enforce receiver null check : oopDesc::klass_offset_in_bytes(); // regular null-checking behavior - __ null_check_throw(receiver_reg, klass_offset, temp1, Interpreter::throw_NullPointerException_entry()); + address NullPointerException_entry = for_compiler_entry ? SharedRuntime::throw_NullPointerException_at_call_entry() + : Interpreter::throw_NullPointerException_entry(); + __ null_check_throw(receiver_reg, klass_offset, temp1, NullPointerException_entry); if (iid != vmIntrinsics::_linkToSpecial || VerifyMethodHandles) { __ load_klass(temp1_recv_klass, receiver_reg); diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 07d681e8982..128e566d0f3 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -258,71 +258,326 @@ register %{ // Vector-Scalar Registers // ---------------------------- // 1st 32 VSRs are aliases for the FPRs which are already defined above. - reg_def VSR0 ( SOC, SOC, Op_VecX, 0, VMRegImpl::Bad()); - reg_def VSR1 ( SOC, SOC, Op_VecX, 1, VMRegImpl::Bad()); - reg_def VSR2 ( SOC, SOC, Op_VecX, 2, VMRegImpl::Bad()); - reg_def VSR3 ( SOC, SOC, Op_VecX, 3, VMRegImpl::Bad()); - reg_def VSR4 ( SOC, SOC, Op_VecX, 4, VMRegImpl::Bad()); - reg_def VSR5 ( SOC, SOC, Op_VecX, 5, VMRegImpl::Bad()); - reg_def VSR6 ( SOC, SOC, Op_VecX, 6, VMRegImpl::Bad()); - reg_def VSR7 ( SOC, SOC, Op_VecX, 7, VMRegImpl::Bad()); - reg_def VSR8 ( SOC, SOC, Op_VecX, 8, VMRegImpl::Bad()); - reg_def VSR9 ( SOC, SOC, Op_VecX, 9, VMRegImpl::Bad()); - reg_def VSR10 ( SOC, SOC, Op_VecX, 10, VMRegImpl::Bad()); - reg_def VSR11 ( SOC, SOC, Op_VecX, 11, VMRegImpl::Bad()); - reg_def VSR12 ( SOC, SOC, Op_VecX, 12, VMRegImpl::Bad()); - reg_def VSR13 ( SOC, SOC, Op_VecX, 13, VMRegImpl::Bad()); - reg_def VSR14 ( SOC, SOE, Op_VecX, 14, VMRegImpl::Bad()); - reg_def VSR15 ( SOC, SOE, Op_VecX, 15, VMRegImpl::Bad()); - reg_def VSR16 ( SOC, SOE, Op_VecX, 16, VMRegImpl::Bad()); - reg_def VSR17 ( SOC, SOE, Op_VecX, 17, VMRegImpl::Bad()); - reg_def VSR18 ( SOC, SOE, Op_VecX, 18, VMRegImpl::Bad()); - reg_def VSR19 ( SOC, SOE, Op_VecX, 19, VMRegImpl::Bad()); - reg_def VSR20 ( SOC, SOE, Op_VecX, 20, VMRegImpl::Bad()); - reg_def VSR21 ( SOC, SOE, Op_VecX, 21, VMRegImpl::Bad()); - reg_def VSR22 ( SOC, SOE, Op_VecX, 22, VMRegImpl::Bad()); - reg_def VSR23 ( SOC, SOE, Op_VecX, 23, VMRegImpl::Bad()); - reg_def VSR24 ( SOC, SOE, Op_VecX, 24, VMRegImpl::Bad()); - reg_def VSR25 ( SOC, SOE, Op_VecX, 25, VMRegImpl::Bad()); - reg_def VSR26 ( SOC, SOE, Op_VecX, 26, VMRegImpl::Bad()); - reg_def VSR27 ( SOC, SOE, Op_VecX, 27, VMRegImpl::Bad()); - reg_def VSR28 ( SOC, SOE, Op_VecX, 28, VMRegImpl::Bad()); - reg_def VSR29 ( SOC, SOE, Op_VecX, 29, VMRegImpl::Bad()); - reg_def VSR30 ( SOC, SOE, Op_VecX, 30, VMRegImpl::Bad()); - reg_def VSR31 ( SOC, SOE, Op_VecX, 31, VMRegImpl::Bad()); + reg_def VSR0 (SOC, SOC, Op_RegF, 0, VMRegImpl::Bad()); + reg_def VSR0_H (SOC, SOC, Op_RegF, 0, VMRegImpl::Bad()); + reg_def VSR0_J (SOC, SOC, Op_RegF, 0, VMRegImpl::Bad()); + reg_def VSR0_K (SOC, SOC, Op_RegF, 0, VMRegImpl::Bad()); + + reg_def VSR1 (SOC, SOC, Op_RegF, 1, VMRegImpl::Bad()); + reg_def VSR1_H (SOC, SOC, Op_RegF, 1, VMRegImpl::Bad()); + reg_def VSR1_J (SOC, SOC, Op_RegF, 1, VMRegImpl::Bad()); + reg_def VSR1_K (SOC, SOC, Op_RegF, 1, VMRegImpl::Bad()); + + reg_def VSR2 (SOC, SOC, Op_RegF, 2, VMRegImpl::Bad()); + reg_def VSR2_H (SOC, SOC, Op_RegF, 2, VMRegImpl::Bad()); + reg_def VSR2_J (SOC, SOC, Op_RegF, 2, VMRegImpl::Bad()); + reg_def VSR2_K (SOC, SOC, Op_RegF, 2, VMRegImpl::Bad()); + + reg_def VSR3 (SOC, SOC, Op_RegF, 3, VMRegImpl::Bad()); + reg_def VSR3_H (SOC, SOC, Op_RegF, 3, VMRegImpl::Bad()); + reg_def VSR3_J (SOC, SOC, Op_RegF, 3, VMRegImpl::Bad()); + reg_def VSR3_K (SOC, SOC, Op_RegF, 3, VMRegImpl::Bad()); + + reg_def VSR4 (SOC, SOC, Op_RegF, 4, VMRegImpl::Bad()); + reg_def VSR4_H (SOC, SOC, Op_RegF, 4, VMRegImpl::Bad()); + reg_def VSR4_J (SOC, SOC, Op_RegF, 4, VMRegImpl::Bad()); + reg_def VSR4_K (SOC, SOC, Op_RegF, 4, VMRegImpl::Bad()); + + reg_def VSR5 (SOC, SOC, Op_RegF, 5, VMRegImpl::Bad()); + reg_def VSR5_H (SOC, SOC, Op_RegF, 5, VMRegImpl::Bad()); + reg_def VSR5_J (SOC, SOC, Op_RegF, 5, VMRegImpl::Bad()); + reg_def VSR5_K (SOC, SOC, Op_RegF, 5, VMRegImpl::Bad()); + + reg_def VSR6 (SOC, SOC, Op_RegF, 6, VMRegImpl::Bad()); + reg_def VSR6_H (SOC, SOC, Op_RegF, 6, VMRegImpl::Bad()); + reg_def VSR6_J (SOC, SOC, Op_RegF, 6, VMRegImpl::Bad()); + reg_def VSR6_K (SOC, SOC, Op_RegF, 6, VMRegImpl::Bad()); + + reg_def VSR7 (SOC, SOC, Op_RegF, 7, VMRegImpl::Bad()); + reg_def VSR7_H (SOC, SOC, Op_RegF, 7, VMRegImpl::Bad()); + reg_def VSR7_J (SOC, SOC, Op_RegF, 7, VMRegImpl::Bad()); + reg_def VSR7_K (SOC, SOC, Op_RegF, 7, VMRegImpl::Bad()); + + reg_def VSR8 (SOC, SOC, Op_RegF, 8, VMRegImpl::Bad()); + reg_def VSR8_H (SOC, SOC, Op_RegF, 8, VMRegImpl::Bad()); + reg_def VSR8_J (SOC, SOC, Op_RegF, 8, VMRegImpl::Bad()); + reg_def VSR8_K (SOC, SOC, Op_RegF, 8, VMRegImpl::Bad()); + + reg_def VSR9 (SOC, SOC, Op_RegF, 9, VMRegImpl::Bad()); + reg_def VSR9_H (SOC, SOC, Op_RegF, 9, VMRegImpl::Bad()); + reg_def VSR9_J (SOC, SOC, Op_RegF, 9, VMRegImpl::Bad()); + reg_def VSR9_K (SOC, SOC, Op_RegF, 9, VMRegImpl::Bad()); + + reg_def VSR10 (SOC, SOC, Op_RegF, 10, VMRegImpl::Bad()); + reg_def VSR10_H(SOC, SOC, Op_RegF, 10, VMRegImpl::Bad()); + reg_def VSR10_J(SOC, SOC, Op_RegF, 10, VMRegImpl::Bad()); + reg_def VSR10_K(SOC, SOC, Op_RegF, 10, VMRegImpl::Bad()); + + reg_def VSR11 (SOC, SOC, Op_RegF, 11, VMRegImpl::Bad()); + reg_def VSR11_H(SOC, SOC, Op_RegF, 11, VMRegImpl::Bad()); + reg_def VSR11_J(SOC, SOC, Op_RegF, 11, VMRegImpl::Bad()); + reg_def VSR11_K(SOC, SOC, Op_RegF, 11, VMRegImpl::Bad()); + + reg_def VSR12 (SOC, SOC, Op_RegF, 12, VMRegImpl::Bad()); + reg_def VSR12_H(SOC, SOC, Op_RegF, 12, VMRegImpl::Bad()); + reg_def VSR12_J(SOC, SOC, Op_RegF, 12, VMRegImpl::Bad()); + reg_def VSR12_K(SOC, SOC, Op_RegF, 12, VMRegImpl::Bad()); + + reg_def VSR13 (SOC, SOC, Op_RegF, 13, VMRegImpl::Bad()); + reg_def VSR13_H(SOC, SOC, Op_RegF, 13, VMRegImpl::Bad()); + reg_def VSR13_J(SOC, SOC, Op_RegF, 13, VMRegImpl::Bad()); + reg_def VSR13_K(SOC, SOC, Op_RegF, 13, VMRegImpl::Bad()); + + reg_def VSR14 (SOC, SOC, Op_RegF, 14, VMRegImpl::Bad()); + reg_def VSR14_H(SOC, SOC, Op_RegF, 14, VMRegImpl::Bad()); + reg_def VSR14_J(SOC, SOC, Op_RegF, 14, VMRegImpl::Bad()); + reg_def VSR14_K(SOC, SOC, Op_RegF, 14, VMRegImpl::Bad()); + + reg_def VSR15 (SOC, SOC, Op_RegF, 15, VMRegImpl::Bad()); + reg_def VSR15_H(SOC, SOC, Op_RegF, 15, VMRegImpl::Bad()); + reg_def VSR15_J(SOC, SOC, Op_RegF, 15, VMRegImpl::Bad()); + reg_def VSR15_K(SOC, SOC, Op_RegF, 15, VMRegImpl::Bad()); + + reg_def VSR16 (SOC, SOC, Op_RegF, 16, VMRegImpl::Bad()); + reg_def VSR16_H(SOC, SOC, Op_RegF, 16, VMRegImpl::Bad()); + reg_def VSR16_J(SOC, SOC, Op_RegF, 16, VMRegImpl::Bad()); + reg_def VSR16_K(SOC, SOC, Op_RegF, 16, VMRegImpl::Bad()); + + reg_def VSR17 (SOC, SOC, Op_RegF, 17, VMRegImpl::Bad()); + reg_def VSR17_H(SOC, SOC, Op_RegF, 17, VMRegImpl::Bad()); + reg_def VSR17_J(SOC, SOC, Op_RegF, 17, VMRegImpl::Bad()); + reg_def VSR17_K(SOC, SOC, Op_RegF, 17, VMRegImpl::Bad()); + + reg_def VSR18 (SOC, SOC, Op_RegF, 18, VMRegImpl::Bad()); + reg_def VSR18_H(SOC, SOC, Op_RegF, 18, VMRegImpl::Bad()); + reg_def VSR18_J(SOC, SOC, Op_RegF, 18, VMRegImpl::Bad()); + reg_def VSR18_K(SOC, SOC, Op_RegF, 18, VMRegImpl::Bad()); + + reg_def VSR19 (SOC, SOC, Op_RegF, 19, VMRegImpl::Bad()); + reg_def VSR19_H(SOC, SOC, Op_RegF, 19, VMRegImpl::Bad()); + reg_def VSR19_J(SOC, SOC, Op_RegF, 19, VMRegImpl::Bad()); + reg_def VSR19_K(SOC, SOC, Op_RegF, 19, VMRegImpl::Bad()); + + reg_def VSR20 (SOC, SOC, Op_RegF, 20, VMRegImpl::Bad()); + reg_def VSR20_H(SOC, SOC, Op_RegF, 20, VMRegImpl::Bad()); + reg_def VSR20_J(SOC, SOC, Op_RegF, 20, VMRegImpl::Bad()); + reg_def VSR20_K(SOC, SOC, Op_RegF, 20, VMRegImpl::Bad()); + + reg_def VSR21 (SOC, SOC, Op_RegF, 21, VMRegImpl::Bad()); + reg_def VSR21_H(SOC, SOC, Op_RegF, 21, VMRegImpl::Bad()); + reg_def VSR21_J(SOC, SOC, Op_RegF, 21, VMRegImpl::Bad()); + reg_def VSR21_K(SOC, SOC, Op_RegF, 21, VMRegImpl::Bad()); + + reg_def VSR22 (SOC, SOC, Op_RegF, 22, VMRegImpl::Bad()); + reg_def VSR22_H(SOC, SOC, Op_RegF, 22, VMRegImpl::Bad()); + reg_def VSR22_J(SOC, SOC, Op_RegF, 22, VMRegImpl::Bad()); + reg_def VSR22_K(SOC, SOC, Op_RegF, 22, VMRegImpl::Bad()); + + reg_def VSR23 (SOC, SOC, Op_RegF, 23, VMRegImpl::Bad()); + reg_def VSR23_H(SOC, SOC, Op_RegF, 23, VMRegImpl::Bad()); + reg_def VSR23_J(SOC, SOC, Op_RegF, 23, VMRegImpl::Bad()); + reg_def VSR23_K(SOC, SOC, Op_RegF, 23, VMRegImpl::Bad()); + + reg_def VSR24 (SOC, SOC, Op_RegF, 24, VMRegImpl::Bad()); + reg_def VSR24_H(SOC, SOC, Op_RegF, 24, VMRegImpl::Bad()); + reg_def VSR24_J(SOC, SOC, Op_RegF, 24, VMRegImpl::Bad()); + reg_def VSR24_K(SOC, SOC, Op_RegF, 24, VMRegImpl::Bad()); + + reg_def VSR25 (SOC, SOC, Op_RegF, 25, VMRegImpl::Bad()); + reg_def VSR25_H(SOC, SOC, Op_RegF, 25, VMRegImpl::Bad()); + reg_def VSR25_J(SOC, SOC, Op_RegF, 25, VMRegImpl::Bad()); + reg_def VSR25_K(SOC, SOC, Op_RegF, 25, VMRegImpl::Bad()); + + reg_def VSR26 (SOC, SOC, Op_RegF, 26, VMRegImpl::Bad()); + reg_def VSR26_H(SOC, SOC, Op_RegF, 26, VMRegImpl::Bad()); + reg_def VSR26_J(SOC, SOC, Op_RegF, 26, VMRegImpl::Bad()); + reg_def VSR26_K(SOC, SOC, Op_RegF, 26, VMRegImpl::Bad()); + + reg_def VSR27 (SOC, SOC, Op_RegF, 27, VMRegImpl::Bad()); + reg_def VSR27_H(SOC, SOC, Op_RegF, 27, VMRegImpl::Bad()); + reg_def VSR27_J(SOC, SOC, Op_RegF, 27, VMRegImpl::Bad()); + reg_def VSR27_K(SOC, SOC, Op_RegF, 27, VMRegImpl::Bad()); + + reg_def VSR28 (SOC, SOC, Op_RegF, 28, VMRegImpl::Bad()); + reg_def VSR28_H(SOC, SOC, Op_RegF, 28, VMRegImpl::Bad()); + reg_def VSR28_J(SOC, SOC, Op_RegF, 28, VMRegImpl::Bad()); + reg_def VSR28_K(SOC, SOC, Op_RegF, 28, VMRegImpl::Bad()); + + reg_def VSR29 (SOC, SOC, Op_RegF, 29, VMRegImpl::Bad()); + reg_def VSR29_H(SOC, SOC, Op_RegF, 29, VMRegImpl::Bad()); + reg_def VSR29_J(SOC, SOC, Op_RegF, 29, VMRegImpl::Bad()); + reg_def VSR29_K(SOC, SOC, Op_RegF, 29, VMRegImpl::Bad()); + + reg_def VSR30 (SOC, SOC, Op_RegF, 30, VMRegImpl::Bad()); + reg_def VSR30_H(SOC, SOC, Op_RegF, 30, VMRegImpl::Bad()); + reg_def VSR30_J(SOC, SOC, Op_RegF, 30, VMRegImpl::Bad()); + reg_def VSR30_K(SOC, SOC, Op_RegF, 30, VMRegImpl::Bad()); + + reg_def VSR31 (SOC, SOC, Op_RegF, 31, VMRegImpl::Bad()); + reg_def VSR31_H(SOC, SOC, Op_RegF, 31, VMRegImpl::Bad()); + reg_def VSR31_J(SOC, SOC, Op_RegF, 31, VMRegImpl::Bad()); + reg_def VSR31_K(SOC, SOC, Op_RegF, 31, VMRegImpl::Bad()); + // 2nd 32 VSRs are aliases for the VRs which are only defined here. - reg_def VSR32 ( SOC, SOC, Op_VecX, 32, VSR32->as_VMReg()); - reg_def VSR33 ( SOC, SOC, Op_VecX, 33, VSR33->as_VMReg()); - reg_def VSR34 ( SOC, SOC, Op_VecX, 34, VSR34->as_VMReg()); - reg_def VSR35 ( SOC, SOC, Op_VecX, 35, VSR35->as_VMReg()); - reg_def VSR36 ( SOC, SOC, Op_VecX, 36, VSR36->as_VMReg()); - reg_def VSR37 ( SOC, SOC, Op_VecX, 37, VSR37->as_VMReg()); - reg_def VSR38 ( SOC, SOC, Op_VecX, 38, VSR38->as_VMReg()); - reg_def VSR39 ( SOC, SOC, Op_VecX, 39, VSR39->as_VMReg()); - reg_def VSR40 ( SOC, SOC, Op_VecX, 40, VSR40->as_VMReg()); - reg_def VSR41 ( SOC, SOC, Op_VecX, 41, VSR41->as_VMReg()); - reg_def VSR42 ( SOC, SOC, Op_VecX, 42, VSR42->as_VMReg()); - reg_def VSR43 ( SOC, SOC, Op_VecX, 43, VSR43->as_VMReg()); - reg_def VSR44 ( SOC, SOC, Op_VecX, 44, VSR44->as_VMReg()); - reg_def VSR45 ( SOC, SOC, Op_VecX, 45, VSR45->as_VMReg()); - reg_def VSR46 ( SOC, SOC, Op_VecX, 46, VSR46->as_VMReg()); - reg_def VSR47 ( SOC, SOC, Op_VecX, 47, VSR47->as_VMReg()); - reg_def VSR48 ( SOC, SOC, Op_VecX, 48, VSR48->as_VMReg()); - reg_def VSR49 ( SOC, SOC, Op_VecX, 49, VSR49->as_VMReg()); - reg_def VSR50 ( SOC, SOC, Op_VecX, 50, VSR50->as_VMReg()); - reg_def VSR51 ( SOC, SOC, Op_VecX, 51, VSR51->as_VMReg()); - reg_def VSR52 ( SOC, SOE, Op_VecX, 52, VSR52->as_VMReg()); - reg_def VSR53 ( SOC, SOE, Op_VecX, 53, VSR53->as_VMReg()); - reg_def VSR54 ( SOC, SOE, Op_VecX, 54, VSR54->as_VMReg()); - reg_def VSR55 ( SOC, SOE, Op_VecX, 55, VSR55->as_VMReg()); - reg_def VSR56 ( SOC, SOE, Op_VecX, 56, VSR56->as_VMReg()); - reg_def VSR57 ( SOC, SOE, Op_VecX, 57, VSR57->as_VMReg()); - reg_def VSR58 ( SOC, SOE, Op_VecX, 58, VSR58->as_VMReg()); - reg_def VSR59 ( SOC, SOE, Op_VecX, 59, VSR59->as_VMReg()); - reg_def VSR60 ( SOC, SOE, Op_VecX, 60, VSR60->as_VMReg()); - reg_def VSR61 ( SOC, SOE, Op_VecX, 61, VSR61->as_VMReg()); - reg_def VSR62 ( SOC, SOE, Op_VecX, 62, VSR62->as_VMReg()); - reg_def VSR63 ( SOC, SOE, Op_VecX, 63, VSR63->as_VMReg()); + reg_def VSR32 (SOC, SOC, Op_RegF, 32, VSR32->as_VMReg() ); + reg_def VSR32_H(SOC, SOC, Op_RegF, 32, VSR32->as_VMReg()->next() ); + reg_def VSR32_J(SOC, SOC, Op_RegF, 32, VSR32->as_VMReg()->next(2)); + reg_def VSR32_K(SOC, SOC, Op_RegF, 32, VSR32->as_VMReg()->next(3)); + + reg_def VSR33 (SOC, SOC, Op_RegF, 33, VSR33->as_VMReg() ); + reg_def VSR33_H(SOC, SOC, Op_RegF, 33, VSR33->as_VMReg()->next() ); + reg_def VSR33_J(SOC, SOC, Op_RegF, 33, VSR33->as_VMReg()->next(2)); + reg_def VSR33_K(SOC, SOC, Op_RegF, 33, VSR33->as_VMReg()->next(3)); + + reg_def VSR34 (SOC, SOC, Op_RegF, 34, VSR34->as_VMReg() ); + reg_def VSR34_H(SOC, SOC, Op_RegF, 34, VSR34->as_VMReg()->next() ); + reg_def VSR34_J(SOC, SOC, Op_RegF, 34, VSR34->as_VMReg()->next(2)); + reg_def VSR34_K(SOC, SOC, Op_RegF, 34, VSR34->as_VMReg()->next(3)); + + reg_def VSR35 (SOC, SOC, Op_RegF, 35, VSR35->as_VMReg() ); + reg_def VSR35_H(SOC, SOC, Op_RegF, 35, VSR35->as_VMReg()->next() ); + reg_def VSR35_J(SOC, SOC, Op_RegF, 35, VSR35->as_VMReg()->next(2)); + reg_def VSR35_K(SOC, SOC, Op_RegF, 35, VSR35->as_VMReg()->next(3)); + + reg_def VSR36 (SOC, SOC, Op_RegF, 36, VSR36->as_VMReg() ); + reg_def VSR36_H(SOC, SOC, Op_RegF, 36, VSR36->as_VMReg()->next() ); + reg_def VSR36_J(SOC, SOC, Op_RegF, 36, VSR36->as_VMReg()->next(2)); + reg_def VSR36_K(SOC, SOC, Op_RegF, 36, VSR36->as_VMReg()->next(3)); + + reg_def VSR37 (SOC, SOC, Op_RegF, 37, VSR37->as_VMReg() ); + reg_def VSR37_H(SOC, SOC, Op_RegF, 37, VSR37->as_VMReg()->next() ); + reg_def VSR37_J(SOC, SOC, Op_RegF, 37, VSR37->as_VMReg()->next(2)); + reg_def VSR37_K(SOC, SOC, Op_RegF, 37, VSR37->as_VMReg()->next(3)); + + reg_def VSR38 (SOC, SOC, Op_RegF, 38, VSR38->as_VMReg() ); + reg_def VSR38_H(SOC, SOC, Op_RegF, 38, VSR38->as_VMReg()->next() ); + reg_def VSR38_J(SOC, SOC, Op_RegF, 38, VSR38->as_VMReg()->next(2)); + reg_def VSR38_K(SOC, SOC, Op_RegF, 38, VSR38->as_VMReg()->next(3)); + + reg_def VSR39 (SOC, SOC, Op_RegF, 39, VSR39->as_VMReg() ); + reg_def VSR39_H(SOC, SOC, Op_RegF, 39, VSR39->as_VMReg()->next() ); + reg_def VSR39_J(SOC, SOC, Op_RegF, 39, VSR39->as_VMReg()->next(2)); + reg_def VSR39_K(SOC, SOC, Op_RegF, 39, VSR39->as_VMReg()->next(3)); + + reg_def VSR40 (SOC, SOC, Op_RegF, 40, VSR40->as_VMReg() ); + reg_def VSR40_H(SOC, SOC, Op_RegF, 40, VSR40->as_VMReg()->next() ); + reg_def VSR40_J(SOC, SOC, Op_RegF, 40, VSR40->as_VMReg()->next(2)); + reg_def VSR40_K(SOC, SOC, Op_RegF, 40, VSR40->as_VMReg()->next(3)); + + reg_def VSR41 (SOC, SOC, Op_RegF, 41, VSR41->as_VMReg() ); + reg_def VSR41_H(SOC, SOC, Op_RegF, 41, VSR41->as_VMReg()->next() ); + reg_def VSR41_J(SOC, SOC, Op_RegF, 41, VSR41->as_VMReg()->next(2)); + reg_def VSR41_K(SOC, SOC, Op_RegF, 41, VSR41->as_VMReg()->next(3)); + + reg_def VSR42 (SOC, SOC, Op_RegF, 42, VSR42->as_VMReg() ); + reg_def VSR42_H(SOC, SOC, Op_RegF, 42, VSR42->as_VMReg()->next() ); + reg_def VSR42_J(SOC, SOC, Op_RegF, 42, VSR42->as_VMReg()->next(2)); + reg_def VSR42_K(SOC, SOC, Op_RegF, 42, VSR42->as_VMReg()->next(3)); + + reg_def VSR43 (SOC, SOC, Op_RegF, 43, VSR43->as_VMReg() ); + reg_def VSR43_H(SOC, SOC, Op_RegF, 43, VSR43->as_VMReg()->next() ); + reg_def VSR43_J(SOC, SOC, Op_RegF, 43, VSR43->as_VMReg()->next(2)); + reg_def VSR43_K(SOC, SOC, Op_RegF, 43, VSR43->as_VMReg()->next(3)); + + reg_def VSR44 (SOC, SOC, Op_RegF, 44, VSR44->as_VMReg() ); + reg_def VSR44_H(SOC, SOC, Op_RegF, 44, VSR44->as_VMReg()->next() ); + reg_def VSR44_J(SOC, SOC, Op_RegF, 44, VSR44->as_VMReg()->next(2)); + reg_def VSR44_K(SOC, SOC, Op_RegF, 44, VSR44->as_VMReg()->next(3)); + + reg_def VSR45 (SOC, SOC, Op_RegF, 45, VSR45->as_VMReg() ); + reg_def VSR45_H(SOC, SOC, Op_RegF, 45, VSR45->as_VMReg()->next() ); + reg_def VSR45_J(SOC, SOC, Op_RegF, 45, VSR45->as_VMReg()->next(2)); + reg_def VSR45_K(SOC, SOC, Op_RegF, 45, VSR45->as_VMReg()->next(3)); + + reg_def VSR46 (SOC, SOC, Op_RegF, 46, VSR46->as_VMReg() ); + reg_def VSR46_H(SOC, SOC, Op_RegF, 46, VSR46->as_VMReg()->next() ); + reg_def VSR46_J(SOC, SOC, Op_RegF, 46, VSR46->as_VMReg()->next(2)); + reg_def VSR46_K(SOC, SOC, Op_RegF, 46, VSR46->as_VMReg()->next(3)); + + reg_def VSR47 (SOC, SOC, Op_RegF, 47, VSR47->as_VMReg() ); + reg_def VSR47_H(SOC, SOC, Op_RegF, 47, VSR47->as_VMReg()->next() ); + reg_def VSR47_J(SOC, SOC, Op_RegF, 47, VSR47->as_VMReg()->next(2)); + reg_def VSR47_K(SOC, SOC, Op_RegF, 47, VSR47->as_VMReg()->next(3)); + + reg_def VSR48 (SOC, SOC, Op_RegF, 48, VSR48->as_VMReg() ); + reg_def VSR48_H(SOC, SOC, Op_RegF, 48, VSR48->as_VMReg()->next() ); + reg_def VSR48_J(SOC, SOC, Op_RegF, 48, VSR48->as_VMReg()->next(2)); + reg_def VSR48_K(SOC, SOC, Op_RegF, 48, VSR48->as_VMReg()->next(3)); + + reg_def VSR49 (SOC, SOC, Op_RegF, 49, VSR49->as_VMReg() ); + reg_def VSR49_H(SOC, SOC, Op_RegF, 49, VSR49->as_VMReg()->next() ); + reg_def VSR49_J(SOC, SOC, Op_RegF, 49, VSR49->as_VMReg()->next(2)); + reg_def VSR49_K(SOC, SOC, Op_RegF, 49, VSR49->as_VMReg()->next(3)); + + reg_def VSR50 (SOC, SOC, Op_RegF, 50, VSR50->as_VMReg() ); + reg_def VSR50_H(SOC, SOC, Op_RegF, 50, VSR50->as_VMReg()->next() ); + reg_def VSR50_J(SOC, SOC, Op_RegF, 50, VSR50->as_VMReg()->next(2)); + reg_def VSR50_K(SOC, SOC, Op_RegF, 50, VSR50->as_VMReg()->next(3)); + + reg_def VSR51 (SOC, SOC, Op_RegF, 51, VSR51->as_VMReg() ); + reg_def VSR51_H(SOC, SOC, Op_RegF, 51, VSR51->as_VMReg()->next() ); + reg_def VSR51_J(SOC, SOC, Op_RegF, 51, VSR51->as_VMReg()->next(2)); + reg_def VSR51_K(SOC, SOC, Op_RegF, 51, VSR51->as_VMReg()->next(3)); + + reg_def VSR52 (SOC, SOE, Op_RegF, 52, VSR52->as_VMReg() ); + reg_def VSR52_H(SOC, SOE, Op_RegF, 52, VSR52->as_VMReg()->next() ); + reg_def VSR52_J(SOC, SOE, Op_RegF, 52, VSR52->as_VMReg()->next(2)); + reg_def VSR52_K(SOC, SOE, Op_RegF, 52, VSR52->as_VMReg()->next(3)); + + reg_def VSR53 (SOC, SOE, Op_RegF, 53, VSR53->as_VMReg() ); + reg_def VSR53_H(SOC, SOE, Op_RegF, 53, VSR53->as_VMReg()->next() ); + reg_def VSR53_J(SOC, SOE, Op_RegF, 53, VSR53->as_VMReg()->next(2)); + reg_def VSR53_K(SOC, SOE, Op_RegF, 53, VSR53->as_VMReg()->next(3)); + + reg_def VSR54 (SOC, SOE, Op_RegF, 54, VSR54->as_VMReg() ); + reg_def VSR54_H(SOC, SOE, Op_RegF, 54, VSR54->as_VMReg()->next() ); + reg_def VSR54_J(SOC, SOE, Op_RegF, 54, VSR54->as_VMReg()->next(2)); + reg_def VSR54_K(SOC, SOE, Op_RegF, 54, VSR54->as_VMReg()->next(3)); + + reg_def VSR55 (SOC, SOE, Op_RegF, 55, VSR55->as_VMReg() ); + reg_def VSR55_H(SOC, SOE, Op_RegF, 55, VSR55->as_VMReg()->next() ); + reg_def VSR55_J(SOC, SOE, Op_RegF, 55, VSR55->as_VMReg()->next(2)); + reg_def VSR55_K(SOC, SOE, Op_RegF, 55, VSR55->as_VMReg()->next(3)); + + reg_def VSR56 (SOC, SOE, Op_RegF, 56, VSR56->as_VMReg() ); + reg_def VSR56_H(SOC, SOE, Op_RegF, 56, VSR56->as_VMReg()->next() ); + reg_def VSR56_J(SOC, SOE, Op_RegF, 56, VSR56->as_VMReg()->next(2)); + reg_def VSR56_K(SOC, SOE, Op_RegF, 56, VSR56->as_VMReg()->next(3)); + + reg_def VSR57 (SOC, SOE, Op_RegF, 57, VSR57->as_VMReg() ); + reg_def VSR57_H(SOC, SOE, Op_RegF, 57, VSR57->as_VMReg()->next() ); + reg_def VSR57_J(SOC, SOE, Op_RegF, 57, VSR57->as_VMReg()->next(2)); + reg_def VSR57_K(SOC, SOE, Op_RegF, 57, VSR57->as_VMReg()->next(3)); + + reg_def VSR58 (SOC, SOE, Op_RegF, 58, VSR58->as_VMReg() ); + reg_def VSR58_H(SOC, SOE, Op_RegF, 58, VSR58->as_VMReg()->next() ); + reg_def VSR58_J(SOC, SOE, Op_RegF, 58, VSR58->as_VMReg()->next(2)); + reg_def VSR58_K(SOC, SOE, Op_RegF, 58, VSR58->as_VMReg()->next(3)); + + reg_def VSR59 (SOC, SOE, Op_RegF, 59, VSR59->as_VMReg() ); + reg_def VSR59_H(SOC, SOE, Op_RegF, 59, VSR59->as_VMReg()->next() ); + reg_def VSR59_J(SOC, SOE, Op_RegF, 59, VSR59->as_VMReg()->next(2)); + reg_def VSR59_K(SOC, SOE, Op_RegF, 59, VSR59->as_VMReg()->next(3)); + + reg_def VSR60 (SOC, SOE, Op_RegF, 60, VSR60->as_VMReg() ); + reg_def VSR60_H(SOC, SOE, Op_RegF, 60, VSR60->as_VMReg()->next() ); + reg_def VSR60_J(SOC, SOE, Op_RegF, 60, VSR60->as_VMReg()->next(2)); + reg_def VSR60_K(SOC, SOE, Op_RegF, 60, VSR60->as_VMReg()->next(3)); + + reg_def VSR61 (SOC, SOE, Op_RegF, 61, VSR61->as_VMReg() ); + reg_def VSR61_H(SOC, SOE, Op_RegF, 61, VSR61->as_VMReg()->next() ); + reg_def VSR61_J(SOC, SOE, Op_RegF, 61, VSR61->as_VMReg()->next(2)); + reg_def VSR61_K(SOC, SOE, Op_RegF, 61, VSR61->as_VMReg()->next(3)); + + reg_def VSR62 (SOC, SOE, Op_RegF, 62, VSR62->as_VMReg() ); + reg_def VSR62_H(SOC, SOE, Op_RegF, 62, VSR62->as_VMReg()->next() ); + reg_def VSR62_J(SOC, SOE, Op_RegF, 62, VSR62->as_VMReg()->next(2)); + reg_def VSR62_K(SOC, SOE, Op_RegF, 62, VSR62->as_VMReg()->next(3)); + + reg_def VSR63 (SOC, SOE, Op_RegF, 63, VSR63->as_VMReg() ); + reg_def VSR63_H(SOC, SOE, Op_RegF, 63, VSR63->as_VMReg()->next() ); + reg_def VSR63_J(SOC, SOE, Op_RegF, 63, VSR63->as_VMReg()->next(2)); + reg_def VSR63_K(SOC, SOE, Op_RegF, 63, VSR63->as_VMReg()->next(3)); // ---------------------------- // Specify priority of register selection within phases of register @@ -441,8 +696,74 @@ alloc_class chunk1 ( ); alloc_class chunk2 ( - // Chunk2 contains *all* 8 condition code registers. + VSR0 , VSR0_H , VSR0_J , VSR0_K , + VSR1 , VSR1_H , VSR1_J , VSR1_K , + VSR2 , VSR2_H , VSR2_J , VSR2_K , + VSR3 , VSR3_H , VSR3_J , VSR3_K , + VSR4 , VSR4_H , VSR4_J , VSR4_K , + VSR5 , VSR5_H , VSR5_J , VSR5_K , + VSR6 , VSR6_H , VSR6_J , VSR6_K , + VSR7 , VSR7_H , VSR7_J , VSR7_K , + VSR8 , VSR8_H , VSR8_J , VSR8_K , + VSR9 , VSR9_H , VSR9_J , VSR9_K , + VSR10, VSR10_H, VSR10_J, VSR10_K, + VSR11, VSR11_H, VSR11_J, VSR11_K, + VSR12, VSR12_H, VSR12_J, VSR12_K, + VSR13, VSR13_H, VSR13_J, VSR13_K, + VSR14, VSR14_H, VSR14_J, VSR14_K, + VSR15, VSR15_H, VSR15_J, VSR15_K, + VSR16, VSR16_H, VSR16_J, VSR16_K, + VSR17, VSR17_H, VSR17_J, VSR17_K, + VSR18, VSR18_H, VSR18_J, VSR18_K, + VSR19, VSR19_H, VSR19_J, VSR19_K, + VSR20, VSR20_H, VSR20_J, VSR20_K, + VSR21, VSR21_H, VSR21_J, VSR21_K, + VSR22, VSR22_H, VSR22_J, VSR22_K, + VSR23, VSR23_H, VSR23_J, VSR23_K, + VSR24, VSR24_H, VSR24_J, VSR24_K, + VSR25, VSR25_H, VSR25_J, VSR25_K, + VSR26, VSR26_H, VSR26_J, VSR26_K, + VSR27, VSR27_H, VSR27_J, VSR27_K, + VSR28, VSR28_H, VSR28_J, VSR28_K, + VSR29, VSR29_H, VSR29_J, VSR29_K, + VSR30, VSR30_H, VSR30_J, VSR30_K, + VSR31, VSR31_H, VSR31_J, VSR31_K, + VSR32, VSR32_H, VSR32_J, VSR32_K, + VSR33, VSR33_H, VSR33_J, VSR33_K, + VSR34, VSR34_H, VSR34_J, VSR34_K, + VSR35, VSR35_H, VSR35_J, VSR35_K, + VSR36, VSR36_H, VSR36_J, VSR36_K, + VSR37, VSR37_H, VSR37_J, VSR37_K, + VSR38, VSR38_H, VSR38_J, VSR38_K, + VSR39, VSR39_H, VSR39_J, VSR39_K, + VSR40, VSR40_H, VSR40_J, VSR40_K, + VSR41, VSR41_H, VSR41_J, VSR41_K, + VSR42, VSR42_H, VSR42_J, VSR42_K, + VSR43, VSR43_H, VSR43_J, VSR43_K, + VSR44, VSR44_H, VSR44_J, VSR44_K, + VSR45, VSR45_H, VSR45_J, VSR45_K, + VSR46, VSR46_H, VSR46_J, VSR46_K, + VSR47, VSR47_H, VSR47_J, VSR47_K, + VSR48, VSR48_H, VSR48_J, VSR48_K, + VSR49, VSR49_H, VSR49_J, VSR49_K, + VSR50, VSR50_H, VSR50_J, VSR50_K, + VSR51, VSR51_H, VSR51_J, VSR51_K, + VSR52, VSR52_H, VSR52_J, VSR52_K, + VSR53, VSR53_H, VSR53_J, VSR53_K, + VSR54, VSR54_H, VSR54_J, VSR54_K, + VSR55, VSR55_H, VSR55_J, VSR55_K, + VSR56, VSR56_H, VSR56_J, VSR56_K, + VSR57, VSR57_H, VSR57_J, VSR57_K, + VSR58, VSR58_H, VSR58_J, VSR58_K, + VSR59, VSR59_H, VSR59_J, VSR59_K, + VSR60, VSR60_H, VSR60_J, VSR60_K, + VSR61, VSR61_H, VSR61_J, VSR61_K, + VSR62, VSR62_H, VSR62_J, VSR62_K, + VSR63, VSR63_H, VSR63_J, VSR63_K +); +alloc_class chunk3 ( + // Chunk2 contains *all* 8 condition code registers. CR0, CR1, CR2, @@ -453,73 +774,6 @@ alloc_class chunk2 ( CR7 ); -alloc_class chunk3 ( - VSR0, - VSR1, - VSR2, - VSR3, - VSR4, - VSR5, - VSR6, - VSR7, - VSR8, - VSR9, - VSR10, - VSR11, - VSR12, - VSR13, - VSR14, - VSR15, - VSR16, - VSR17, - VSR18, - VSR19, - VSR20, - VSR21, - VSR22, - VSR23, - VSR24, - VSR25, - VSR26, - VSR27, - VSR28, - VSR29, - VSR30, - VSR31, - VSR32, - VSR33, - VSR34, - VSR35, - VSR36, - VSR37, - VSR38, - VSR39, - VSR40, - VSR41, - VSR42, - VSR43, - VSR44, - VSR45, - VSR46, - VSR47, - VSR48, - VSR49, - VSR50, - VSR51, - VSR52, - VSR53, - VSR54, - VSR55, - VSR56, - VSR57, - VSR58, - VSR59, - VSR60, - VSR61, - VSR62, - VSR63 -); - alloc_class chunk4 ( // special registers // These registers are not allocated, but used for nodes generated by postalloc expand. @@ -910,28 +1164,38 @@ reg_class dbl_reg( // ---------------------------- reg_class vs_reg( - // Attention: Only these ones are saved & restored at safepoint by RegisterSaver. - VSR32, - VSR33, - VSR34, - VSR35, - VSR36, - VSR37, - VSR38, - VSR39, - VSR40, - VSR41, - VSR42, - VSR43, - VSR44, - VSR45, - VSR46, - VSR47, - VSR48, - VSR49, - VSR50, - VSR51 - // VSR52-VSR63 // nv! + VSR32, VSR32_H, VSR32_J, VSR32_K, + VSR33, VSR33_H, VSR33_J, VSR33_K, + VSR34, VSR34_H, VSR34_J, VSR34_K, + VSR35, VSR35_H, VSR35_J, VSR35_K, + VSR36, VSR36_H, VSR36_J, VSR36_K, + VSR37, VSR37_H, VSR37_J, VSR37_K, + VSR38, VSR38_H, VSR38_J, VSR38_K, + VSR39, VSR39_H, VSR39_J, VSR39_K, + VSR40, VSR40_H, VSR40_J, VSR40_K, + VSR41, VSR41_H, VSR41_J, VSR41_K, + VSR42, VSR42_H, VSR42_J, VSR42_K, + VSR43, VSR43_H, VSR43_J, VSR43_K, + VSR44, VSR44_H, VSR44_J, VSR44_K, + VSR45, VSR45_H, VSR45_J, VSR45_K, + VSR46, VSR46_H, VSR46_J, VSR46_K, + VSR47, VSR47_H, VSR47_J, VSR47_K, + VSR48, VSR48_H, VSR48_J, VSR48_K, + VSR49, VSR49_H, VSR49_J, VSR49_K, + VSR50, VSR50_H, VSR50_J, VSR50_K, + VSR51, VSR51_H, VSR51_J, VSR51_K, + VSR52, VSR52_H, VSR52_J, VSR52_K, // non-volatile + VSR53, VSR53_H, VSR53_J, VSR53_K, // non-volatile + VSR54, VSR54_H, VSR54_J, VSR54_K, // non-volatile + VSR55, VSR55_H, VSR55_J, VSR55_K, // non-volatile + VSR56, VSR56_H, VSR56_J, VSR56_K, // non-volatile + VSR57, VSR57_H, VSR57_J, VSR57_K, // non-volatile + VSR58, VSR58_H, VSR58_J, VSR58_K, // non-volatile + VSR59, VSR59_H, VSR59_J, VSR59_K, // non-volatile + VSR60, VSR60_H, VSR60_J, VSR60_K, // non-volatile + VSR61, VSR61_H, VSR61_J, VSR61_K, // non-volatile + VSR62, VSR62_H, VSR62_J, VSR62_K, // non-volatile + VSR63, VSR63_H, VSR63_J, VSR63_K // non-volatile ); %} @@ -1656,17 +1920,19 @@ static enum RC rc_class(OptoReg::Name reg) { if (reg == OptoReg::Bad) return rc_bad; // We have 64 integer register halves, starting at index 0. - if (reg < 64) return rc_int; + STATIC_ASSERT((int)ConcreteRegisterImpl::max_gpr == (int)MachRegisterNumbers::F0_num); + if (reg < ConcreteRegisterImpl::max_gpr) return rc_int; // We have 64 floating-point register halves, starting at index 64. - if (reg < 64+64) return rc_float; + STATIC_ASSERT((int)ConcreteRegisterImpl::max_fpr == (int)MachRegisterNumbers::VSR0_num); + if (reg < ConcreteRegisterImpl::max_fpr) return rc_float; // We have 64 vector-scalar registers, starting at index 128. - if (reg < 64+64+64) return rc_vs; - - // Between float regs & stack are the flags regs. - assert(OptoReg::is_stack(reg) || reg < 64+64+64, "blow up if spilling flags"); + STATIC_ASSERT((int)ConcreteRegisterImpl::max_vsr == (int)MachRegisterNumbers::CR0_num); + if (reg < ConcreteRegisterImpl::max_vsr) return rc_vs; + // Condition and special purpose registers are not allocated. We only accept stack from here. + assert(OptoReg::is_stack(reg), "what else is it?"); return rc_stack; } @@ -1743,21 +2009,53 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r else if (src_lo_rc == rc_vs && dst_lo_rc == rc_stack) { VectorSRegister Rsrc = as_VectorSRegister(Matcher::_regEncode[src_lo]); int dst_offset = ra_->reg2offset(dst_lo); - if (masm) { - __ addi(R0, R1_SP, dst_offset); - __ stxvd2x(Rsrc, R0); + if (PowerArchitecturePPC64 >= 9) { + if (is_aligned(dst_offset, 16)) { + if (masm) { + __ stxv(Rsrc, dst_offset, R1_SP); // matches storeV16_Power9 + } + size += 4; + } else { + // Other alignment can be used by Vector API (VectorPayload in rearrangeOp, + // observed with VectorRearrangeTest.java on Power9). + if (masm) { + __ addi(R0, R1_SP, dst_offset); + __ stxvx(Rsrc, R0); // matches storeV16_Power9 (regarding element ordering) + } + size += 8; + } + } else { + if (masm) { + __ addi(R0, R1_SP, dst_offset); + __ stxvd2x(Rsrc, R0); // matches storeV16_Power8 + } + size += 8; } - size += 8; } // Memory->VectorSRegister Spill. else if (src_lo_rc == rc_stack && dst_lo_rc == rc_vs) { VectorSRegister Rdst = as_VectorSRegister(Matcher::_regEncode[dst_lo]); int src_offset = ra_->reg2offset(src_lo); - if (masm) { - __ addi(R0, R1_SP, src_offset); - __ lxvd2x(Rdst, R0); + if (PowerArchitecturePPC64 >= 9) { + if (is_aligned(src_offset, 16)) { + if (masm) { + __ lxv(Rdst, src_offset, R1_SP); + } + size += 4; + } else { + if (masm) { + __ addi(R0, R1_SP, src_offset); + __ lxvx(Rdst, R0); + } + size += 8; + } + } else { + if (masm) { + __ addi(R0, R1_SP, src_offset); + __ lxvd2x(Rdst, R0); + } + size += 8; } - size += 8; } // VectorSRegister->VectorSRegister. else if (src_lo_rc == rc_vs && dst_lo_rc == rc_vs) { @@ -2064,10 +2362,6 @@ bool Matcher::match_rule_supported(int opcode) { } switch (opcode) { - case Op_SqrtD: - return VM_Version::has_fsqrt(); - case Op_RoundDoubleMode: - return VM_Version::has_vsx(); case Op_CountLeadingZerosI: case Op_CountLeadingZerosL: return UseCountLeadingZerosInstructionsPPC64; @@ -2076,11 +2370,10 @@ bool Matcher::match_rule_supported(int opcode) { return (UseCountLeadingZerosInstructionsPPC64 || UseCountTrailingZerosInstructionsPPC64); case Op_PopCountI: case Op_PopCountL: - return (UsePopCountInstruction && VM_Version::has_popcntw()); + return UsePopCountInstruction; case Op_ConvF2HF: case Op_ConvHF2F: return VM_Version::supports_float16(); - case Op_AddVB: case Op_AddVS: case Op_AddVI: @@ -2106,6 +2399,18 @@ bool Matcher::match_rule_supported(int opcode) { case Op_SubVL: case Op_MulVI: case Op_RoundDoubleModeV: + case Op_MinV: + case Op_MaxV: + case Op_AndV: + case Op_OrV: + case Op_XorV: + case Op_AddReductionVI: + case Op_MulReductionVI: + case Op_AndReductionV: + case Op_OrReductionV: + case Op_XorReductionV: + case Op_MinReductionV: + case Op_MaxReductionV: return SuperwordUseVSX; case Op_PopCountVI: case Op_PopCountVL: @@ -2147,6 +2452,22 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { if (!match_rule_supported(opcode) || !vector_size_supported(bt, vlen)) { return false; } + // Special cases + switch (opcode) { + // Reductions only support INT at the moment. + case Op_AddReductionVI: + case Op_MulReductionVI: + case Op_AndReductionV: + case Op_OrReductionV: + case Op_XorReductionV: + case Op_MinReductionV: + case Op_MaxReductionV: + return bt == T_INT; + // MaxV, MinV need types == INT || LONG. + case Op_MaxV: + case Op_MinV: + return bt == T_INT || bt == T_LONG; + } return true; // Per default match rules are supported. } @@ -2265,52 +2586,11 @@ bool Matcher::is_generic_vector(MachOper* opnd) { return false; } -// Constants for c2c and c calling conventions. - -const MachRegisterNumbers iarg_reg[8] = { - R3_num, R4_num, R5_num, R6_num, - R7_num, R8_num, R9_num, R10_num -}; - -const MachRegisterNumbers farg_reg[13] = { - F1_num, F2_num, F3_num, F4_num, - F5_num, F6_num, F7_num, F8_num, - F9_num, F10_num, F11_num, F12_num, - F13_num -}; - -const MachRegisterNumbers vsarg_reg[64] = { - VSR0_num, VSR1_num, VSR2_num, VSR3_num, - VSR4_num, VSR5_num, VSR6_num, VSR7_num, - VSR8_num, VSR9_num, VSR10_num, VSR11_num, - VSR12_num, VSR13_num, VSR14_num, VSR15_num, - VSR16_num, VSR17_num, VSR18_num, VSR19_num, - VSR20_num, VSR21_num, VSR22_num, VSR23_num, - VSR24_num, VSR23_num, VSR24_num, VSR25_num, - VSR28_num, VSR29_num, VSR30_num, VSR31_num, - VSR32_num, VSR33_num, VSR34_num, VSR35_num, - VSR36_num, VSR37_num, VSR38_num, VSR39_num, - VSR40_num, VSR41_num, VSR42_num, VSR43_num, - VSR44_num, VSR45_num, VSR46_num, VSR47_num, - VSR48_num, VSR49_num, VSR50_num, VSR51_num, - VSR52_num, VSR53_num, VSR54_num, VSR55_num, - VSR56_num, VSR57_num, VSR58_num, VSR59_num, - VSR60_num, VSR61_num, VSR62_num, VSR63_num -}; - -const int num_iarg_registers = sizeof(iarg_reg) / sizeof(iarg_reg[0]); - -const int num_farg_registers = sizeof(farg_reg) / sizeof(farg_reg[0]); - -const int num_vsarg_registers = sizeof(vsarg_reg) / sizeof(vsarg_reg[0]); - // Return whether or not this register is ever used as an argument. This // function is used on startup to build the trampoline stubs in generateOptoStub. // Registers not mentioned will be killed by the VM call in the trampoline, and // arguments in those registers not be available to the callee. bool Matcher::can_be_java_arg(int reg) { - // We return true for all registers contained in iarg_reg[] and - // farg_reg[] and their virtual halves. // We must include the virtual halves in order to get STDs and LDs // instead of STWs and LWs in the trampoline stubs. @@ -2928,85 +3208,42 @@ encode %{ %} enc_class postalloc_expand_encode_oop(iRegNdst dst, iRegPdst src, flagsReg crx) %{ + // use isel instruction with Power 7 + cmpP_reg_imm16Node *n_compare = new cmpP_reg_imm16Node(); + encodeP_subNode *n_sub_base = new encodeP_subNode(); + encodeP_shiftNode *n_shift = new encodeP_shiftNode(); + cond_set_0_oopNode *n_cond_set = new cond_set_0_oopNode(); - if (VM_Version::has_isel()) { - // use isel instruction with Power 7 - cmpP_reg_imm16Node *n_compare = new cmpP_reg_imm16Node(); - encodeP_subNode *n_sub_base = new encodeP_subNode(); - encodeP_shiftNode *n_shift = new encodeP_shiftNode(); - cond_set_0_oopNode *n_cond_set = new cond_set_0_oopNode(); - - n_compare->add_req(n_region, n_src); - n_compare->_opnds[0] = op_crx; - n_compare->_opnds[1] = op_src; - n_compare->_opnds[2] = new immL16Oper(0); - - n_sub_base->add_req(n_region, n_src); - n_sub_base->_opnds[0] = op_dst; - n_sub_base->_opnds[1] = op_src; - n_sub_base->_bottom_type = _bottom_type; - - n_shift->add_req(n_region, n_sub_base); - n_shift->_opnds[0] = op_dst; - n_shift->_opnds[1] = op_dst; - n_shift->_bottom_type = _bottom_type; - - n_cond_set->add_req(n_region, n_compare, n_shift); - n_cond_set->_opnds[0] = op_dst; - n_cond_set->_opnds[1] = op_crx; - n_cond_set->_opnds[2] = op_dst; - n_cond_set->_bottom_type = _bottom_type; - - ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); - ra_->set_pair(n_sub_base->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - ra_->set_pair(n_shift->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - ra_->set_pair(n_cond_set->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - - nodes->push(n_compare); - nodes->push(n_sub_base); - nodes->push(n_shift); - nodes->push(n_cond_set); + n_compare->add_req(n_region, n_src); + n_compare->_opnds[0] = op_crx; + n_compare->_opnds[1] = op_src; + n_compare->_opnds[2] = new immL16Oper(0); - } else { - // before Power 7 - moveRegNode *n_move = new moveRegNode(); - cmpP_reg_imm16Node *n_compare = new cmpP_reg_imm16Node(); - encodeP_shiftNode *n_shift = new encodeP_shiftNode(); - cond_sub_baseNode *n_sub_base = new cond_sub_baseNode(); - - n_move->add_req(n_region, n_src); - n_move->_opnds[0] = op_dst; - n_move->_opnds[1] = op_src; - ra_->set_oop(n_move, true); // Until here, 'n_move' still produces an oop. - - n_compare->add_req(n_region, n_src); - n_compare->add_prec(n_move); - - n_compare->_opnds[0] = op_crx; - n_compare->_opnds[1] = op_src; - n_compare->_opnds[2] = new immL16Oper(0); - - n_sub_base->add_req(n_region, n_compare, n_src); - n_sub_base->_opnds[0] = op_dst; - n_sub_base->_opnds[1] = op_crx; - n_sub_base->_opnds[2] = op_src; - n_sub_base->_bottom_type = _bottom_type; - - n_shift->add_req(n_region, n_sub_base); - n_shift->_opnds[0] = op_dst; - n_shift->_opnds[1] = op_dst; - n_shift->_bottom_type = _bottom_type; - - ra_->set_pair(n_shift->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); - ra_->set_pair(n_sub_base->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - ra_->set_pair(n_move->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - - nodes->push(n_move); - nodes->push(n_compare); - nodes->push(n_sub_base); - nodes->push(n_shift); - } + n_sub_base->add_req(n_region, n_src); + n_sub_base->_opnds[0] = op_dst; + n_sub_base->_opnds[1] = op_src; + n_sub_base->_bottom_type = _bottom_type; + + n_shift->add_req(n_region, n_sub_base); + n_shift->_opnds[0] = op_dst; + n_shift->_opnds[1] = op_dst; + n_shift->_bottom_type = _bottom_type; + + n_cond_set->add_req(n_region, n_compare, n_shift); + n_cond_set->_opnds[0] = op_dst; + n_cond_set->_opnds[1] = op_crx; + n_cond_set->_opnds[2] = op_dst; + n_cond_set->_bottom_type = _bottom_type; + + ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); + ra_->set_pair(n_sub_base->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_shift->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_cond_set->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + + nodes->push(n_compare); + nodes->push(n_sub_base); + nodes->push(n_shift); + nodes->push(n_cond_set); assert(!(ra_->is_oop(this)), "sanity"); // This is not supposed to be GC'ed. %} @@ -3046,56 +3283,33 @@ encode %{ n_shift->_opnds[1] = op_src; n_shift->_bottom_type = _bottom_type; - if (VM_Version::has_isel()) { - // use isel instruction with Power 7 - - decodeN_addNode *n_add_base = new decodeN_addNode(); - n_add_base->add_req(n_region, n_shift); - n_add_base->_opnds[0] = op_dst; - n_add_base->_opnds[1] = op_dst; - n_add_base->_bottom_type = _bottom_type; - - cond_set_0_ptrNode *n_cond_set = new cond_set_0_ptrNode(); - n_cond_set->add_req(n_region, n_compare, n_add_base); - n_cond_set->_opnds[0] = op_dst; - n_cond_set->_opnds[1] = op_crx; - n_cond_set->_opnds[2] = op_dst; - n_cond_set->_bottom_type = _bottom_type; - - assert(ra_->is_oop(this) == true, "A decodeN node must produce an oop!"); - ra_->set_oop(n_cond_set, true); - - ra_->set_pair(n_shift->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); - ra_->set_pair(n_add_base->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - ra_->set_pair(n_cond_set->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - - nodes->push(n_compare); - nodes->push(n_shift); - nodes->push(n_add_base); - nodes->push(n_cond_set); + // use isel instruction with Power 7 + decodeN_addNode *n_add_base = new decodeN_addNode(); + n_add_base->add_req(n_region, n_shift); + n_add_base->_opnds[0] = op_dst; + n_add_base->_opnds[1] = op_dst; + n_add_base->_bottom_type = _bottom_type; - } else { - // before Power 7 - cond_add_baseNode *n_add_base = new cond_add_baseNode(); + cond_set_0_ptrNode *n_cond_set = new cond_set_0_ptrNode(); + n_cond_set->add_req(n_region, n_compare, n_add_base); + n_cond_set->_opnds[0] = op_dst; + n_cond_set->_opnds[1] = op_crx; + n_cond_set->_opnds[2] = op_dst; + n_cond_set->_bottom_type = _bottom_type; - n_add_base->add_req(n_region, n_compare, n_shift); - n_add_base->_opnds[0] = op_dst; - n_add_base->_opnds[1] = op_crx; - n_add_base->_opnds[2] = op_dst; - n_add_base->_bottom_type = _bottom_type; + assert(ra_->is_oop(this) == true, "A decodeN node must produce an oop!"); + ra_->set_oop(n_cond_set, true); - assert(ra_->is_oop(this) == true, "A decodeN node must produce an oop!"); - ra_->set_oop(n_add_base, true); + ra_->set_pair(n_shift->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); + ra_->set_pair(n_add_base->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + ra_->set_pair(n_cond_set->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - ra_->set_pair(n_shift->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); - ra_->set_pair(n_compare->_idx, ra_->get_reg_second(n_crx), ra_->get_reg_first(n_crx)); - ra_->set_pair(n_add_base->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); + nodes->push(n_compare); + nodes->push(n_shift); + nodes->push(n_add_base); + nodes->push(n_cond_set); - nodes->push(n_compare); - nodes->push(n_shift); - nodes->push(n_add_base); - } %} enc_class postalloc_expand_decode_oop_not_null(iRegPdst dst, iRegNsrc src) %{ @@ -3120,25 +3334,6 @@ encode %{ nodes->push(n2); %} - enc_class enc_cmove_reg(iRegIdst dst, flagsRegSrc crx, iRegIsrc src, cmpOp cmp) %{ - int cc = $cmp$$cmpcode; - int flags_reg = $crx$$reg; - Label done; - assert((Assembler::bcondCRbiIs1 & ~Assembler::bcondCRbiIs0) == 8, "check encoding"); - // Branch if not (cmp crx). - __ bc(cc_to_inverse_boint(cc), cc_to_biint(cc, flags_reg), done); - __ mr($dst$$Register, $src$$Register); - __ bind(done); - %} - - enc_class enc_cmove_imm(iRegIdst dst, flagsRegSrc crx, immI16 src, cmpOp cmp) %{ - Label done; - assert((Assembler::bcondCRbiIs1 & ~Assembler::bcondCRbiIs0) == 8, "check encoding"); - // Branch if not (cmp crx). - __ bc(cc_to_inverse_boint($cmp$$cmpcode), cc_to_biint($cmp$$cmpcode, $crx$$reg), done); - __ li($dst$$Register, $src$$constant); - __ bind(done); - %} // This enc_class is needed so that scheduler gets proper // input mapping for latency computation. @@ -4125,6 +4320,15 @@ operand immL16Alg4() %{ interface(CONST_INTER); %} +// Long Immediate: 16-bit, 16-aligned +operand immL16Alg16() %{ + predicate(Assembler::is_simm(n->get_long(), 16) && ((n->get_long() & 0xf) == 0)); + match(ConL); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // Long Immediate: 32-bit, where lowest 16 bits are 0x0000. operand immL32hi16() %{ predicate(Assembler::is_simm(n->get_long(), 32) && ((n->get_long() & 0xffffL) == 0L)); @@ -4643,6 +4847,20 @@ operand indOffset16Alg4(iRegPsrc reg, immL16Alg4 offset) %{ %} %} +// Indirect with 16-aligned Offset +operand indOffset16Alg16(iRegPsrc reg, immL16Alg16 offset) %{ + constraint(ALLOC_IN_RC(bits64_reg_ro)); + match(AddP reg offset); + op_cost(100); + format %{ "[$reg + $offset]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0x0); + scale(0x0); + disp($offset); + %} +%} + //----------Complex Operands for Compressed OOPs------------------------------- // Compressed OOPs with narrow_oop_shift == 0. @@ -4852,6 +5070,7 @@ operand cmpOp() %{ opclass memory(indirect, indOffset16 /*, indIndex, tlsReference*/, indirectNarrow, indirectNarrow_klass, indOffset16Narrow, indOffset16Narrow_klass); // Memory operand where offsets are 4-aligned. Required for ld, std. opclass memoryAlg4(indirect, indOffset16Alg4, indirectNarrow, indOffset16NarrowAlg4, indOffset16NarrowAlg4_klass); +opclass memoryAlg16(indirect, indOffset16Alg16); opclass indirectMemory(indirect, indirectNarrow); // Special opclass for I and ConvL2I. @@ -5392,8 +5611,9 @@ instruct loadV8(iRegLdst dst, memoryAlg4 mem) %{ %} // Load Aligned Packed Byte -instruct loadV16(vecX dst, indirect mem) %{ - predicate(n->as_LoadVector()->memory_size() == 16); +// Note: The Power8 instruction loads the contents in a special order in Little Endian mode. +instruct loadV16_Power8(vecX dst, indirect mem) %{ + predicate(n->as_LoadVector()->memory_size() == 16 && PowerArchitecturePPC64 == 8); match(Set dst (LoadVector mem)); ins_cost(MEMORY_REF_COST); @@ -5405,6 +5625,19 @@ instruct loadV16(vecX dst, indirect mem) %{ ins_pipe(pipe_class_default); %} +instruct loadV16_Power9(vecX dst, memoryAlg16 mem) %{ + predicate(n->as_LoadVector()->memory_size() == 16 && PowerArchitecturePPC64 >= 9); + match(Set dst (LoadVector mem)); + ins_cost(MEMORY_REF_COST); + + format %{ "LXV $dst, $mem \t// load 16-byte Vector" %} + size(4); + ins_encode %{ + __ lxv($dst$$VectorSRegister, $mem$$disp, $mem$$Register); + %} + ins_pipe(pipe_class_default); +%} + // Load Range, range = array length (=jint) instruct loadRange(iRegIdst dst, memory mem) %{ match(Set dst (LoadRange mem)); @@ -6418,8 +6651,9 @@ instruct storeA8B(memoryAlg4 mem, iRegLsrc src) %{ %} // Store Packed Byte long register to memory -instruct storeV16(indirect mem, vecX src) %{ - predicate(n->as_StoreVector()->memory_size() == 16); +// Note: The Power8 instruction stores the contents in a special order in Little Endian mode. +instruct storeV16_Power8(indirect mem, vecX src) %{ + predicate(n->as_StoreVector()->memory_size() == 16 && PowerArchitecturePPC64 == 8); match(Set mem (StoreVector mem src)); ins_cost(MEMORY_REF_COST); @@ -6431,6 +6665,19 @@ instruct storeV16(indirect mem, vecX src) %{ ins_pipe(pipe_class_default); %} +instruct storeV16_Power9(memoryAlg16 mem, vecX src) %{ + predicate(n->as_StoreVector()->memory_size() == 16 && PowerArchitecturePPC64 >= 9); + match(Set mem (StoreVector mem src)); + ins_cost(MEMORY_REF_COST); + + format %{ "STXV $mem, $src \t// store 16-byte Vector" %} + size(4); + ins_encode %{ + __ stxv($src$$VectorSRegister, $mem$$disp, $mem$$Register); + %} + ins_pipe(pipe_class_default); +%} + // Reinterpret: only one vector size used: either L or X instruct reinterpretL(iRegLdst dst) %{ match(Set dst (VectorReinterpret dst)); @@ -6787,7 +7034,7 @@ instruct decodeN_Disjoint_isel_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ effect(TEMP_DEF dst, TEMP crx); predicate((n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && - CompressedOops::base_disjoint() && VM_Version::has_isel()); + CompressedOops::base_disjoint()); ins_cost(3 * DEFAULT_COST); format %{ "DecodeN $dst, $src \t// decode with disjoint base using isel" %} @@ -7167,7 +7414,6 @@ instruct membar_CPUOrder() %{ // Cmove using isel. instruct cmovI_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegIdst dst, iRegIsrc src) %{ match(Set dst (CMoveI (Binary cmp crx) (Binary dst src))); - predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST); format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} @@ -7182,37 +7428,9 @@ instruct cmovI_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegIdst dst, iRegIsrc src) ins_pipe(pipe_class_default); %} -instruct cmovI_reg(cmpOp cmp, flagsRegSrc crx, iRegIdst dst, iRegIsrc src) %{ - match(Set dst (CMoveI (Binary cmp crx) (Binary dst src))); - predicate(!VM_Version::has_isel()); - ins_cost(DEFAULT_COST+BRANCH_COST); - - ins_variable_size_depending_on_alignment(true); - - format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler - size(8); - ins_encode( enc_cmove_reg(dst, crx, src, cmp) ); - ins_pipe(pipe_class_default); -%} - -instruct cmovI_imm(cmpOp cmp, flagsRegSrc crx, iRegIdst dst, immI16 src) %{ - match(Set dst (CMoveI (Binary cmp crx) (Binary dst src))); - ins_cost(DEFAULT_COST+BRANCH_COST); - - ins_variable_size_depending_on_alignment(true); - - format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler - size(8); - ins_encode( enc_cmove_imm(dst, crx, src, cmp) ); - ins_pipe(pipe_class_default); -%} - // Cmove using isel. instruct cmovL_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegLdst dst, iRegLsrc src) %{ match(Set dst (CMoveL (Binary cmp crx) (Binary dst src))); - predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST); format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} @@ -7227,37 +7445,9 @@ instruct cmovL_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegLdst dst, iRegLsrc src) ins_pipe(pipe_class_default); %} -instruct cmovL_reg(cmpOp cmp, flagsRegSrc crx, iRegLdst dst, iRegLsrc src) %{ - match(Set dst (CMoveL (Binary cmp crx) (Binary dst src))); - predicate(!VM_Version::has_isel()); - ins_cost(DEFAULT_COST+BRANCH_COST); - - ins_variable_size_depending_on_alignment(true); - - format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler. - size(8); - ins_encode( enc_cmove_reg(dst, crx, src, cmp) ); - ins_pipe(pipe_class_default); -%} - -instruct cmovL_imm(cmpOp cmp, flagsRegSrc crx, iRegLdst dst, immL16 src) %{ - match(Set dst (CMoveL (Binary cmp crx) (Binary dst src))); - ins_cost(DEFAULT_COST+BRANCH_COST); - - ins_variable_size_depending_on_alignment(true); - - format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler. - size(8); - ins_encode( enc_cmove_imm(dst, crx, src, cmp) ); - ins_pipe(pipe_class_default); -%} - // Cmove using isel. instruct cmovN_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegNdst dst, iRegNsrc src) %{ match(Set dst (CMoveN (Binary cmp crx) (Binary dst src))); - predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST); format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} @@ -7272,38 +7462,9 @@ instruct cmovN_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegNdst dst, iRegNsrc src) ins_pipe(pipe_class_default); %} -// Conditional move for RegN. Only cmov(reg, reg). -instruct cmovN_reg(cmpOp cmp, flagsRegSrc crx, iRegNdst dst, iRegNsrc src) %{ - match(Set dst (CMoveN (Binary cmp crx) (Binary dst src))); - predicate(!VM_Version::has_isel()); - ins_cost(DEFAULT_COST+BRANCH_COST); - - ins_variable_size_depending_on_alignment(true); - - format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler. - size(8); - ins_encode( enc_cmove_reg(dst, crx, src, cmp) ); - ins_pipe(pipe_class_default); -%} - -instruct cmovN_imm(cmpOp cmp, flagsRegSrc crx, iRegNdst dst, immN_0 src) %{ - match(Set dst (CMoveN (Binary cmp crx) (Binary dst src))); - ins_cost(DEFAULT_COST+BRANCH_COST); - - ins_variable_size_depending_on_alignment(true); - - format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler. - size(8); - ins_encode( enc_cmove_imm(dst, crx, src, cmp) ); - ins_pipe(pipe_class_default); -%} - // Cmove using isel. instruct cmovP_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegPdst dst, iRegPsrc src) %{ match(Set dst (CMoveP (Binary cmp crx) (Binary dst src))); - predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST); format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} @@ -7318,33 +7479,6 @@ instruct cmovP_reg_isel(cmpOp cmp, flagsRegSrc crx, iRegPdst dst, iRegPsrc src) ins_pipe(pipe_class_default); %} -instruct cmovP_reg(cmpOp cmp, flagsRegSrc crx, iRegPdst dst, iRegP_N2P src) %{ - match(Set dst (CMoveP (Binary cmp crx) (Binary dst src))); - predicate(!VM_Version::has_isel()); - ins_cost(DEFAULT_COST+BRANCH_COST); - - ins_variable_size_depending_on_alignment(true); - - format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler. - size(8); - ins_encode( enc_cmove_reg(dst, crx, src, cmp) ); - ins_pipe(pipe_class_default); -%} - -instruct cmovP_imm(cmpOp cmp, flagsRegSrc crx, iRegPdst dst, immP_0 src) %{ - match(Set dst (CMoveP (Binary cmp crx) (Binary dst src))); - ins_cost(DEFAULT_COST+BRANCH_COST); - - ins_variable_size_depending_on_alignment(true); - - format %{ "CMOVE $cmp, $crx, $dst, $src\n\t" %} - // Worst case is branch + move + stop, no stop without scheduler. - size(8); - ins_encode( enc_cmove_imm(dst, crx, src, cmp) ); - ins_pipe(pipe_class_default); -%} - instruct cmovF_reg(cmpOp cmp, flagsRegSrc crx, regF dst, regF src) %{ match(Set dst (CMoveF (Binary cmp crx) (Binary dst src))); ins_cost(DEFAULT_COST+BRANCH_COST); @@ -7395,31 +7529,11 @@ instruct cmovD_reg(cmpOp cmp, flagsRegSrc crx, regD dst, regD src) %{ instruct compareAndSwapB_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapB mem_ptr (Binary src1 src2))); - predicate(VM_Version::has_lqarx()); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "CMPXCHGB $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, nullptr, true); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ isync(); - } else { - __ sync(); - } - %} - ins_pipe(pipe_class_default); -%} - -instruct compareAndSwapB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0) %{ - match(Set res (CompareAndSwapB mem_ptr (Binary src1 src2))); - predicate(!VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); // TEMP_DEF to avoid jump - format %{ "CMPXCHGB $res, $mem_ptr, $src1, $src2; as bool" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, + __ cmpxchgb(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { @@ -7433,31 +7547,11 @@ instruct compareAndSwapB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIs instruct compareAndSwapS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapS mem_ptr (Binary src1 src2))); - predicate(VM_Version::has_lqarx()); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "CMPXCHGH $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, nullptr, true); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ isync(); - } else { - __ sync(); - } - %} - ins_pipe(pipe_class_default); -%} - -instruct compareAndSwapS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0) %{ - match(Set res (CompareAndSwapS mem_ptr (Binary src1 src2))); - predicate(!VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); // TEMP_DEF to avoid jump - format %{ "CMPXCHGH $res, $mem_ptr, $src1, $src2; as bool" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, + __ cmpxchgh(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { @@ -7547,26 +7641,12 @@ instruct compareAndSwapP_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, iRegPsrc instruct weakCompareAndSwapB_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (WeakCompareAndSwapB mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && VM_Version::has_lqarx()); + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "weak CMPXCHGB $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, - MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); - %} - ins_pipe(pipe_class_default); -%} - -instruct weakCompareAndSwapB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapB mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && !VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); // TEMP_DEF to avoid jump - format %{ "weak CMPXCHGB $res, $mem_ptr, $src1, $src2; as bool" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, + __ cmpxchgb(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} @@ -7575,55 +7655,27 @@ instruct weakCompareAndSwapB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR instruct weakCompareAndSwapB_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (WeakCompareAndSwapB mem_ptr (Binary src1 src2))); - predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && VM_Version::has_lqarx()); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) ); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "weak CMPXCHGB acq $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, + __ cmpxchgb(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} -instruct weakCompareAndSwapB4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapB mem_ptr (Binary src1 src2))); - predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && !VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); // TEMP_DEF to avoid jump - format %{ "weak CMPXCHGB acq $res, $mem_ptr, $src1, $src2; as bool" %} +instruct weakCompareAndSwapS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ + match(Set res (WeakCompareAndSwapS mem_ptr (Binary src1 src2))); + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump + format %{ "weak CMPXCHGH $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, - support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); - %} - ins_pipe(pipe_class_default); -%} - -instruct weakCompareAndSwapS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapS mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && VM_Version::has_lqarx()); - effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump - format %{ "weak CMPXCHGH $res, $mem_ptr, $src1, $src2; as bool" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, - MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); - %} - ins_pipe(pipe_class_default); -%} - -instruct weakCompareAndSwapS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapS mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && !VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); // TEMP_DEF to avoid jump - format %{ "weak CMPXCHGH $res, $mem_ptr, $src1, $src2; as bool" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, - MacroAssembler::MemBarNone, + __ cmpxchgh(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); @@ -7631,26 +7683,12 @@ instruct weakCompareAndSwapS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR instruct weakCompareAndSwapS_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (WeakCompareAndSwapS mem_ptr (Binary src1 src2))); - predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && VM_Version::has_lqarx()); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "weak CMPXCHGH acq $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, - support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); - %} - ins_pipe(pipe_class_default); -%} - -instruct weakCompareAndSwapS4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, iRegIdst tmp2, flagsRegCR0 cr0) %{ - match(Set res (WeakCompareAndSwapS mem_ptr (Binary src1 src2))); - predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && !VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); // TEMP_DEF to avoid jump - format %{ "weak CMPXCHGH acq $res, $mem_ptr, $src1, $src2; as bool" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, + __ cmpxchgh(CR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} @@ -7782,26 +7820,12 @@ instruct weakCompareAndSwapP_acq_regP_regP_regP(iRegIdst res, iRegPdst mem_ptr, instruct compareAndExchangeB_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeB mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && VM_Version::has_lqarx()); + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGB $res, $mem_ptr, $src1, $src2; as int" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, nullptr, true); - %} - ins_pipe(pipe_class_default); -%} - -instruct compareAndExchangeB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, flagsRegCR0 cr0) %{ - match(Set res (CompareAndExchangeB mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && !VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP cr0); - format %{ "CMPXCHGB $res, $mem_ptr, $src1, $src2; as int" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0, + __ cmpxchgb(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, nullptr, true); %} @@ -7810,12 +7834,12 @@ instruct compareAndExchangeB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR instruct compareAndExchangeB_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeB mem_ptr (Binary src1 src2))); - predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && VM_Version::has_lqarx()); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGB acq $res, $mem_ptr, $src1, $src2; as int" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, + __ cmpxchgb(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { @@ -7828,48 +7852,15 @@ instruct compareAndExchangeB_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, ins_pipe(pipe_class_default); %} -instruct compareAndExchangeB4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, flagsRegCR0 cr0) %{ - match(Set res (CompareAndExchangeB mem_ptr (Binary src1 src2))); - predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && !VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP cr0); - format %{ "CMPXCHGB acq $res, $mem_ptr, $src1, $src2; as int" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgb(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, nullptr, true); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ isync(); - } else { - // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. - __ sync(); - } - %} - ins_pipe(pipe_class_default); -%} instruct compareAndExchangeS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeS mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && VM_Version::has_lqarx()); + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGH $res, $mem_ptr, $src1, $src2; as int" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, nullptr, true); - %} - ins_pipe(pipe_class_default); -%} - -instruct compareAndExchangeS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, flagsRegCR0 cr0) %{ - match(Set res (CompareAndExchangeS mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && !VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP cr0); - format %{ "CMPXCHGH $res, $mem_ptr, $src1, $src2; as int" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0, + __ cmpxchgh(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, nullptr, true); %} @@ -7878,32 +7869,12 @@ instruct compareAndExchangeS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR instruct compareAndExchangeS_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeS mem_ptr (Binary src1 src2))); - predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && VM_Version::has_lqarx()); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGH acq $res, $mem_ptr, $src1, $src2; as int" %} ins_encode %{ // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, - MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, nullptr, true); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ isync(); - } else { - // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. - __ sync(); - } - %} - ins_pipe(pipe_class_default); -%} - -instruct compareAndExchangeS4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src1, rarg4RegI src2, iRegIdst tmp1, flagsRegCR0 cr0) %{ - match(Set res (CompareAndExchangeS mem_ptr (Binary src1 src2))); - predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && !VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL src2, USE_KILL mem_ptr, TEMP tmp1, TEMP cr0); - format %{ "CMPXCHGH acq $res, $mem_ptr, $src1, $src2; as int" %} - ins_encode %{ - // CmpxchgX sets CR0 to cmpX(src1, src2) and Rres to 'true'/'false'. - __ cmpxchgh(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0, + __ cmpxchgh(CR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { @@ -8058,7 +8029,6 @@ instruct compareAndExchangeP_acq_regP_regP_regP(iRegPdst res, iRegPdst mem_ptr, instruct getAndAddB(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndAddB mem_ptr src)); - predicate(VM_Version::has_lqarx()); effect(TEMP_DEF res, TEMP cr0); format %{ "GetAndAddB $res, $mem_ptr, $src" %} ins_encode %{ @@ -8073,26 +8043,8 @@ instruct getAndAddB(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr ins_pipe(pipe_class_default); %} -instruct getAndAddB4(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src, iRegIsrc tmp1, iRegIsrc tmp2, flagsRegCR0 cr0) %{ - match(Set res (GetAndAddB mem_ptr src)); - predicate(!VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); - format %{ "GetAndAddB $res, $mem_ptr, $src" %} - ins_encode %{ - __ getandaddb($res$$Register, $src$$Register, $mem_ptr$$Register, - R0, $tmp1$$Register, $tmp2$$Register, MacroAssembler::cmpxchgx_hint_atomic_update()); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ isync(); - } else { - __ sync(); - } - %} - ins_pipe(pipe_class_default); -%} - instruct getAndAddS(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndAddS mem_ptr src)); - predicate(VM_Version::has_lqarx()); effect(TEMP_DEF res, TEMP cr0); format %{ "GetAndAddS $res, $mem_ptr, $src" %} ins_encode %{ @@ -8107,22 +8059,6 @@ instruct getAndAddS(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr ins_pipe(pipe_class_default); %} -instruct getAndAddS4(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src, iRegIsrc tmp1, iRegIsrc tmp2, flagsRegCR0 cr0) %{ - match(Set res (GetAndAddS mem_ptr src)); - predicate(!VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); - format %{ "GetAndAddS $res, $mem_ptr, $src" %} - ins_encode %{ - __ getandaddh($res$$Register, $src$$Register, $mem_ptr$$Register, - R0, $tmp1$$Register, $tmp2$$Register, MacroAssembler::cmpxchgx_hint_atomic_update()); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ isync(); - } else { - __ sync(); - } - %} - ins_pipe(pipe_class_default); -%} instruct getAndAddI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndAddI mem_ptr src)); @@ -8158,7 +8094,6 @@ instruct getAndAddL(iRegLdst res, iRegPdst mem_ptr, iRegLsrc src, flagsRegCR0 cr instruct getAndSetB(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetB mem_ptr src)); - predicate(VM_Version::has_lqarx()); effect(TEMP_DEF res, TEMP cr0); format %{ "GetAndSetB $res, $mem_ptr, $src" %} ins_encode %{ @@ -8173,26 +8108,8 @@ instruct getAndSetB(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr ins_pipe(pipe_class_default); %} -instruct getAndSetB4(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src, iRegIsrc tmp1, iRegIsrc tmp2, flagsRegCR0 cr0) %{ - match(Set res (GetAndSetB mem_ptr src)); - predicate(!VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); - format %{ "GetAndSetB $res, $mem_ptr, $src" %} - ins_encode %{ - __ getandsetb($res$$Register, $src$$Register, $mem_ptr$$Register, - R0, $tmp1$$Register, $tmp2$$Register, MacroAssembler::cmpxchgx_hint_atomic_update()); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ isync(); - } else { - __ sync(); - } - %} - ins_pipe(pipe_class_default); -%} - instruct getAndSetS(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetS mem_ptr src)); - predicate(VM_Version::has_lqarx()); effect(TEMP_DEF res, TEMP cr0); format %{ "GetAndSetS $res, $mem_ptr, $src" %} ins_encode %{ @@ -8207,22 +8124,6 @@ instruct getAndSetS(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr ins_pipe(pipe_class_default); %} -instruct getAndSetS4(iRegIdst res, rarg3RegP mem_ptr, iRegIsrc src, iRegIsrc tmp1, iRegIsrc tmp2, flagsRegCR0 cr0) %{ - match(Set res (GetAndSetS mem_ptr src)); - predicate(!VM_Version::has_lqarx()); - effect(TEMP_DEF res, USE_KILL mem_ptr, TEMP tmp1, TEMP tmp2, TEMP cr0); - format %{ "GetAndSetS $res, $mem_ptr, $src" %} - ins_encode %{ - __ getandseth($res$$Register, $src$$Register, $mem_ptr$$Register, - R0, $tmp1$$Register, $tmp2$$Register, MacroAssembler::cmpxchgx_hint_atomic_update()); - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - __ isync(); - } else { - __ sync(); - } - %} - ins_pipe(pipe_class_default); -%} instruct getAndSetI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetI mem_ptr src)); @@ -9511,7 +9412,6 @@ instruct negD_absD_reg(regD dst, regD src) %{ ins_pipe(pipe_class_default); %} -// VM_Version::has_fsqrt() decides if this node will be used. // Sqrt float double precision instruct sqrtD_reg(regD dst, regD src) %{ match(Set dst (SqrtD src)); @@ -9526,7 +9426,6 @@ instruct sqrtD_reg(regD dst, regD src) %{ // Single-precision sqrt. instruct sqrtF_reg(regF dst, regF src) %{ match(Set dst (SqrtF src)); - predicate(VM_Version::has_fsqrts()); ins_cost(DEFAULT_COST); format %{ "FSQRTS $dst, $src" %} @@ -10028,7 +9927,6 @@ instruct andcL_reg_reg(iRegLdst dst, iRegLsrc src1, iRegLsrc src2) %{ instruct moveL2D_reg(regD dst, iRegLsrc src) %{ match(Set dst (MoveL2D src)); - predicate(VM_Version::has_mtfprd()); format %{ "MTFPRD $dst, $src" %} size(4); @@ -10148,18 +10046,6 @@ instruct moveI2F_reg_stack(stackSlotF dst, iRegIsrc src) %{ ins_pipe(pipe_class_memory); %} -//----------Moves between long and float - -instruct moveF2L_reg_stack(stackSlotL dst, regF src) %{ - // no match-rule, false predicate - effect(DEF dst, USE src); - predicate(false); - - format %{ "storeD $src, $dst \t// STACK" %} - size(4); - ins_encode( enc_stfd(src, dst) ); - ins_pipe(pipe_class_default); -%} //----------Moves between long and double @@ -10185,27 +10071,6 @@ instruct moveD2L_reg_stack(stackSlotL dst, regD src) %{ ins_pipe(pipe_class_memory); %} -// Move long value from long stack-location to double register. -instruct moveL2D_stack_reg(regD dst, stackSlotL src) %{ - match(Set dst (MoveL2D src)); - ins_cost(MEMORY_REF_COST); - - format %{ "LFD $dst, $src \t// MoveL2D" %} - size(4); - ins_encode( enc_lfd(dst, src) ); - ins_pipe(pipe_class_memory); -%} - -// Move long value from long register to double stack-location. -instruct moveL2D_reg_stack(stackSlotD dst, iRegLsrc src) %{ - match(Set dst (MoveL2D src)); - ins_cost(MEMORY_REF_COST); - - format %{ "STD $src, $dst \t// MoveL2D" %} - size(4); - ins_encode( enc_std(src, dst) ); - ins_pipe(pipe_class_memory); -%} //----------Register Move Instructions----------------------------------------- @@ -10605,59 +10470,6 @@ instruct cmovI_bso_reg(iRegIdst dst, flagsRegSrc crx, regD src) %{ ins_pipe(pipe_class_default); %} -instruct cmovI_bso_stackSlotL_conLvalue0_Ex(iRegIdst dst, flagsRegSrc crx, stackSlotL mem) %{ - // no match-rule, false predicate - effect(DEF dst, USE crx, USE mem); - predicate(false); - - format %{ "CmovI $dst, $crx, $mem \t// postalloc expanded" %} - postalloc_expand %{ - // - // replaces - // - // region dst crx mem - // \ | | / - // dst=cmovI_bso_stackSlotL_conLvalue0 - // - // with - // - // region dst - // \ / - // dst=loadConI16(0) - // | - // ^ region dst crx mem - // | \ | | / - // dst=cmovI_bso_stackSlotL - // - - // Create new nodes. - MachNode *m1 = new loadConI16Node(); - MachNode *m2 = new cmovI_bso_stackSlotLNode(); - - // inputs for new nodes - m1->add_req(n_region); - m2->add_req(n_region, n_crx, n_mem); - - // precedences for new nodes - m2->add_prec(m1); - - // operands for new nodes - m1->_opnds[0] = op_dst; - m1->_opnds[1] = new immI16Oper(0); - - m2->_opnds[0] = op_dst; - m2->_opnds[1] = op_crx; - m2->_opnds[2] = op_mem; - - // registers for new nodes - ra_->set_pair(m1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); // dst - ra_->set_pair(m2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); // dst - - // Insert new nodes. - nodes->push(m1); - nodes->push(m2); - %} -%} instruct cmovI_bso_reg_conLvalue0_Ex(iRegIdst dst, flagsRegSrc crx, regD src) %{ // no match-rule, false predicate @@ -10713,27 +10525,10 @@ instruct cmovI_bso_reg_conLvalue0_Ex(iRegIdst dst, flagsRegSrc crx, regD src) %{ %} %} -// Double to Int conversion, NaN is mapped to 0. -instruct convD2I_reg_ExEx(iRegIdst dst, regD src) %{ - match(Set dst (ConvD2I src)); - predicate(!VM_Version::has_mtfprd()); - ins_cost(DEFAULT_COST); - - expand %{ - regD tmpD; - stackSlotL tmpS; - flagsReg crx; - cmpDUnordered_reg_reg(crx, src, src); // Check whether src is NaN. - convD2IRaw_regD(tmpD, src); // Convert float to int (speculated). - moveD2L_reg_stack(tmpS, tmpD); // Store float to stack (speculated). - cmovI_bso_stackSlotL_conLvalue0_Ex(dst, crx, tmpS); // Cmove based on NaN check. - %} -%} // Double to Int conversion, NaN is mapped to 0. Special version for Power8. instruct convD2I_reg_mffprd_ExEx(iRegIdst dst, regD src) %{ match(Set dst (ConvD2I src)); - predicate(VM_Version::has_mtfprd()); ins_cost(DEFAULT_COST); expand %{ @@ -10758,27 +10553,10 @@ instruct convF2IRaw_regF(regF dst, regF src) %{ ins_pipe(pipe_class_default); %} -// Float to Int conversion, NaN is mapped to 0. -instruct convF2I_regF_ExEx(iRegIdst dst, regF src) %{ - match(Set dst (ConvF2I src)); - predicate(!VM_Version::has_mtfprd()); - ins_cost(DEFAULT_COST); - - expand %{ - regF tmpF; - stackSlotL tmpS; - flagsReg crx; - cmpFUnordered_reg_reg(crx, src, src); // Check whether src is NaN. - convF2IRaw_regF(tmpF, src); // Convert float to int (speculated). - moveF2L_reg_stack(tmpS, tmpF); // Store float to stack (speculated). - cmovI_bso_stackSlotL_conLvalue0_Ex(dst, crx, tmpS); // Cmove based on NaN check. - %} -%} // Float to Int conversion, NaN is mapped to 0. Special version for Power8. instruct convF2I_regF_mffprd_ExEx(iRegIdst dst, regF src) %{ match(Set dst (ConvF2I src)); - predicate(VM_Version::has_mtfprd()); ins_cost(DEFAULT_COST); expand %{ @@ -10869,56 +10647,6 @@ instruct cmovL_bso_reg(iRegLdst dst, flagsRegSrc crx, regD src) %{ ins_pipe(pipe_class_default); %} -instruct cmovL_bso_stackSlotL_conLvalue0_Ex(iRegLdst dst, flagsRegSrc crx, stackSlotL mem) %{ - // no match-rule, false predicate - effect(DEF dst, USE crx, USE mem); - predicate(false); - - format %{ "CmovL $dst, $crx, $mem \t// postalloc expanded" %} - postalloc_expand %{ - // - // replaces - // - // region dst crx mem - // \ | | / - // dst=cmovL_bso_stackSlotL_conLvalue0 - // - // with - // - // region dst - // \ / - // dst=loadConL16(0) - // | - // ^ region dst crx mem - // | \ | | / - // dst=cmovL_bso_stackSlotL - // - - // Create new nodes. - MachNode *m1 = new loadConL16Node(); - MachNode *m2 = new cmovL_bso_stackSlotLNode(); - - // inputs for new nodes - m1->add_req(n_region); - m2->add_req(n_region, n_crx, n_mem); - m2->add_prec(m1); - - // operands for new nodes - m1->_opnds[0] = op_dst; - m1->_opnds[1] = new immL16Oper(0); - m2->_opnds[0] = op_dst; - m2->_opnds[1] = op_crx; - m2->_opnds[2] = op_mem; - - // registers for new nodes - ra_->set_pair(m1->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); // dst - ra_->set_pair(m2->_idx, ra_->get_reg_second(this), ra_->get_reg_first(this)); // dst - - // Insert new nodes. - nodes->push(m1); - nodes->push(m2); - %} -%} instruct cmovL_bso_reg_conLvalue0_Ex(iRegLdst dst, flagsRegSrc crx, regD src) %{ // no match-rule, false predicate @@ -10971,27 +10699,10 @@ instruct cmovL_bso_reg_conLvalue0_Ex(iRegLdst dst, flagsRegSrc crx, regD src) %{ %} %} -// Float to Long conversion, NaN is mapped to 0. -instruct convF2L_reg_ExEx(iRegLdst dst, regF src) %{ - match(Set dst (ConvF2L src)); - predicate(!VM_Version::has_mtfprd()); - ins_cost(DEFAULT_COST); - - expand %{ - regF tmpF; - stackSlotL tmpS; - flagsReg crx; - cmpFUnordered_reg_reg(crx, src, src); // Check whether src is NaN. - convF2LRaw_regF(tmpF, src); // Convert float to long (speculated). - moveF2L_reg_stack(tmpS, tmpF); // Store float to stack (speculated). - cmovL_bso_stackSlotL_conLvalue0_Ex(dst, crx, tmpS); // Cmove based on NaN check. - %} -%} // Float to Long conversion, NaN is mapped to 0. Special version for Power8. instruct convF2L_reg_mffprd_ExEx(iRegLdst dst, regF src) %{ match(Set dst (ConvF2L src)); - predicate(VM_Version::has_mtfprd()); ins_cost(DEFAULT_COST); expand %{ @@ -11016,27 +10727,10 @@ instruct convD2LRaw_regD(regD dst, regD src) %{ ins_pipe(pipe_class_default); %} -// Double to Long conversion, NaN is mapped to 0. -instruct convD2L_reg_ExEx(iRegLdst dst, regD src) %{ - match(Set dst (ConvD2L src)); - predicate(!VM_Version::has_mtfprd()); - ins_cost(DEFAULT_COST); - - expand %{ - regD tmpD; - stackSlotL tmpS; - flagsReg crx; - cmpDUnordered_reg_reg(crx, src, src); // Check whether src is NaN. - convD2LRaw_regD(tmpD, src); // Convert float to long (speculated). - moveD2L_reg_stack(tmpS, tmpD); // Store float to stack (speculated). - cmovL_bso_stackSlotL_conLvalue0_Ex(dst, crx, tmpS); // Cmove based on NaN check. - %} -%} // Double to Long conversion, NaN is mapped to 0. Special version for Power8. instruct convD2L_reg_mffprd_ExEx(iRegLdst dst, regD src) %{ match(Set dst (ConvD2L src)); - predicate(VM_Version::has_mtfprd()); ins_cost(DEFAULT_COST); expand %{ @@ -11075,25 +10769,6 @@ instruct convD2F_reg(regF dst, regD src) %{ ins_pipe(pipe_class_default); %} -// Integer to Float conversion. -instruct convI2F_ireg_Ex(regF dst, iRegIsrc src) %{ - match(Set dst (ConvI2F src)); - predicate(!VM_Version::has_fcfids()); - ins_cost(DEFAULT_COST); - - expand %{ - iRegLdst tmpL; - stackSlotL tmpS; - regD tmpD; - regD tmpD2; - convI2L_reg(tmpL, src); // Sign-extension int to long. - regL_to_stkL(tmpS, tmpL); // Store long to stack. - moveL2D_stack_reg(tmpD, tmpS); // Load long into double register. - convL2DRaw_regD(tmpD2, tmpD); // Convert to double. - convD2F_reg(dst, tmpD2); // Convert double to float. - %} -%} - instruct convL2FRaw_regF(regF dst, regD src) %{ // no match-rule, false predicate effect(DEF dst, USE src); @@ -11107,27 +10782,10 @@ instruct convL2FRaw_regF(regF dst, regD src) %{ ins_pipe(pipe_class_default); %} -// Integer to Float conversion. Special version for Power7. -instruct convI2F_ireg_fcfids_Ex(regF dst, iRegIsrc src) %{ - match(Set dst (ConvI2F src)); - predicate(VM_Version::has_fcfids() && !VM_Version::has_mtfprd()); - ins_cost(DEFAULT_COST); - - expand %{ - iRegLdst tmpL; - stackSlotL tmpS; - regD tmpD; - convI2L_reg(tmpL, src); // Sign-extension int to long. - regL_to_stkL(tmpS, tmpL); // Store long to stack. - moveL2D_stack_reg(tmpD, tmpS); // Load long into double register. - convL2FRaw_regF(dst, tmpD); // Convert to float. - %} -%} // Integer to Float conversion. Special version for Power8. instruct convI2F_ireg_mtfprd_Ex(regF dst, iRegIsrc src) %{ match(Set dst (ConvI2F src)); - predicate(VM_Version::has_fcfids() && VM_Version::has_mtfprd()); ins_cost(DEFAULT_COST); expand %{ @@ -11137,25 +10795,10 @@ instruct convI2F_ireg_mtfprd_Ex(regF dst, iRegIsrc src) %{ %} %} -// L2F to avoid runtime call. -instruct convL2F_ireg_fcfids_Ex(regF dst, iRegLsrc src) %{ - match(Set dst (ConvL2F src)); - predicate(VM_Version::has_fcfids() && !VM_Version::has_mtfprd()); - ins_cost(DEFAULT_COST); - - expand %{ - stackSlotL tmpS; - regD tmpD; - regL_to_stkL(tmpS, src); // Store long to stack. - moveL2D_stack_reg(tmpD, tmpS); // Load long into double register. - convL2FRaw_regF(dst, tmpD); // Convert to float. - %} -%} // L2F to avoid runtime call. Special version for Power8. instruct convL2F_ireg_mtfprd_Ex(regF dst, iRegLsrc src) %{ match(Set dst (ConvL2F src)); - predicate(VM_Version::has_fcfids() && VM_Version::has_mtfprd()); ins_cost(DEFAULT_COST); expand %{ @@ -11170,27 +10813,10 @@ instruct convL2F_ireg_mtfprd_Ex(regF dst, iRegLsrc src) %{ // Convert to Double -// Integer to Double conversion. -instruct convI2D_reg_Ex(regD dst, iRegIsrc src) %{ - match(Set dst (ConvI2D src)); - predicate(!VM_Version::has_mtfprd()); - ins_cost(DEFAULT_COST); - - expand %{ - iRegLdst tmpL; - stackSlotL tmpS; - regD tmpD; - convI2L_reg(tmpL, src); // Sign-extension int to long. - regL_to_stkL(tmpS, tmpL); // Store long to stack. - moveL2D_stack_reg(tmpD, tmpS); // Load long into double register. - convL2DRaw_regD(dst, tmpD); // Convert to double. - %} -%} // Integer to Double conversion. Special version for Power8. instruct convI2D_reg_mtfprd_Ex(regD dst, iRegIsrc src) %{ match(Set dst (ConvI2D src)); - predicate(VM_Version::has_mtfprd()); ins_cost(DEFAULT_COST); expand %{ @@ -11200,22 +10826,10 @@ instruct convI2D_reg_mtfprd_Ex(regD dst, iRegIsrc src) %{ %} %} -// Long to Double conversion -instruct convL2D_reg_Ex(regD dst, stackSlotL src) %{ - match(Set dst (ConvL2D src)); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - - expand %{ - regD tmpD; - moveL2D_stack_reg(tmpD, src); - convL2DRaw_regD(dst, tmpD); - %} -%} // Long to Double conversion. Special version for Power8. instruct convL2D_reg_mtfprd_Ex(regD dst, iRegLsrc src) %{ match(Set dst (ConvL2D src)); - predicate(VM_Version::has_mtfprd()); ins_cost(DEFAULT_COST); expand %{ @@ -12810,30 +12424,10 @@ instruct encode_ascii_array(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst //---------- Min/Max Instructions --------------------------------------------- -instruct minI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ - match(Set dst (MinI src1 src2)); - ins_cost(DEFAULT_COST*6); - - expand %{ - iRegLdst src1s; - iRegLdst src2s; - iRegLdst diff; - iRegLdst sm; - iRegLdst doz; // difference or zero - convI2L_reg(src1s, src1); // Ensure proper sign extension. - convI2L_reg(src2s, src2); // Ensure proper sign extension. - subL_reg_reg(diff, src2s, src1s); - // Need to consider >=33 bit result, therefore we need signmaskL. - signmask64L_regL(sm, diff); - andL_reg_reg(doz, diff, sm); // <=0 - addI_regL_regL(dst, doz, src1s); - %} -%} instruct minI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set dst (MinI src1 src2)); effect(KILL cr0); - predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST*2); ins_encode %{ @@ -12843,30 +12437,10 @@ instruct minI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegC ins_pipe(pipe_class_default); %} -instruct maxI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ - match(Set dst (MaxI src1 src2)); - ins_cost(DEFAULT_COST*6); - - expand %{ - iRegLdst src1s; - iRegLdst src2s; - iRegLdst diff; - iRegLdst sm; - iRegLdst doz; // difference or zero - convI2L_reg(src1s, src1); // Ensure proper sign extension. - convI2L_reg(src2s, src2); // Ensure proper sign extension. - subL_reg_reg(diff, src2s, src1s); - // Need to consider >=33 bit result, therefore we need signmaskL. - signmask64L_regL(sm, diff); - andcL_reg_reg(doz, diff, sm); // >=0 - addI_regL_regL(dst, doz, src1s); - %} -%} instruct maxI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ match(Set dst (MaxI src1 src2)); effect(KILL cr0); - predicate(VM_Version::has_isel()); ins_cost(DEFAULT_COST*2); ins_encode %{ @@ -12881,7 +12455,7 @@ instruct maxI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegC // Popcnt for Power7. instruct popCountI(iRegIdst dst, iRegIsrc src) %{ match(Set dst (PopCountI src)); - predicate(UsePopCountInstruction && VM_Version::has_popcntw()); + predicate(UsePopCountInstruction); ins_cost(DEFAULT_COST); format %{ "POPCNTW $dst, $src" %} @@ -12894,7 +12468,7 @@ instruct popCountI(iRegIdst dst, iRegIsrc src) %{ // Popcnt for Power7. instruct popCountL(iRegIdst dst, iRegLsrc src) %{ - predicate(UsePopCountInstruction && VM_Version::has_popcntw()); + predicate(UsePopCountInstruction); match(Set dst (PopCountL src)); ins_cost(DEFAULT_COST); @@ -13253,7 +12827,7 @@ instruct loadI_reversed_acquire(iRegIdst dst, indirect mem) %{ // Load Long - aligned and reversed instruct loadL_reversed(iRegLdst dst, indirect mem) %{ match(Set dst (ReverseBytesL (LoadL mem))); - predicate(VM_Version::has_ldbrx() && (n->in(1)->as_Load()->is_unordered() || followed_by_acquire(n->in(1)))); + predicate((n->in(1)->as_Load()->is_unordered() || followed_by_acquire(n->in(1)))); ins_cost(MEMORY_REF_COST); size(4); @@ -13265,7 +12839,6 @@ instruct loadL_reversed(iRegLdst dst, indirect mem) %{ instruct loadL_reversed_acquire(iRegLdst dst, indirect mem) %{ match(Set dst (ReverseBytesL (LoadL mem))); - predicate(VM_Version::has_ldbrx()); ins_cost(2 * MEMORY_REF_COST); size(12); @@ -13346,7 +12919,6 @@ instruct storeI_reversed(iRegIsrc src, indirect mem) %{ // Store Long reversed byte order instruct storeL_reversed(iRegLsrc src, indirect mem) %{ match(Set mem (StoreL mem (ReverseBytesL src))); - predicate(VM_Version::has_stdbrx()); ins_cost(MEMORY_REF_COST); size(4); @@ -13941,6 +13513,113 @@ instruct vdiv2D_reg(vecX dst, vecX src1, vecX src2) %{ ins_pipe(pipe_class_default); %} +// Vector Min / Max Instructions + +instruct vmin_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (MinV src1 src2)); + format %{ "VMIN $dst,$src1,$src2\t// vector min" %} + size(4); + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + switch (bt) { + case T_INT: + __ vminsw($dst$$VectorSRegister->to_vr(), $src1$$VectorSRegister->to_vr(), $src2$$VectorSRegister->to_vr()); + break; + case T_LONG: + __ vminsd($dst$$VectorSRegister->to_vr(), $src1$$VectorSRegister->to_vr(), $src2$$VectorSRegister->to_vr()); + break; + default: + ShouldNotReachHere(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct vmax_reg(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (MaxV src1 src2)); + format %{ "VMAX $dst,$src1,$src2\t// vector max" %} + size(4); + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + switch (bt) { + case T_INT: + __ vmaxsw($dst$$VectorSRegister->to_vr(), $src1$$VectorSRegister->to_vr(), $src2$$VectorSRegister->to_vr()); + break; + case T_LONG: + __ vmaxsd($dst$$VectorSRegister->to_vr(), $src1$$VectorSRegister->to_vr(), $src2$$VectorSRegister->to_vr()); + break; + default: + ShouldNotReachHere(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct vand(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (AndV src1 src2)); + size(4); + format %{ "VAND $dst,$src1,$src2\t// and vectors" %} + ins_encode %{ + __ vand($dst$$VectorSRegister->to_vr(), $src1$$VectorSRegister->to_vr(), $src2$$VectorSRegister->to_vr()); + %} + ins_pipe(pipe_class_default); +%} + +instruct vor(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (OrV src1 src2)); + size(4); + format %{ "VOR $dst,$src1,$src2\t// or vectors" %} + ins_encode %{ + __ vor($dst$$VectorSRegister->to_vr(), $src1$$VectorSRegister->to_vr(), $src2$$VectorSRegister->to_vr()); + %} + ins_pipe(pipe_class_default); +%} + +instruct vxor(vecX dst, vecX src1, vecX src2) %{ + match(Set dst (XorV src1 src2)); + size(4); + format %{ "VXOR $dst,$src1,$src2\t// xor vectors" %} + ins_encode %{ + __ vxor($dst$$VectorSRegister->to_vr(), $src1$$VectorSRegister->to_vr(), $src2$$VectorSRegister->to_vr()); + %} + ins_pipe(pipe_class_default); +%} + +instruct reductionI_arith_logic(iRegIdst dst, iRegIsrc srcInt, vecX srcVec, vecX tmp1, vecX tmp2) %{ + predicate(Matcher::vector_element_basic_type(n->in(2)) == T_INT); + match(Set dst (AddReductionVI srcInt srcVec)); + match(Set dst (MulReductionVI srcInt srcVec)); + match(Set dst (AndReductionV srcInt srcVec)); + match(Set dst ( OrReductionV srcInt srcVec)); + match(Set dst (XorReductionV srcInt srcVec)); + effect(TEMP tmp1, TEMP tmp2); + ins_cost(DEFAULT_COST * 6); + format %{ "REDUCEI_ARITH_LOGIC // $dst,$srcInt,$srcVec,$tmp1,$tmp2\t// reduce vector int add/mul/and/or/xor" %} + size(24); + ins_encode %{ + int opcode = this->ideal_Opcode(); + __ reduceI(opcode, $dst$$Register, $srcInt$$Register, $srcVec$$VectorSRegister->to_vr(), + $tmp1$$VectorSRegister->to_vr(), $tmp2$$VectorSRegister->to_vr()); + %} + ins_pipe(pipe_class_default); +%} + +instruct reductionI_min_max(iRegIdst dst, iRegIsrc srcInt, vecX srcVec, vecX tmp1, vecX tmp2, flagsRegCR0 cr0) %{ + predicate(Matcher::vector_element_basic_type(n->in(2)) == T_INT); + match(Set dst (MinReductionV srcInt srcVec)); + match(Set dst (MaxReductionV srcInt srcVec)); + effect(TEMP tmp1, TEMP tmp2, KILL cr0); + ins_cost(DEFAULT_COST * 7); + format %{ "REDUCEI_MINMAX // $dst,$srcInt,$srcVec,$tmp1,$tmp2,cr0\t// reduce vector int min/max" %} + size(28); + ins_encode %{ + int opcode = this->ideal_Opcode(); + __ reduceI(opcode, $dst$$Register, $srcInt$$Register, $srcVec$$VectorSRegister->to_vr(), + $tmp1$$VectorSRegister->to_vr(), $tmp2$$VectorSRegister->to_vr()); + %} + ins_pipe(pipe_class_default); +%} + // Vector Absolute Instructions instruct vabs4F_reg(vecX dst, vecX src) %{ diff --git a/src/hotspot/cpu/ppc/register_ppc.hpp b/src/hotspot/cpu/ppc/register_ppc.hpp index 565542ad7c0..b7949750dcc 100644 --- a/src/hotspot/cpu/ppc/register_ppc.hpp +++ b/src/hotspot/cpu/ppc/register_ppc.hpp @@ -99,8 +99,8 @@ class Register { // testers constexpr bool is_valid() const { return ( 0 <= _encoding && _encoding < number_of_registers); } - constexpr bool is_volatile() const { return ( 0 <= _encoding && _encoding <= 13 ); } - constexpr bool is_nonvolatile() const { return (14 <= _encoding && _encoding <= 31 ); } + constexpr bool is_volatile() const { return ( 0 <= _encoding && _encoding <= 13); } + constexpr bool is_nonvolatile() const { return (14 <= _encoding && _encoding <= 31); } const char* name() const; }; @@ -169,7 +169,7 @@ class ConditionRegister { // testers constexpr bool is_valid() const { return (0 <= _encoding && _encoding < number_of_registers); } - constexpr bool is_nonvolatile() const { return (2 <= _encoding && _encoding <= 4 ); } + constexpr bool is_nonvolatile() const { return (2 <= _encoding && _encoding <= 4); } const char* name() const; }; @@ -214,6 +214,7 @@ class FloatRegister { // testers constexpr bool is_valid() const { return (0 <= _encoding && _encoding < number_of_registers); } + constexpr bool is_nonvolatile() const { return (14 <= _encoding && _encoding <= 31); } const char* name() const; @@ -323,6 +324,7 @@ class VectorRegister { // testers constexpr bool is_valid() const { return (0 <= _encoding && _encoding < number_of_registers); } + constexpr bool is_nonvolatile() const { return (20 <= _encoding && _encoding <= 31); } const char* name() const; @@ -372,6 +374,7 @@ constexpr VectorRegister VR31 = as_VectorRegister(31); // The implementation of Vector-Scalar (VSX) registers on POWER architecture. +// VSR0-31 are aliases for F0-31 and VSR32-63 are aliases for VR0-31. class VectorSRegister { int _encoding; public: @@ -390,6 +393,7 @@ class VectorSRegister { // accessors constexpr int encoding() const { assert(is_valid(), "invalid register"); return _encoding; } inline VMReg as_VMReg() const; + VectorSRegister successor() const { return VectorSRegister(encoding() + 1); } // testers constexpr bool is_valid() const { return (0 <= _encoding && _encoding < number_of_registers); } @@ -480,7 +484,7 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { enum { max_gpr = Register::number_of_registers * 2, max_fpr = max_gpr + FloatRegister::number_of_registers * 2, - max_vsr = max_fpr + VectorSRegister::number_of_registers, + max_vsr = max_fpr + VectorSRegister::number_of_registers * 4, max_cnd = max_vsr + ConditionRegister::number_of_registers, max_spr = max_cnd + SpecialRegister::number_of_registers, // This number must be large enough to cover REG_COUNT (defined by c2) registers. @@ -519,7 +523,7 @@ constexpr FloatRegister F11_ARG11 = F11; // volatile constexpr FloatRegister F12_ARG12 = F12; // volatile constexpr FloatRegister F13_ARG13 = F13; // volatile -// Register declarations to be used in frame manager assembly code. +// Register declarations to be used in template interpreter assembly code. // Use only non-volatile registers in order to keep values across C-calls. constexpr Register R14_bcp = R14; constexpr Register R15_esp = R15; // slot below top of expression stack for ld/st with update @@ -529,7 +533,7 @@ constexpr Register R17_tos = R17; // The interpreter's top of (expres constexpr Register R18_locals = R18; // address of first param slot (receiver). constexpr Register R19_method = R19; // address of current method -// Temporary registers to be used within frame manager. We can use +// Temporary registers to be used within template interpreter. We can use // the non-volatiles because the call stub has saved them. // Use only non-volatile registers in order to keep values across C-calls. constexpr Register R21_tmp1 = R21; diff --git a/src/hotspot/cpu/ppc/runtime_ppc.cpp b/src/hotspot/cpu/ppc/runtime_ppc.cpp index 94e8c08ebf5..6d9a1dfcb1e 100644 --- a/src/hotspot/cpu/ppc/runtime_ppc.cpp +++ b/src/hotspot/cpu/ppc/runtime_ppc.cpp @@ -73,6 +73,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Setup code generation tools. const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); address start = __ pc(); diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 5a94d469434..4ec2483b267 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -243,7 +243,19 @@ static const RegisterSaver::LiveRegType RegisterSaver_LiveVSRegs[] = { RegisterSaver_LiveVSReg( VSR48 ), RegisterSaver_LiveVSReg( VSR49 ), RegisterSaver_LiveVSReg( VSR50 ), - RegisterSaver_LiveVSReg( VSR51 ) + RegisterSaver_LiveVSReg( VSR51 ), + RegisterSaver_LiveVSReg( VSR52 ), + RegisterSaver_LiveVSReg( VSR53 ), + RegisterSaver_LiveVSReg( VSR54 ), + RegisterSaver_LiveVSReg( VSR55 ), + RegisterSaver_LiveVSReg( VSR56 ), + RegisterSaver_LiveVSReg( VSR57 ), + RegisterSaver_LiveVSReg( VSR58 ), + RegisterSaver_LiveVSReg( VSR59 ), + RegisterSaver_LiveVSReg( VSR60 ), + RegisterSaver_LiveVSReg( VSR61 ), + RegisterSaver_LiveVSReg( VSR62 ), + RegisterSaver_LiveVSReg( VSR63 ) }; @@ -336,26 +348,50 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble } if (generate_oop_map) { - map->set_callee_saved(VMRegImpl::stack2reg(offset>>2), + map->set_callee_saved(VMRegImpl::stack2reg(offset >> 2), RegisterSaver_LiveRegs[i].vmreg); - map->set_callee_saved(VMRegImpl::stack2reg((offset + half_reg_size)>>2), - RegisterSaver_LiveRegs[i].vmreg->next()); } offset += reg_size; } - for (int i = 0; i < vsregstosave_num; i++) { - int reg_num = RegisterSaver_LiveVSRegs[i].reg_num; - int reg_type = RegisterSaver_LiveVSRegs[i].reg_type; - - __ li(R30, offset); - __ stxvd2x(as_VectorSRegister(reg_num), R30, R1_SP); + // Note that generate_oop_map in the following loop is only used for the + // polling_page_vectors_safepoint_handler_blob. + // The order in which the vector contents are stored depends on Endianess and + // the utilized instructions (PowerArchitecturePPC64). + assert(is_aligned(offset, StackAlignmentInBytes), "should be"); + if (PowerArchitecturePPC64 >= 10) { + assert(is_even(vsregstosave_num), "expectation"); + for (int i = 0; i < vsregstosave_num; i += 2) { + int reg_num = RegisterSaver_LiveVSRegs[i].reg_num; + assert(RegisterSaver_LiveVSRegs[i + 1].reg_num == reg_num + 1, "or use other instructions!"); + + __ stxvp(as_VectorSRegister(reg_num), offset, R1_SP); + // Note: The contents were read in the same order (see loadV16_Power9 node in ppc.ad). + if (generate_oop_map) { + map->set_callee_saved(VMRegImpl::stack2reg(offset >> 2), + RegisterSaver_LiveVSRegs[i LITTLE_ENDIAN_ONLY(+1) ].vmreg); + map->set_callee_saved(VMRegImpl::stack2reg((offset + vs_reg_size) >> 2), + RegisterSaver_LiveVSRegs[i BIG_ENDIAN_ONLY(+1) ].vmreg); + } + offset += (2 * vs_reg_size); + } + } else { + for (int i = 0; i < vsregstosave_num; i++) { + int reg_num = RegisterSaver_LiveVSRegs[i].reg_num; - if (generate_oop_map) { - map->set_callee_saved(VMRegImpl::stack2reg(offset>>2), - RegisterSaver_LiveVSRegs[i].vmreg); + if (PowerArchitecturePPC64 >= 9) { + __ stxv(as_VectorSRegister(reg_num), offset, R1_SP); + } else { + __ li(R31, offset); + __ stxvd2x(as_VectorSRegister(reg_num), R31, R1_SP); + } + // Note: The contents were read in the same order (see loadV16_Power8 / loadV16_Power9 node in ppc.ad). + if (generate_oop_map) { + VMReg vsr = RegisterSaver_LiveVSRegs[i].vmreg; + map->set_callee_saved(VMRegImpl::stack2reg(offset >> 2), vsr); + } + offset += vs_reg_size; } - offset += vs_reg_size; } assert(offset == frame_size_in_bytes, "consistency check"); @@ -418,14 +454,29 @@ void RegisterSaver::restore_live_registers_and_pop_frame(MacroAssembler* masm, offset += reg_size; } - for (int i = 0; i < vsregstosave_num; i++) { - int reg_num = RegisterSaver_LiveVSRegs[i].reg_num; - int reg_type = RegisterSaver_LiveVSRegs[i].reg_type; + assert(is_aligned(offset, StackAlignmentInBytes), "should be"); + if (PowerArchitecturePPC64 >= 10) { + for (int i = 0; i < vsregstosave_num; i += 2) { + int reg_num = RegisterSaver_LiveVSRegs[i].reg_num; + assert(RegisterSaver_LiveVSRegs[i + 1].reg_num == reg_num + 1, "or use other instructions!"); - __ li(R31, offset); - __ lxvd2x(as_VectorSRegister(reg_num), R31, R1_SP); + __ lxvp(as_VectorSRegister(reg_num), offset, R1_SP); - offset += vs_reg_size; + offset += (2 * vs_reg_size); + } + } else { + for (int i = 0; i < vsregstosave_num; i++) { + int reg_num = RegisterSaver_LiveVSRegs[i].reg_num; + + if (PowerArchitecturePPC64 >= 9) { + __ lxv(as_VectorSRegister(reg_num), offset, R1_SP); + } else { + __ li(R31, offset); + __ lxvd2x(as_VectorSRegister(reg_num), R31, R1_SP); + } + + offset += vs_reg_size; + } } assert(offset == frame_size_in_bytes, "consistency check"); @@ -1143,12 +1194,12 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, __ bctr(); } -AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs, - AdapterFingerPrint* fingerprint) { +void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + AdapterHandlerEntry* handler) { address i2c_entry; address c2i_unverified_entry; address c2i_entry; @@ -1223,8 +1274,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, call_interpreter, ientry); - return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, - c2i_no_clinit_check_entry); + handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); + return; } // An oop arg. Must pass a handle not the oop itself. @@ -2689,6 +2740,21 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ li(r_temp_2, 0); __ stw(r_temp_2, in_bytes(JNIHandleBlock::top_offset()), r_temp_1); + // Prepare for return + // -------------------------------------------------------------------------- + __ pop_frame(); + __ restore_LR(R11); + +#if INCLUDE_JFR + // We need to do a poll test after unwind in case the sampler + // managed to sample the native frame after returning to Java. + Label L_stub; + int safepoint_offset = __ offset(); + if (!UseSIGTRAP) { + __ relocate(relocInfo::poll_return_type); + } + __ safepoint_poll(L_stub, r_temp_2, true /* at_return */, true /* in_nmethod: frame already popped */); +#endif // INCLUDE_JFR // Check for pending exceptions. // -------------------------------------------------------------------------- @@ -2696,13 +2762,16 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, __ cmpdi(CR0, r_temp_2, 0); __ bne(CR0, handle_pending_exception); - // Return - // -------------------------------------------------------------------------- - - __ pop_frame(); - __ restore_LR(R11); + // Return. __ blr(); + // Handler for return safepoint (out-of-line). +#if INCLUDE_JFR + if (!UseSIGTRAP) { + __ bind(L_stub); + __ jump_to_polling_page_return_handler_blob(safepoint_offset); + } +#endif // INCLUDE_JFR // Handler for pending exceptions (out-of-line). // -------------------------------------------------------------------------- @@ -2710,9 +2779,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // is the empty function. We just pop this frame and then jump to // forward_exception_entry. __ bind(handle_pending_exception); - - __ pop_frame(); - __ restore_LR(R11); __ b64_patchable((address)StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type); @@ -2869,7 +2935,7 @@ static void push_skeleton_frames(MacroAssembler* masm, bool deopt, __ cmpdi(CR0, number_of_frames_reg, 0); __ bne(CR0, loop); - // Get the return address pointing into the frame manager. + // Get the return address pointing into the template interpreter. __ ld(R0, 0, pcs_reg); // Store it in the top interpreter frame. __ std(R0, _abi0(lr), R1_SP); @@ -3106,6 +3172,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Setup code generation tools. const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); address start = __ pc(); diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 939c3d3094a..2624131033c 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -86,7 +86,7 @@ class StubGenerator: public StubCodeGenerator { // R10 - thread : Thread* // address generate_call_stub(address& return_address) { - // Setup a new c frame, copy java arguments, call frame manager or + // Setup a new c frame, copy java arguments, call template interpreter or // native_entry, and process result. StubGenStubId stub_id = StubGenStubId::call_stub_id; @@ -94,10 +94,13 @@ class StubGenerator: public StubCodeGenerator { address start = __ function_entry(); + int save_nonvolatile_registers_size = __ save_nonvolatile_registers_size(true, SuperwordUseVSX); + // some sanity checks + STATIC_ASSERT(StackAlignmentInBytes == 16); assert((sizeof(frame::native_abi_minframe) % 16) == 0, "unaligned"); assert((sizeof(frame::native_abi_reg_args) % 16) == 0, "unaligned"); - assert((sizeof(frame::spill_nonvolatiles) % 16) == 0, "unaligned"); + assert((save_nonvolatile_registers_size % 16) == 0, "unaligned"); assert((sizeof(frame::parent_ijava_frame_abi) % 16) == 0, "unaligned"); assert((sizeof(frame::entry_frame_locals) % 16) == 0, "unaligned"); @@ -106,93 +109,72 @@ class StubGenerator: public StubCodeGenerator { Register r_arg_result_type = R5; Register r_arg_method = R6; Register r_arg_entry = R7; + Register r_arg_argument_addr = R8; + Register r_arg_argument_count = R9; Register r_arg_thread = R10; - Register r_temp = R24; - Register r_top_of_arguments_addr = R25; - Register r_entryframe_fp = R26; + Register r_entryframe_fp = R2; // volatile + Register r_argument_size = R11_scratch1; // volatile + Register r_top_of_arguments_addr = R21_tmp1; { // Stack on entry to call_stub: // // F1 [C_FRAME] // ... - - Register r_arg_argument_addr = R8; - Register r_arg_argument_count = R9; - Register r_frame_alignment_in_bytes = R27; - Register r_argument_addr = R28; - Register r_argumentcopy_addr = R29; - Register r_argument_size_in_bytes = R30; - Register r_frame_size = R23; - + Register r_frame_size = R12_scratch2; // volatile Label arguments_copied; // Save LR/CR to caller's C_FRAME. __ save_LR_CR(R0); - // Zero extend arg_argument_count. - __ clrldi(r_arg_argument_count, r_arg_argument_count, 32); - - // Save non-volatiles GPRs to ENTRY_FRAME (not yet pushed, but it's safe). - __ save_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14)); - // Keep copy of our frame pointer (caller's SP). __ mr(r_entryframe_fp, R1_SP); + // calculate frame size + STATIC_ASSERT(Interpreter::logStackElementSize == 3); + + // space for arguments aligned up: ((arg_count + 1) * 8) &~ 15 + __ addi(r_frame_size, r_arg_argument_count, 1); + __ rldicr(r_frame_size, r_frame_size, 3, 63 - 4); + + // this is the pure space for arguments (excluding alignment padding) + __ sldi(r_argument_size, r_arg_argument_count, 3); + + __ addi(r_frame_size, r_frame_size, + save_nonvolatile_registers_size + frame::entry_frame_locals_size + frame::top_ijava_frame_abi_size); + + // push ENTRY_FRAME + __ push_frame(r_frame_size, R0); + + // Save non-volatiles registers to ENTRY_FRAME. + __ save_nonvolatile_registers(r_entryframe_fp, -(frame::entry_frame_locals_size + save_nonvolatile_registers_size), + true, SuperwordUseVSX); + BLOCK_COMMENT("Push ENTRY_FRAME including arguments"); // Push ENTRY_FRAME including arguments: // // F0 [TOP_IJAVA_FRAME_ABI] // alignment (optional) // [outgoing Java arguments] + // [non-volatiles] // [ENTRY_FRAME_LOCALS] // F1 [C_FRAME] // ... - // calculate frame size - - // unaligned size of arguments - __ sldi(r_argument_size_in_bytes, - r_arg_argument_count, Interpreter::logStackElementSize); - // arguments alignment (max 1 slot) - // FIXME: use round_to() here - __ andi_(r_frame_alignment_in_bytes, r_arg_argument_count, 1); - __ sldi(r_frame_alignment_in_bytes, - r_frame_alignment_in_bytes, Interpreter::logStackElementSize); - - // size = unaligned size of arguments + top abi's size - __ addi(r_frame_size, r_argument_size_in_bytes, - frame::top_ijava_frame_abi_size); - // size += arguments alignment - __ add(r_frame_size, - r_frame_size, r_frame_alignment_in_bytes); - // size += size of call_stub locals - __ addi(r_frame_size, - r_frame_size, frame::entry_frame_locals_size); - - // push ENTRY_FRAME - __ push_frame(r_frame_size, r_temp); - // initialize call_stub locals (step 1) - __ std(r_arg_call_wrapper_addr, - _entry_frame_locals_neg(call_wrapper_address), r_entryframe_fp); - __ std(r_arg_result_addr, - _entry_frame_locals_neg(result_address), r_entryframe_fp); - __ std(r_arg_result_type, - _entry_frame_locals_neg(result_type), r_entryframe_fp); + __ std(r_arg_call_wrapper_addr, _entry_frame_locals_neg(call_wrapper_address), r_entryframe_fp); + __ std(r_arg_result_addr, _entry_frame_locals_neg(result_address), r_entryframe_fp); + __ std(r_arg_result_type, _entry_frame_locals_neg(result_type), r_entryframe_fp); // we will save arguments_tos_address later - BLOCK_COMMENT("Copy Java arguments"); // copy Java arguments // Calculate top_of_arguments_addr which will be R17_tos (not prepushed) later. - // FIXME: why not simply use SP+frame::top_ijava_frame_size? - __ addi(r_top_of_arguments_addr, - R1_SP, frame::top_ijava_frame_abi_size); - __ add(r_top_of_arguments_addr, - r_top_of_arguments_addr, r_frame_alignment_in_bytes); + __ addi(r_top_of_arguments_addr, r_entryframe_fp, + -(save_nonvolatile_registers_size + frame::entry_frame_locals_size)); + __ sub(r_top_of_arguments_addr, r_top_of_arguments_addr, r_argument_size); // any arguments to copy? __ cmpdi(CR0, r_arg_argument_count, 0); @@ -200,6 +182,8 @@ class StubGenerator: public StubCodeGenerator { // prepare loop and copy arguments in reverse order { + Register r_argument_addr = R22_tmp2; + Register r_argumentcopy_addr = R23_tmp3; // init CTR with arg_argument_count __ mtctr(r_arg_argument_count); @@ -207,8 +191,7 @@ class StubGenerator: public StubCodeGenerator { __ mr(r_argumentcopy_addr, r_top_of_arguments_addr); // let r_argument_addr point to last incoming java argument - __ add(r_argument_addr, - r_arg_argument_addr, r_argument_size_in_bytes); + __ add(r_argument_addr, r_arg_argument_addr, r_argument_size); __ addi(r_argument_addr, r_argument_addr, -BytesPerWord); // now loop while CTR > 0 and copy arguments @@ -216,10 +199,10 @@ class StubGenerator: public StubCodeGenerator { Label next_argument; __ bind(next_argument); - __ ld(r_temp, 0, r_argument_addr); + __ ld(R0, 0, r_argument_addr); // argument_addr--; __ addi(r_argument_addr, r_argument_addr, -BytesPerWord); - __ std(r_temp, 0, r_argumentcopy_addr); + __ std(R0, 0, r_argumentcopy_addr); // argumentcopy_addr++; __ addi(r_argumentcopy_addr, r_argumentcopy_addr, BytesPerWord); @@ -232,15 +215,10 @@ class StubGenerator: public StubCodeGenerator { } { - BLOCK_COMMENT("Call frame manager or native entry."); - // Call frame manager or native entry. - Register r_new_arg_entry = R14; - assert_different_registers(r_new_arg_entry, r_top_of_arguments_addr, - r_arg_method, r_arg_thread); - - __ mr(r_new_arg_entry, r_arg_entry); + BLOCK_COMMENT("Call template interpreter or native entry."); + assert_different_registers(r_arg_entry, r_top_of_arguments_addr, r_arg_method, r_arg_thread); - // Register state on entry to frame manager / native entry: + // Register state on entry to template interpreter / native entry: // // tos - intptr_t* sender tos (prepushed) Lesp = (SP) + copied_arguments_offset - 8 // R19_method - Method @@ -262,42 +240,43 @@ class StubGenerator: public StubCodeGenerator { assert(tos != r_arg_thread && R19_method != r_arg_thread, "trashed r_arg_thread"); // Set R15_prev_state to 0 for simplifying checks in callee. - __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R11_scratch1); - // Stack on entry to frame manager / native entry: + __ load_const_optimized(R25_templateTableBase, (address)Interpreter::dispatch_table((TosState)0), R0); + // Stack on entry to template interpreter / native entry: // // F0 [TOP_IJAVA_FRAME_ABI] // alignment (optional) // [outgoing Java arguments] + // [non-volatiles] // [ENTRY_FRAME_LOCALS] // F1 [C_FRAME] // ... // // global toc register - __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R11_scratch1); + __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); // Remember the senderSP so we interpreter can pop c2i arguments off of the stack // when called via a c2i. // Pass initial_caller_sp to framemanager. __ mr(R21_sender_SP, R1_SP); - // Do a light-weight C-call here, r_new_arg_entry holds the address - // of the interpreter entry point (frame manager or native entry) + // Do a light-weight C-call here, r_arg_entry holds the address + // of the interpreter entry point (template interpreter or native entry) // and save runtime-value of LR in return_address. - assert(r_new_arg_entry != tos && r_new_arg_entry != R19_method && r_new_arg_entry != R16_thread, - "trashed r_new_arg_entry"); - return_address = __ call_stub(r_new_arg_entry); + assert(r_arg_entry != tos && r_arg_entry != R19_method && r_arg_entry != R16_thread, + "trashed r_arg_entry"); + return_address = __ call_stub(r_arg_entry); } { - BLOCK_COMMENT("Returned from frame manager or native entry."); - // Returned from frame manager or native entry. + BLOCK_COMMENT("Returned from template interpreter or native entry."); // Now pop frame, process result, and return to caller. - // Stack on exit from frame manager / native entry: + // Stack on exit from template interpreter / native entry: // // F0 [ABI] // ... + // [non-volatiles] // [ENTRY_FRAME_LOCALS] // F1 [C_FRAME] // ... @@ -310,39 +289,38 @@ class StubGenerator: public StubCodeGenerator { Label ret_is_float; Label ret_is_double; - Register r_entryframe_fp = R30; - Register r_lr = R7_ARG5; - Register r_cr = R8_ARG6; + Register r_lr = R11_scratch1; + Register r_cr = R12_scratch2; // Reload some volatile registers which we've spilled before the call - // to frame manager / native entry. + // to template interpreter / native entry. // Access all locals via frame pointer, because we know nothing about // the topmost frame's size. - __ ld(r_entryframe_fp, _abi0(callers_sp), R1_SP); + __ ld(r_entryframe_fp, _abi0(callers_sp), R1_SP); // restore after call assert_different_registers(r_entryframe_fp, R3_RET, r_arg_result_addr, r_arg_result_type, r_cr, r_lr); - __ ld(r_arg_result_addr, - _entry_frame_locals_neg(result_address), r_entryframe_fp); - __ ld(r_arg_result_type, - _entry_frame_locals_neg(result_type), r_entryframe_fp); + __ ld(r_arg_result_addr, _entry_frame_locals_neg(result_address), r_entryframe_fp); + __ ld(r_arg_result_type, _entry_frame_locals_neg(result_type), r_entryframe_fp); __ ld(r_cr, _abi0(cr), r_entryframe_fp); __ ld(r_lr, _abi0(lr), r_entryframe_fp); - - // pop frame and restore non-volatiles, LR and CR - __ mr(R1_SP, r_entryframe_fp); - __ pop_cont_fastpath(); - __ mtcr(r_cr); - __ mtlr(r_lr); + __ mtcr(r_cr); // restore CR + __ mtlr(r_lr); // restore LR // Store result depending on type. Everything that is not // T_OBJECT, T_LONG, T_FLOAT, or T_DOUBLE is treated as T_INT. - __ cmpwi(CR0, r_arg_result_type, T_OBJECT); - __ cmpwi(CR1, r_arg_result_type, T_LONG); - __ cmpwi(CR5, r_arg_result_type, T_FLOAT); - __ cmpwi(CR6, r_arg_result_type, T_DOUBLE); + // Using volatile CRs. + __ cmpwi(CR1, r_arg_result_type, T_OBJECT); + __ cmpwi(CR5, r_arg_result_type, T_LONG); + __ cmpwi(CR6, r_arg_result_type, T_FLOAT); + __ cmpwi(CR7, r_arg_result_type, T_DOUBLE); + + __ pop_cont_fastpath(); // kills CR0, uses R16_thread // restore non-volatile registers - __ restore_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14)); + __ restore_nonvolatile_registers(r_entryframe_fp, -(frame::entry_frame_locals_size + save_nonvolatile_registers_size), + true, SuperwordUseVSX); + // pop frame + __ mr(R1_SP, r_entryframe_fp); // Stack on exit from call_stub: // @@ -351,24 +329,18 @@ class StubGenerator: public StubCodeGenerator { // // no call_stub frames left. - // All non-volatiles have been restored at this point!! - assert(R3_RET == R3, "R3_RET should be R3"); - - __ beq(CR0, ret_is_object); - __ beq(CR1, ret_is_long); - __ beq(CR5, ret_is_float); - __ beq(CR6, ret_is_double); + __ beq(CR1, ret_is_object); + __ beq(CR5, ret_is_long); + __ beq(CR6, ret_is_float); + __ beq(CR7, ret_is_double); // default: __ stw(R3_RET, 0, r_arg_result_addr); __ blr(); // return to caller // case T_OBJECT: - __ bind(ret_is_object); - __ std(R3_RET, 0, r_arg_result_addr); - __ blr(); // return to caller - // case T_LONG: + __ bind(ret_is_object); __ bind(ret_is_long); __ std(R3_RET, 0, r_arg_result_addr); __ blr(); // return to caller @@ -546,6 +518,177 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Computes the Galois/Counter Mode (GCM) product and reduction. + // + // This function performs polynomial multiplication of the subkey H with + // the current GHASH state using vectorized polynomial multiplication (`vpmsumd`). + // The subkey H is divided into lower, middle, and higher halves. + // The multiplication results are reduced using `vConstC2` to stay within GF(2^128). + // The final computed value is stored back into `vState`. + static void computeGCMProduct(MacroAssembler* _masm, + VectorRegister vLowerH, VectorRegister vH, VectorRegister vHigherH, + VectorRegister vConstC2, VectorRegister vZero, VectorRegister vState, + VectorRegister vLowProduct, VectorRegister vMidProduct, VectorRegister vHighProduct, + VectorRegister vReducedLow, VectorRegister vTmp8, VectorRegister vTmp9, + VectorRegister vCombinedResult, VectorRegister vSwappedH) { + __ vxor(vH, vH, vState); + __ vpmsumd(vLowProduct, vLowerH, vH); // L : Lower Half of subkey H + __ vpmsumd(vMidProduct, vSwappedH, vH); // M : Combined halves of subkey H + __ vpmsumd(vHighProduct, vHigherH, vH); // H : Higher Half of subkey H + __ vpmsumd(vReducedLow, vLowProduct, vConstC2); // Reduction + __ vsldoi(vTmp8, vMidProduct, vZero, 8); // mL : Extract the lower 64 bits of M + __ vsldoi(vTmp9, vZero, vMidProduct, 8); // mH : Extract the higher 64 bits of M + __ vxor(vLowProduct, vLowProduct, vTmp8); // LL + mL : Partial result for lower half + __ vxor(vHighProduct, vHighProduct, vTmp9); // HH + mH : Partial result for upper half + __ vsldoi(vLowProduct, vLowProduct, vLowProduct, 8); // Swap + __ vxor(vLowProduct, vLowProduct, vReducedLow); + __ vsldoi(vCombinedResult, vLowProduct, vLowProduct, 8); // Swap + __ vpmsumd(vLowProduct, vLowProduct, vConstC2); // Reduction using constant + __ vxor(vCombinedResult, vCombinedResult, vHighProduct); // Combine reduced Low & High products + __ vxor(vState, vLowProduct, vCombinedResult); + } + + // Generate stub for ghash process blocks. + // + // Arguments for generated stub: + // state: R3_ARG1 (long[] state) + // subkeyH: R4_ARG2 (long[] subH) + // data: R5_ARG3 (byte[] data) + // blocks: R6_ARG4 (number of 16-byte blocks to process) + // + // The polynomials are processed in bit-reflected order for efficiency reasons. + // This optimization leverages the structure of the Galois field arithmetic + // to minimize the number of bit manipulations required during multiplication. + // For an explanation of how this works, refer : + // Vinodh Gopal, Erdinc Ozturk, Wajdi Feghali, Jim Guilford, Gil Wolrich, + // Martin Dixon. "Optimized Galois-Counter-Mode Implementation on Intel® + // Architecture Processor" + // http://web.archive.org/web/20130609111954/http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/communications-ia-galois-counter-mode-paper.pdf + // + // + address generate_ghash_processBlocks() { + StubCodeMark mark(this, "StubRoutines", "ghash"); + address start = __ function_entry(); + + // Registers for parameters + Register state = R3_ARG1; // long[] state + Register subkeyH = R4_ARG2; // long[] subH + Register data = R5_ARG3; // byte[] data + Register blocks = R6_ARG4; + Register temp1 = R8; + // Vector Registers + VectorRegister vZero = VR0; + VectorRegister vH = VR1; + VectorRegister vLowerH = VR2; + VectorRegister vHigherH = VR3; + VectorRegister vLowProduct = VR4; + VectorRegister vMidProduct = VR5; + VectorRegister vHighProduct = VR6; + VectorRegister vReducedLow = VR7; + VectorRegister vTmp8 = VR8; + VectorRegister vTmp9 = VR9; + VectorRegister vTmp10 = VR10; + VectorRegister vSwappedH = VR11; + VectorRegister vTmp12 = VR12; + VectorRegister loadOrder = VR13; + VectorRegister vHigh = VR14; + VectorRegister vLow = VR15; + VectorRegister vState = VR16; + VectorRegister vPerm = VR17; + VectorRegister vCombinedResult = VR18; + VectorRegister vConstC2 = VR19; + + __ li(temp1, 0xc2); + __ sldi(temp1, temp1, 56); + __ vspltisb(vZero, 0); + __ mtvrd(vConstC2, temp1); + __ lxvd2x(vH->to_vsr(), subkeyH); + __ lxvd2x(vState->to_vsr(), state); + // Operations to obtain lower and higher bytes of subkey H. + __ vspltisb(vReducedLow, 1); + __ vspltisb(vTmp10, 7); + __ vsldoi(vTmp8, vZero, vReducedLow, 1); // 0x1 + __ vor(vTmp8, vConstC2, vTmp8); // 0xC2...1 + __ vsplt(vTmp9, 0, vH); // MSB of H + __ vsl(vH, vH, vReducedLow); // Carry = H<<7 + __ vsrab(vTmp9, vTmp9, vTmp10); + __ vand(vTmp9, vTmp9, vTmp8); // Carry + __ vxor(vTmp10, vH, vTmp9); + __ vsldoi(vConstC2, vZero, vConstC2, 8); + __ vsldoi(vSwappedH, vTmp10, vTmp10, 8); // swap Lower and Higher Halves of subkey H + __ vsldoi(vLowerH, vZero, vSwappedH, 8); // H.L + __ vsldoi(vHigherH, vSwappedH, vZero, 8); // H.H +#ifdef ASSERT + __ cmpwi(CR0, blocks, 0); // Compare 'blocks' (R6_ARG4) with zero + __ asm_assert_ne("blocks should NOT be zero"); +#endif + __ clrldi(blocks, blocks, 32); + __ mtctr(blocks); + __ lvsl(loadOrder, temp1); +#ifdef VM_LITTLE_ENDIAN + __ vspltisb(vTmp12, 0xf); + __ vxor(loadOrder, loadOrder, vTmp12); +#define LE_swap_bytes(x) __ vec_perm(x, x, x, loadOrder) +#else +#define LE_swap_bytes(x) +#endif + + // This code performs Karatsuba multiplication in Galois fields to compute the GHASH operation. + // + // The Karatsuba method breaks the multiplication of two 128-bit numbers into smaller parts, + // performing three 128-bit multiplications and combining the results efficiently. + // + // (C1:C0) = A1*B1, (D1:D0) = A0*B0, (E1:E0) = (A0+A1)(B0+B1) + // (A1:A0)(B1:B0) = C1:(C0+C1+D1+E1):(D1+C0+D0+E0):D0 + // + // Inputs: + // - vH: The data vector (state), containing both B0 (lower half) and B1 (higher half). + // - vLowerH: Lower half of the subkey H (A0). + // - vHigherH: Higher half of the subkey H (A1). + // - vConstC2: Constant used for reduction (for final processing). + // + // References: + // Shay Gueron, Michael E. Kounavis. + // "Intel® Carry-Less Multiplication Instruction and its Usage for Computing the GCM Mode" + // https://web.archive.org/web/20110609115824/https://software.intel.com/file/24918 + // + Label L_aligned_loop, L_store, L_unaligned_loop, L_initialize_unaligned_loop; + __ andi(temp1, data, 15); + __ cmpwi(CR0, temp1, 0); + __ bne(CR0, L_initialize_unaligned_loop); + + __ bind(L_aligned_loop); + __ lvx(vH, temp1, data); + LE_swap_bytes(vH); + computeGCMProduct(_masm, vLowerH, vH, vHigherH, vConstC2, vZero, vState, + vLowProduct, vMidProduct, vHighProduct, vReducedLow, vTmp8, vTmp9, vCombinedResult, vSwappedH); + __ addi(data, data, 16); + __ bdnz(L_aligned_loop); + __ b(L_store); + + __ bind(L_initialize_unaligned_loop); + __ li(temp1, 0); + __ lvsl(vPerm, temp1, data); + __ lvx(vHigh, temp1, data); +#ifdef VM_LITTLE_ENDIAN + __ vspltisb(vTmp12, -1); + __ vxor(vPerm, vPerm, vTmp12); +#endif + __ bind(L_unaligned_loop); + __ addi(data, data, 16); + __ lvx(vLow, temp1, data); + __ vec_perm(vH, vHigh, vLow, vPerm); + computeGCMProduct(_masm, vLowerH, vH, vHigherH, vConstC2, vZero, vState, + vLowProduct, vMidProduct, vHighProduct, vReducedLow, vTmp8, vTmp9, vCombinedResult, vSwappedH); + __ vmr(vHigh, vLow); + __ bdnz(L_unaligned_loop); + + __ bind(L_store); + __ stxvd2x(vState->to_vsr(), state); + __ blr(); + + return start; + } // -XX:+OptimizeFill : convert fill/copy loops into intrinsic // // The code is implemented(ported from sparc) as we believe it benefits JVM98, however @@ -809,10 +952,8 @@ class StubGenerator: public StubCodeGenerator { address start_pc = __ pc(); Register tmp1 = R6_ARG4; // probably copy stub would have changed value reset it. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp1, VM_Version::_dscr_val); - __ mtdscr(tmp1); - } + __ load_const_optimized(tmp1, VM_Version::_dscr_val); + __ mtdscr(tmp1); __ li(R3_RET, 0); // return 0 __ blr(); return start_pc; @@ -924,34 +1065,13 @@ class StubGenerator: public StubCodeGenerator { __ andi_(R5_ARG3, R5_ARG3, 31); __ mtctr(tmp1); - if (!VM_Version::has_vsx()) { - - __ bind(l_8); - // Use unrolled version for mass copying (copy 32 elements a time) - // Load feeding store gets zero latency on Power6, however not on Power5. - // Therefore, the following sequence is made for the good of both. - __ ld(tmp1, 0, R3_ARG1); - __ ld(tmp2, 8, R3_ARG1); - __ ld(tmp3, 16, R3_ARG1); - __ ld(tmp4, 24, R3_ARG1); - __ std(tmp1, 0, R4_ARG2); - __ std(tmp2, 8, R4_ARG2); - __ std(tmp3, 16, R4_ARG2); - __ std(tmp4, 24, R4_ARG2); - __ addi(R3_ARG1, R3_ARG1, 32); - __ addi(R4_ARG2, R4_ARG2, 32); - __ bdnz(l_8); - - } else { // Processor supports VSX, so use it to mass copy. // Prefetch the data into the L2 cache. __ dcbt(R3_ARG1, 0); // If supported set DSCR pre-fetch to deepest. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); - __ mtdscr(tmp2); - } + __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); + __ mtdscr(tmp2); __ li(tmp1, 16); @@ -972,12 +1092,9 @@ class StubGenerator: public StubCodeGenerator { __ bdnz(l_10); // Dec CTR and loop if not zero. // Restore DSCR pre-fetch value. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val); - __ mtdscr(tmp2); - } + __ load_const_optimized(tmp2, VM_Version::_dscr_val); + __ mtdscr(tmp2); - } // VSX } // FasterArrayCopy __ bind(l_6); @@ -1220,34 +1337,15 @@ class StubGenerator: public StubCodeGenerator { __ andi_(R5_ARG3, R5_ARG3, 15); __ mtctr(tmp1); - if (!VM_Version::has_vsx()) { - - __ bind(l_8); - // Use unrolled version for mass copying (copy 16 elements a time). - // Load feeding store gets zero latency on Power6, however not on Power5. - // Therefore, the following sequence is made for the good of both. - __ ld(tmp1, 0, R3_ARG1); - __ ld(tmp2, 8, R3_ARG1); - __ ld(tmp3, 16, R3_ARG1); - __ ld(tmp4, 24, R3_ARG1); - __ std(tmp1, 0, R4_ARG2); - __ std(tmp2, 8, R4_ARG2); - __ std(tmp3, 16, R4_ARG2); - __ std(tmp4, 24, R4_ARG2); - __ addi(R3_ARG1, R3_ARG1, 32); - __ addi(R4_ARG2, R4_ARG2, 32); - __ bdnz(l_8); - - } else { // Processor supports VSX, so use it to mass copy. + + // Processor supports VSX, so use it to mass copy. // Prefetch src data into L2 cache. __ dcbt(R3_ARG1, 0); // If supported set DSCR pre-fetch to deepest. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); - __ mtdscr(tmp2); - } + __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); + __ mtdscr(tmp2); __ li(tmp1, 16); // Backbranch target aligned to 32-byte. It's not aligned 16-byte @@ -1267,12 +1365,8 @@ class StubGenerator: public StubCodeGenerator { __ bdnz(l_9); // Dec CTR and loop if not zero. // Restore DSCR pre-fetch value. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val); - __ mtdscr(tmp2); - } - - } + __ load_const_optimized(tmp2, VM_Version::_dscr_val); + __ mtdscr(tmp2); } // FasterArrayCopy __ bind(l_6); @@ -1427,60 +1521,38 @@ class StubGenerator: public StubCodeGenerator { __ andi_(R5_ARG3, R5_ARG3, 7); __ mtctr(tmp1); - if (!VM_Version::has_vsx()) { + // Processor supports VSX, so use it to mass copy. - __ bind(l_6); - // Use unrolled version for mass copying (copy 8 elements a time). - // Load feeding store gets zero latency on power6, however not on power 5. - // Therefore, the following sequence is made for the good of both. - __ ld(tmp1, 0, R3_ARG1); - __ ld(tmp2, 8, R3_ARG1); - __ ld(tmp3, 16, R3_ARG1); - __ ld(tmp4, 24, R3_ARG1); - __ std(tmp1, 0, R4_ARG2); - __ std(tmp2, 8, R4_ARG2); - __ std(tmp3, 16, R4_ARG2); - __ std(tmp4, 24, R4_ARG2); - __ addi(R3_ARG1, R3_ARG1, 32); - __ addi(R4_ARG2, R4_ARG2, 32); - __ bdnz(l_6); - - } else { // Processor supports VSX, so use it to mass copy. + // Prefetch the data into the L2 cache. + __ dcbt(R3_ARG1, 0); - // Prefetch the data into the L2 cache. - __ dcbt(R3_ARG1, 0); + // Set DSCR pre-fetch to deepest. + __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); + __ mtdscr(tmp2); - // If supported set DSCR pre-fetch to deepest. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); - __ mtdscr(tmp2); - } + __ li(tmp1, 16); - __ li(tmp1, 16); + // Backbranch target aligned to 32-byte. Not 16-byte align as + // loop contains < 8 instructions that fit inside a single + // i-cache sector. + __ align(32); - // Backbranch target aligned to 32-byte. Not 16-byte align as - // loop contains < 8 instructions that fit inside a single - // i-cache sector. - __ align(32); + __ bind(l_7); + // Use loop with VSX load/store instructions to + // copy 8 elements a time. + __ lxvd2x(tmp_vsr1, R3_ARG1); // Load src + __ stxvd2x(tmp_vsr1, R4_ARG2); // Store to dst + __ lxvd2x(tmp_vsr2, tmp1, R3_ARG1); // Load src + 16 + __ stxvd2x(tmp_vsr2, tmp1, R4_ARG2); // Store to dst + 16 + __ addi(R3_ARG1, R3_ARG1, 32); // Update src+=32 + __ addi(R4_ARG2, R4_ARG2, 32); // Update dsc+=32 + __ bdnz(l_7); // Dec CTR and loop if not zero. - __ bind(l_7); - // Use loop with VSX load/store instructions to - // copy 8 elements a time. - __ lxvd2x(tmp_vsr1, R3_ARG1); // Load src - __ stxvd2x(tmp_vsr1, R4_ARG2); // Store to dst - __ lxvd2x(tmp_vsr2, tmp1, R3_ARG1); // Load src + 16 - __ stxvd2x(tmp_vsr2, tmp1, R4_ARG2); // Store to dst + 16 - __ addi(R3_ARG1, R3_ARG1, 32); // Update src+=32 - __ addi(R4_ARG2, R4_ARG2, 32); // Update dsc+=32 - __ bdnz(l_7); // Dec CTR and loop if not zero. + // Restore DSCR pre-fetch value. + __ load_const_optimized(tmp2, VM_Version::_dscr_val); + __ mtdscr(tmp2); - // Restore DSCR pre-fetch value. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val); - __ mtdscr(tmp2); - } - } // VSX } // FasterArrayCopy // copy 1 element at a time @@ -1595,31 +1667,13 @@ class StubGenerator: public StubCodeGenerator { __ andi(R5_ARG3, R5_ARG3, 7); __ mtctr(tmp1); - if (!VM_Version::has_vsx()) { - __ bind(l_4); - // Use unrolled version for mass copying (copy 4 elements a time). - // Load feeding store gets zero latency on Power6, however not on Power5. - // Therefore, the following sequence is made for the good of both. - __ addi(R3_ARG1, R3_ARG1, -32); - __ addi(R4_ARG2, R4_ARG2, -32); - __ ld(tmp4, 24, R3_ARG1); - __ ld(tmp3, 16, R3_ARG1); - __ ld(tmp2, 8, R3_ARG1); - __ ld(tmp1, 0, R3_ARG1); - __ std(tmp4, 24, R4_ARG2); - __ std(tmp3, 16, R4_ARG2); - __ std(tmp2, 8, R4_ARG2); - __ std(tmp1, 0, R4_ARG2); - __ bdnz(l_4); - } else { // Processor supports VSX, so use it to mass copy. + // Processor supports VSX, so use it to mass copy. // Prefetch the data into the L2 cache. __ dcbt(R3_ARG1, 0); - // If supported set DSCR pre-fetch to deepest. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); - __ mtdscr(tmp2); - } + // Set DSCR pre-fetch to deepest. + __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); + __ mtdscr(tmp2); __ li(tmp1, 16); @@ -1640,11 +1694,8 @@ class StubGenerator: public StubCodeGenerator { __ bdnz(l_4); // Restore DSCR pre-fetch value. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val); - __ mtdscr(tmp2); - } - } + __ load_const_optimized(tmp2, VM_Version::_dscr_val); + __ mtdscr(tmp2); __ cmpwi(CR0, R5_ARG3, 0); __ beq(CR0, l_6); @@ -1731,33 +1782,14 @@ class StubGenerator: public StubCodeGenerator { __ andi_(R5_ARG3, R5_ARG3, 3); __ mtctr(tmp1); - if (!VM_Version::has_vsx()) { - __ bind(l_4); - // Use unrolled version for mass copying (copy 4 elements a time). - // Load feeding store gets zero latency on Power6, however not on Power5. - // Therefore, the following sequence is made for the good of both. - __ ld(tmp1, 0, R3_ARG1); - __ ld(tmp2, 8, R3_ARG1); - __ ld(tmp3, 16, R3_ARG1); - __ ld(tmp4, 24, R3_ARG1); - __ std(tmp1, 0, R4_ARG2); - __ std(tmp2, 8, R4_ARG2); - __ std(tmp3, 16, R4_ARG2); - __ std(tmp4, 24, R4_ARG2); - __ addi(R3_ARG1, R3_ARG1, 32); - __ addi(R4_ARG2, R4_ARG2, 32); - __ bdnz(l_4); - - } else { // Processor supports VSX, so use it to mass copy. + // Processor supports VSX, so use it to mass copy. // Prefetch the data into the L2 cache. __ dcbt(R3_ARG1, 0); - // If supported set DSCR pre-fetch to deepest. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); - __ mtdscr(tmp2); - } + // Set DSCR pre-fetch to deepest. + __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); + __ mtdscr(tmp2); __ li(tmp1, 16); @@ -1778,12 +1810,9 @@ class StubGenerator: public StubCodeGenerator { __ bdnz(l_5); // Dec CTR and loop if not zero. // Restore DSCR pre-fetch value. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val); - __ mtdscr(tmp2); - } + __ load_const_optimized(tmp2, VM_Version::_dscr_val); + __ mtdscr(tmp2); - } // VSX } // FasterArrayCopy // copy 1 element at a time @@ -1876,31 +1905,13 @@ class StubGenerator: public StubCodeGenerator { __ andi(R5_ARG3, R5_ARG3, 3); __ mtctr(tmp1); - if (!VM_Version::has_vsx()) { - __ bind(l_4); - // Use unrolled version for mass copying (copy 4 elements a time). - // Load feeding store gets zero latency on Power6, however not on Power5. - // Therefore, the following sequence is made for the good of both. - __ addi(R3_ARG1, R3_ARG1, -32); - __ addi(R4_ARG2, R4_ARG2, -32); - __ ld(tmp4, 24, R3_ARG1); - __ ld(tmp3, 16, R3_ARG1); - __ ld(tmp2, 8, R3_ARG1); - __ ld(tmp1, 0, R3_ARG1); - __ std(tmp4, 24, R4_ARG2); - __ std(tmp3, 16, R4_ARG2); - __ std(tmp2, 8, R4_ARG2); - __ std(tmp1, 0, R4_ARG2); - __ bdnz(l_4); - } else { // Processor supports VSX, so use it to mass copy. + // Processor supports VSX, so use it to mass copy. // Prefetch the data into the L2 cache. __ dcbt(R3_ARG1, 0); - // If supported set DSCR pre-fetch to deepest. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); - __ mtdscr(tmp2); - } + // Set DSCR pre-fetch to deepest. + __ load_const_optimized(tmp2, VM_Version::_dscr_val | 7); + __ mtdscr(tmp2); __ li(tmp1, 16); @@ -1921,11 +1932,8 @@ class StubGenerator: public StubCodeGenerator { __ bdnz(l_4); // Restore DSCR pre-fetch value. - if (VM_Version::has_mfdscr()) { - __ load_const_optimized(tmp2, VM_Version::_dscr_val); - __ mtdscr(tmp2); - } - } + __ load_const_optimized(tmp2, VM_Version::_dscr_val); + __ mtdscr(tmp2); __ cmpwi(CR0, R5_ARG3, 0); __ beq(CR0, l_1); @@ -5028,6 +5036,10 @@ void generate_lookup_secondary_supers_table_stub() { StubRoutines::_data_cache_writeback_sync = generate_data_cache_writeback_sync(); } + if (UseGHASHIntrinsics) { + StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); + } + if (UseAESIntrinsics) { StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); diff --git a/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp b/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp index 60cca4efb57..fed3f208f06 100644 --- a/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/stubRoutines_ppc_64.cpp @@ -77,13 +77,10 @@ static julong compute_inverse_poly(julong long_poly) { // Constants to fold n words as needed by macroAssembler. address StubRoutines::ppc::generate_crc_constants(juint reverse_poly) { // Layout of constant table: - // <= Power7 Little Endian: 4 tables for byte folding - // <= Power7 Big Endian: 1 table for single byte folding + 4 tables for multi-byte folding // >= Power8: 1 table for single byte folding + constants for fast vector implementation - const bool use_vector = VM_Version::has_vpmsumb(); const int vector_size = 16 * (CRC32_UNROLL_FACTOR2 + CRC32_UNROLL_FACTOR / CRC32_UNROLL_FACTOR2); - const int size = use_vector ? CRC32_TABLE_SIZE + vector_size : (4 BIG_ENDIAN_ONLY(+1)) * CRC32_TABLE_SIZE; + const int size = CRC32_TABLE_SIZE + vector_size; const address consts = (address)os::malloc(size, mtInternal); if (consts == nullptr) { vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "CRC constants: no enough space"); @@ -91,43 +88,8 @@ address StubRoutines::ppc::generate_crc_constants(juint reverse_poly) { juint* ptr = (juint*)consts; // Simple table used for single byte folding - LITTLE_ENDIAN_ONLY(if (use_vector)) { - for (int i = 0; i < 256; ++i) { - ptr[i] = fold_byte(i, reverse_poly); - } - } - - if (!use_vector) { - BIG_ENDIAN_ONLY(ptr = (juint*)(consts + CRC32_TABLE_SIZE);) - // <= Power7: 4 tables - for (int i = 0; i < 256; ++i) { - juint a = fold_byte(i, reverse_poly), - b = fold_byte(a, reverse_poly), - c = fold_byte(b, reverse_poly), - d = fold_byte(c, reverse_poly); -#ifndef VM_LITTLE_ENDIAN - a = byteswap(a); - b = byteswap(b); - c = byteswap(c); - d = byteswap(d); -#endif - ptr[i ] = a; - ptr[i + 256] = b; - ptr[i + 2* 256] = c; - ptr[i + 3* 256] = d; - } -#if 0 - for (int i = 0; i < 4; ++i) { - tty->print_cr("table %d:", i); - for (int j = 0; j < 32; ++j) { - for (int k = 0; k < 8; ++k) { - tty->print("%08x ", ptr[i*256 + j*8 + k]); - } - tty->cr(); - } - } -#endif - return consts; + for (int i = 0; i < 256; ++i) { + ptr[i] = fold_byte(i, reverse_poly); } // >= Power8: vector constants diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index a8f5dbda484..ab4f35f4d8c 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -119,12 +119,13 @@ address TemplateInterpreterGenerator::generate_slow_signature_handler() { const FloatRegister floatSlot = F0; address entry = __ function_entry(); + int save_nonvolatile_registers_size = __ save_nonvolatile_registers_size(false, false); __ save_LR(R0); - __ save_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14)); + __ save_nonvolatile_registers(R1_SP, -save_nonvolatile_registers_size, false, false); // We use target_sp for storing arguments in the C frame. __ mr(target_sp, R1_SP); - __ push_frame_reg_args_nonvolatiles(0, R11_scratch1); + __ push_frame(frame::native_abi_reg_args_size + save_nonvolatile_registers_size, R11_scratch1); __ mr(arg_java, R3_ARG1); @@ -309,7 +310,7 @@ address TemplateInterpreterGenerator::generate_slow_signature_handler() { __ bind(loop_end); __ pop_frame(); - __ restore_nonvolatile_gprs(R1_SP, _spill_nonvolatiles_neg(r14)); + __ restore_nonvolatile_registers(R1_SP, -save_nonvolatile_registers_size, false, false); __ restore_LR(R0); __ blr(); @@ -1077,7 +1078,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M // PPC64 specific: switch (kind) { - case Interpreter::java_lang_math_sqrt: use_instruction = VM_Version::has_fsqrt(); break; + case Interpreter::java_lang_math_sqrt: use_instruction = true; break; case Interpreter::java_lang_math_abs: use_instruction = true; break; case Interpreter::java_lang_math_fmaF: case Interpreter::java_lang_math_fmaD: use_instruction = UseFMA; break; @@ -1089,8 +1090,9 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M case Interpreter::java_lang_math_cos : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); break; case Interpreter::java_lang_math_tan : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); break; case Interpreter::java_lang_math_tanh : /* run interpreted */ break; + case Interpreter::java_lang_math_cbrt : /* run interpreted */ break; case Interpreter::java_lang_math_abs : /* run interpreted */ break; - case Interpreter::java_lang_math_sqrt : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); break; + case Interpreter::java_lang_math_sqrt : /* run interpreted */ break; case Interpreter::java_lang_math_log : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); break; case Interpreter::java_lang_math_log10: runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10); break; case Interpreter::java_lang_math_pow : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dpow); num_args = 2; break; @@ -1583,6 +1585,24 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ st_ptr(R0, JavaThread::pending_jni_exception_check_fn_offset(), R16_thread); } + #if INCLUDE_JFR + __ enter_jfr_critical_section(); + + // This poll test is to uphold the invariant that a JFR sampled frame + // must not return to its caller without a prior safepoint poll check. + // The earlier poll check in this routine is insufficient for this purpose + // because the thread has transitioned back to Java. + + Label slow_path, fast_path; + __ safepoint_poll(slow_path, R11_scratch1, true /* at_return */, false /* in_nmethod */); + __ b(fast_path); + __ bind(slow_path); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), R16_thread); + __ align(32); + __ bind(fast_path); + +#endif // INCLUDE_JFR + __ reset_last_Java_frame(); // Jvmdi/jvmpi support. Whether we've got an exception pending or @@ -1624,11 +1644,12 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ lfd(F1_RET, _ijava_state_neg(fresult), R11_scratch1); __ call_stub(result_handler_addr); - __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R12_scratch2, R11_scratch1, R0); + JFR_ONLY(__ leave_jfr_critical_section();) // Must use the return pc which was loaded from the caller's frame // as the VM uses return-pc-patching for deoptimization. - __ mtlr(R0); + __ mtlr(R12_scratch2); __ blr(); //----------------------------------------------------------------------------- diff --git a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp index 8be6080e3d1..7431f77aeff 100644 --- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp @@ -319,14 +319,7 @@ void TemplateTable::fast_aldc(LdcType type) { __ ld(R31, simm16_rest, R11_scratch1); __ resolve_oop_handle(R31, R11_scratch1, R12_scratch2, MacroAssembler::PRESERVATION_NONE); __ cmpld(CR0, R17_tos, R31); - if (VM_Version::has_isel()) { - __ isel_0(R17_tos, CR0, Assembler::equal); - } else { - Label not_sentinel; - __ bne(CR0, not_sentinel); - __ li(R17_tos, 0); - __ bind(not_sentinel); - } + __ isel_0(R17_tos, CR0, Assembler::equal); __ verify_oop(R17_tos); __ dispatch_epilog(atos, Bytecodes::length_for(bytecode())); @@ -1042,7 +1035,7 @@ void TemplateTable::bastore() { // Need to check whether array is boolean or byte // since both types share the bastore bytecode. - __ load_klass(Rscratch, Rarray); + __ load_klass_check_null_throw(Rscratch, Rarray, Rscratch); __ lwz(Rscratch, in_bytes(Klass::layout_helper_offset()), Rscratch); int diffbit = exact_log2(Klass::layout_helper_boolean_diffbit()); __ testbitdi(CR0, R0, Rscratch, diffbit); @@ -1534,25 +1527,12 @@ void TemplateTable::convert() { case Bytecodes::_i2f: __ extsw(R17_tos, R17_tos); __ move_l_to_d(); - if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only - // Comment: alternatively, load with sign extend could be done by lfiwax. - __ fcfids(F15_ftos, F15_ftos); - } else { - __ fcfid(F15_ftos, F15_ftos); - __ frsp(F15_ftos, F15_ftos); - } + __ fcfids(F15_ftos, F15_ftos); break; case Bytecodes::_l2f: - if (VM_Version::has_fcfids()) { // fcfids is >= Power7 only - __ move_l_to_d(); - __ fcfids(F15_ftos, F15_ftos); - } else { - // Avoid rounding problem when result should be 0x3f800001: need fixup code before fcfid+frsp. - __ mr(R3_ARG1, R17_tos); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::l2f)); - __ fmr(F15_ftos, F1_RET); - } + __ move_l_to_d(); + __ fcfids(F15_ftos, F15_ftos); break; case Bytecodes::_f2d: @@ -1748,16 +1728,18 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { const Register osr_nmethod = R31; __ mr(osr_nmethod, R3_RET); __ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R11_scratch1); + JFR_ONLY(__ enter_jfr_critical_section();) __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin), R16_thread); __ reset_last_Java_frame(); // OSR buffer is in ARG1. // Remove the interpreter frame. - __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R0, R11_scratch1, R12_scratch2); + __ merge_frames(/*top_frame_sp*/ R21_sender_SP, /*return_pc*/ R12_scratch2, R11_scratch1, R0); + JFR_ONLY(__ leave_jfr_critical_section();) // Jump to the osr code. __ ld(R11_scratch1, nmethod::osr_entry_point_offset(), osr_nmethod); - __ mtlr(R0); + __ mtlr(R12_scratch2); __ mtctr(R11_scratch1); __ bctr(); diff --git a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp index 5c7b0067c3a..ae5410b12df 100644 --- a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp +++ b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023 SAP SE. All rights reserved. + * Copyright (c) 2023, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,86 +35,6 @@ #define __ _masm-> -// for callee saved regs, according to the caller's ABI -static int compute_reg_save_area_size(const ABIDescriptor& abi) { - int size = 0; - for (int i = 0; i < Register::number_of_registers; i++) { - Register reg = as_Register(i); - // R1 saved/restored by prologue/epilogue, R13 (system thread) won't get modified! - if (reg == R1_SP || reg == R13) continue; - if (!abi.is_volatile_reg(reg)) { - size += 8; // bytes - } - } - - for (int i = 0; i < FloatRegister::number_of_registers; i++) { - FloatRegister reg = as_FloatRegister(i); - if (!abi.is_volatile_reg(reg)) { - size += 8; // bytes - } - } - - return size; -} - -static void preserve_callee_saved_registers(MacroAssembler* _masm, const ABIDescriptor& abi, int reg_save_area_offset) { - // 1. iterate all registers in the architecture - // - check if they are volatile or not for the given abi - // - if NOT, we need to save it here - - int offset = reg_save_area_offset; - - __ block_comment("{ preserve_callee_saved_regs "); - for (int i = 0; i < Register::number_of_registers; i++) { - Register reg = as_Register(i); - // R1 saved/restored by prologue/epilogue, R13 (system thread) won't get modified! - if (reg == R1_SP || reg == R13) continue; - if (!abi.is_volatile_reg(reg)) { - __ std(reg, offset, R1_SP); - offset += 8; - } - } - - for (int i = 0; i < FloatRegister::number_of_registers; i++) { - FloatRegister reg = as_FloatRegister(i); - if (!abi.is_volatile_reg(reg)) { - __ stfd(reg, offset, R1_SP); - offset += 8; - } - } - - __ block_comment("} preserve_callee_saved_regs "); -} - -static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescriptor& abi, int reg_save_area_offset) { - // 1. iterate all registers in the architecture - // - check if they are volatile or not for the given abi - // - if NOT, we need to restore it here - - int offset = reg_save_area_offset; - - __ block_comment("{ restore_callee_saved_regs "); - for (int i = 0; i < Register::number_of_registers; i++) { - Register reg = as_Register(i); - // R1 saved/restored by prologue/epilogue, R13 (system thread) won't get modified! - if (reg == R1_SP || reg == R13) continue; - if (!abi.is_volatile_reg(reg)) { - __ ld(reg, offset, R1_SP); - offset += 8; - } - } - - for (int i = 0; i < FloatRegister::number_of_registers; i++) { - FloatRegister reg = as_FloatRegister(i); - if (!abi.is_volatile_reg(reg)) { - __ lfd(reg, offset, R1_SP); - offset += 8; - } - } - - __ block_comment("} restore_callee_saved_regs "); -} - static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; // arg save & restore + move @@ -140,13 +60,17 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, // The Java call uses the JIT ABI, but we also call C. int out_arg_area = MAX2(frame::jit_out_preserve_size + out_arg_bytes, (int)frame::native_abi_reg_args_size); - int reg_save_area_size = compute_reg_save_area_size(abi); + MacroAssembler* _masm = new MacroAssembler(&buffer); + int reg_save_area_size = __ save_nonvolatile_registers_size(true, SuperwordUseVSX); RegSpiller arg_spiller(call_regs._arg_regs); RegSpiller result_spiller(call_regs._ret_regs); int res_save_area_offset = out_arg_area; int arg_save_area_offset = res_save_area_offset + result_spiller.spill_size_bytes(); int reg_save_area_offset = arg_save_area_offset + arg_spiller.spill_size_bytes(); + if (SuperwordUseVSX) { // VectorRegisters want alignment + reg_save_area_offset = align_up(reg_save_area_offset, StackAlignmentInBytes); + } int frame_data_offset = reg_save_area_offset + reg_save_area_size; int frame_bottom_offset = frame_data_offset + sizeof(UpcallStub::FrameData); @@ -201,7 +125,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, ////////////////////////////////////////////////////////////////////////////// - MacroAssembler* _masm = new MacroAssembler(&buffer); address start = __ function_entry(); // called by C __ save_LR_CR(R0); assert((abi._stack_alignment_bytes % 16) == 0, "must be 16 byte aligned"); @@ -212,7 +135,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, // (and maybe attach it). arg_spiller.generate_spill(_masm, arg_save_area_offset); // Java methods won't preserve them, so save them here: - preserve_callee_saved_registers(_masm, abi, reg_save_area_offset); + __ save_nonvolatile_registers(R1_SP, reg_save_area_offset, true, SuperwordUseVSX); // Java code uses TOC (pointer to code cache). __ load_const_optimized(R29_TOC, MacroAssembler::global_toc(), R0); // reinit @@ -310,7 +233,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, __ call_c(call_target_address); __ block_comment("} on_exit"); - restore_callee_saved_registers(_masm, abi, reg_save_area_offset); + __ restore_nonvolatile_registers(R1_SP, reg_save_area_offset, true, SuperwordUseVSX); result_spiller.generate_fill(_masm, res_save_area_offset); diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index 8ec69bffe15..ad5e915a838 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -64,16 +64,8 @@ void VM_Version::initialize() { FLAG_SET_ERGO(PowerArchitecturePPC64, 10); } else if (VM_Version::has_darn()) { FLAG_SET_ERGO(PowerArchitecturePPC64, 9); - } else if (VM_Version::has_lqarx()) { - FLAG_SET_ERGO(PowerArchitecturePPC64, 8); - } else if (VM_Version::has_popcntw()) { - FLAG_SET_ERGO(PowerArchitecturePPC64, 7); - } else if (VM_Version::has_cmpb()) { - FLAG_SET_ERGO(PowerArchitecturePPC64, 6); - } else if (VM_Version::has_popcntb()) { - FLAG_SET_ERGO(PowerArchitecturePPC64, 5); } else { - FLAG_SET_ERGO(PowerArchitecturePPC64, 0); + FLAG_SET_ERGO(PowerArchitecturePPC64, 8); } } @@ -81,20 +73,14 @@ void VM_Version::initialize() { switch (PowerArchitecturePPC64) { case 10: if (!VM_Version::has_brw() ) break; case 9: if (!VM_Version::has_darn() ) break; - case 8: if (!VM_Version::has_lqarx() ) break; - case 7: if (!VM_Version::has_popcntw()) break; - case 6: if (!VM_Version::has_cmpb() ) break; - case 5: if (!VM_Version::has_popcntb()) break; - case 0: PowerArchitecturePPC64_ok = true; break; + case 8: PowerArchitecturePPC64_ok = true; break; default: break; } guarantee(PowerArchitecturePPC64_ok, "PowerArchitecturePPC64 cannot be set to " "%zu on this machine", PowerArchitecturePPC64); // Power 8: Configure Data Stream Control Register. - if (PowerArchitecturePPC64 >= 8 && has_mfdscr()) { - config_dscr(); - } + config_dscr(); if (!UseSIGTRAP) { MSG(TrapBasedICMissChecks); @@ -109,27 +95,13 @@ void VM_Version::initialize() { FLAG_SET_ERGO(TrapBasedRangeChecks, false); } - // Power7 and later. - if (PowerArchitecturePPC64 > 6) { - if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { - FLAG_SET_ERGO(UsePopCountInstruction, true); - } - } - - if (!VM_Version::has_isel() && FLAG_IS_DEFAULT(ConditionalMoveLimit)) { - FLAG_SET_ERGO(ConditionalMoveLimit, 0); - } - - if (PowerArchitecturePPC64 >= 8) { + if (PowerArchitecturePPC64 >= 9) { + // Performance is good since Power9. if (FLAG_IS_DEFAULT(SuperwordUseVSX)) { FLAG_SET_ERGO(SuperwordUseVSX, true); } - } else { - if (SuperwordUseVSX) { - warning("SuperwordUseVSX specified, but needs at least Power8."); - FLAG_SET_DEFAULT(SuperwordUseVSX, false); - } } + MaxVectorSize = SuperwordUseVSX ? 16 : 8; if (FLAG_IS_DEFAULT(AlignVector)) { FLAG_SET_ERGO(AlignVector, false); @@ -198,28 +170,12 @@ void VM_Version::initialize() { // Create and print feature-string. char buf[(num_features+1) * 16]; // Max 16 chars per feature. jio_snprintf(buf, sizeof(buf), - "ppc64%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - (has_fsqrt() ? " fsqrt" : ""), - (has_isel() ? " isel" : ""), - (has_lxarxeh() ? " lxarxeh" : ""), - (has_cmpb() ? " cmpb" : ""), - (has_popcntb() ? " popcntb" : ""), - (has_popcntw() ? " popcntw" : ""), - (has_fcfids() ? " fcfids" : ""), - (has_vand() ? " vand" : ""), - (has_lqarx() ? " lqarx" : ""), - (has_vcipher() ? " aes" : ""), - (has_vpmsumb() ? " vpmsumb" : ""), - (has_mfdscr() ? " mfdscr" : ""), - (has_vsx() ? " vsx" : ""), - (has_ldbrx() ? " ldbrx" : ""), - (has_stdbrx() ? " stdbrx" : ""), - (has_vshasig() ? " sha" : ""), + "ppc64 sha aes%s%s", (has_darn() ? " darn" : ""), (has_brw() ? " brw" : "") // Make sure number of %s matches num_features! ); - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); if (Verbose) { print_features(); } @@ -283,24 +239,12 @@ void VM_Version::initialize() { } // The AES intrinsic stubs require AES instruction support. - if (has_vcipher()) { - if (FLAG_IS_DEFAULT(UseAES)) { - UseAES = true; - } - } else if (UseAES) { - if (!FLAG_IS_DEFAULT(UseAES)) - warning("AES instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseAES, false); + if (FLAG_IS_DEFAULT(UseAES)) { + UseAES = true; } - if (UseAES && has_vcipher()) { - if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { - UseAESIntrinsics = true; - } - } else if (UseAESIntrinsics) { - if (!FLAG_IS_DEFAULT(UseAESIntrinsics)) - warning("AES intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESIntrinsics, false); + if (FLAG_IS_DEFAULT(UseAESIntrinsics)) { + UseAESIntrinsics = true; } if (UseAESCTRIntrinsics) { @@ -308,9 +252,8 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); } - if (UseGHASHIntrinsics) { - warning("GHASH intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); + if (FLAG_IS_DEFAULT(UseGHASHIntrinsics)) { + UseGHASHIntrinsics = true; } if (FLAG_IS_DEFAULT(UseFMA)) { @@ -322,14 +265,8 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseMD5Intrinsics, false); } - if (has_vshasig()) { - if (FLAG_IS_DEFAULT(UseSHA)) { - UseSHA = true; - } - } else if (UseSHA) { - if (!FLAG_IS_DEFAULT(UseSHA)) - warning("SHA instructions are not available on this CPU"); - FLAG_SET_DEFAULT(UseSHA, false); + if (FLAG_IS_DEFAULT(UseSHA)) { + UseSHA = true; } if (UseSHA1Intrinsics) { @@ -337,7 +274,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); } - if (UseSHA && has_vshasig()) { + if (UseSHA) { if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) { FLAG_SET_DEFAULT(UseSHA256Intrinsics, true); } @@ -346,7 +283,7 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); } - if (UseSHA && has_vshasig()) { + if (UseSHA) { if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); } @@ -364,12 +301,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA, false); } - if (UseSecondarySupersTable && PowerArchitecturePPC64 < 7) { - if (!FLAG_IS_DEFAULT(UseSecondarySupersTable)) { - warning("UseSecondarySupersTable requires Power7 or later."); - } - FLAG_SET_DEFAULT(UseSecondarySupersTable, false); - } #ifdef COMPILER2 if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { @@ -519,7 +450,7 @@ void VM_Version::print_platform_virtualization_info(outputStream* st) { } void VM_Version::print_features() { - tty->print_cr("Version: %s L1_data_cache_line_size=%d", features_string(), L1_data_cache_line_size()); + tty->print_cr("Version: %s L1_data_cache_line_size=%d", cpu_info_string(), L1_data_cache_line_size()); if (Verbose) { if (ContendedPaddingWidth > 0) { @@ -555,29 +486,10 @@ void VM_Version::determine_features() { // Emit code. void (*test)(address addr, uint64_t offset)=(void(*)(address addr, uint64_t offset))(void *)a->function_entry(); uint32_t *code = (uint32_t *)a->pc(); - // Don't use R0 in ldarx. // Keep R3_ARG1 unmodified, it contains &field (see below). // Keep R4_ARG2 unmodified, it contains offset = 0 (see below). - a->fsqrt(F3, F4); // code[0] -> fsqrt_m - a->fsqrts(F3, F4); // code[1] -> fsqrts_m - a->isel(R7, R5, R6, 0); // code[2] -> isel_m - a->ldarx_unchecked(R7, R3_ARG1, R4_ARG2, 1); // code[3] -> lxarx_m - a->cmpb(R7, R5, R6); // code[4] -> cmpb - a->popcntb(R7, R5); // code[5] -> popcntb - a->popcntw(R7, R5); // code[6] -> popcntw - a->fcfids(F3, F4); // code[7] -> fcfids - a->vand(VR0, VR0, VR0); // code[8] -> vand - // arg0 of lqarx must be an even register, (arg1 + arg2) must be a multiple of 16 - a->lqarx_unchecked(R6, R3_ARG1, R4_ARG2, 1); // code[9] -> lqarx_m - a->vcipher(VR0, VR1, VR2); // code[10] -> vcipher - a->vpmsumb(VR0, VR1, VR2); // code[11] -> vpmsumb - a->mfdscr(R0); // code[12] -> mfdscr - a->lxvd2x(VSR0, R3_ARG1); // code[13] -> vsx - a->ldbrx(R7, R3_ARG1, R4_ARG2); // code[14] -> ldbrx - a->stdbrx(R7, R3_ARG1, R4_ARG2); // code[15] -> stdbrx - a->vshasigmaw(VR0, VR1, 1, 0xF); // code[16] -> vshasig - a->darn(R7); // code[17] -> darn - a->brw(R5, R6); // code[18] -> brw + a->darn(R7); + a->brw(R5, R6); a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. @@ -612,23 +524,6 @@ void VM_Version::determine_features() { // determine which instructions are legal. int feature_cntr = 0; - if (code[feature_cntr++]) features |= fsqrt_m; - if (code[feature_cntr++]) features |= fsqrts_m; - if (code[feature_cntr++]) features |= isel_m; - if (code[feature_cntr++]) features |= lxarxeh_m; - if (code[feature_cntr++]) features |= cmpb_m; - if (code[feature_cntr++]) features |= popcntb_m; - if (code[feature_cntr++]) features |= popcntw_m; - if (code[feature_cntr++]) features |= fcfids_m; - if (code[feature_cntr++]) features |= vand_m; - if (code[feature_cntr++]) features |= lqarx_m; - if (code[feature_cntr++]) features |= vcipher_m; - if (code[feature_cntr++]) features |= vpmsumb_m; - if (code[feature_cntr++]) features |= mfdscr_m; - if (code[feature_cntr++]) features |= vsx_m; - if (code[feature_cntr++]) features |= ldbrx_m; - if (code[feature_cntr++]) features |= stdbrx_m; - if (code[feature_cntr++]) features |= vshasig_m; if (code[feature_cntr++]) features |= darn_m; if (code[feature_cntr++]) features |= brw_m; @@ -726,6 +621,6 @@ void VM_Version::initialize_cpu_information(void) { _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()); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "PPC %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.hpp b/src/hotspot/cpu/ppc/vm_version_ppc.hpp index 6096f8e4fd1..18dfd843c19 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.hpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2024 SAP SE. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,46 +32,12 @@ class VM_Version: public Abstract_VM_Version { protected: enum Feature_Flag { - fsqrt, - fsqrts, - isel, - lxarxeh, - cmpb, - popcntb, - popcntw, - fcfids, - vand, - lqarx, - vcipher, - vpmsumb, - mfdscr, - vsx, - ldbrx, - stdbrx, - vshasig, darn, brw, num_features // last entry to count features }; enum Feature_Flag_Set { unknown_m = 0, - fsqrt_m = (1 << fsqrt ), - fsqrts_m = (1 << fsqrts ), - isel_m = (1 << isel ), - lxarxeh_m = (1 << lxarxeh), - cmpb_m = (1 << cmpb ), - popcntb_m = (1 << popcntb), - popcntw_m = (1 << popcntw), - fcfids_m = (1 << fcfids ), - vand_m = (1 << vand ), - lqarx_m = (1 << lqarx ), - vcipher_m = (1 << vcipher), - vpmsumb_m = (1 << vpmsumb), - mfdscr_m = (1 << mfdscr ), - vsx_m = (1 << vsx ), - ldbrx_m = (1 << ldbrx ), - stdbrx_m = (1 << stdbrx ), - vshasig_m = (1 << vshasig), darn_m = (1 << darn ), brw_m = (1 << brw ), all_features_m = (unsigned long)-1 @@ -101,28 +67,9 @@ class VM_Version: public Abstract_VM_Version { static bool is_determine_features_test_running() { return _is_determine_features_test_running; } // CPU instruction support - static bool has_fsqrt() { return (_features & fsqrt_m) != 0; } - static bool has_fsqrts() { return (_features & fsqrts_m) != 0; } - static bool has_isel() { return (_features & isel_m) != 0; } - static bool has_lxarxeh() { return (_features & lxarxeh_m) !=0; } - static bool has_cmpb() { return (_features & cmpb_m) != 0; } - static bool has_popcntb() { return (_features & popcntb_m) != 0; } - static bool has_popcntw() { return (_features & popcntw_m) != 0; } - static bool has_fcfids() { return (_features & fcfids_m) != 0; } - static bool has_vand() { return (_features & vand_m) != 0; } - static bool has_lqarx() { return (_features & lqarx_m) != 0; } - static bool has_vcipher() { return (_features & vcipher_m) != 0; } - static bool has_vpmsumb() { return (_features & vpmsumb_m) != 0; } - static bool has_mfdscr() { return (_features & mfdscr_m) != 0; } - static bool has_vsx() { return (_features & vsx_m) != 0; } - static bool has_ldbrx() { return (_features & ldbrx_m) != 0; } - static bool has_stdbrx() { return (_features & stdbrx_m) != 0; } - static bool has_vshasig() { return (_features & vshasig_m) != 0; } static bool has_darn() { return (_features & darn_m) != 0; } static bool has_brw() { return (_features & brw_m) != 0; } - static bool has_mtfprd() { return has_vpmsumb(); } // alias for P8 - // Assembler testing static void allow_all(); static void revert(); diff --git a/src/hotspot/cpu/ppc/vmreg_ppc.cpp b/src/hotspot/cpu/ppc/vmreg_ppc.cpp index d8a5c35cac0..2ed68578a80 100644 --- a/src/hotspot/cpu/ppc/vmreg_ppc.cpp +++ b/src/hotspot/cpu/ppc/vmreg_ppc.cpp @@ -32,21 +32,29 @@ void VMRegImpl::set_regName() { for (i = 0; i < ConcreteRegisterImpl::max_gpr; ) { regName[i++] = reg->name(); regName[i++] = reg->name(); - if (reg->encoding() < Register::number_of_registers-1) + if (reg->encoding() < Register::number_of_registers - 1) { reg = reg->successor(); + } } FloatRegister freg = ::as_FloatRegister(0); for ( ; i < ConcreteRegisterImpl::max_fpr; ) { regName[i++] = freg->name(); regName[i++] = freg->name(); - if (reg->encoding() < FloatRegister::number_of_registers-1) + if (reg->encoding() < FloatRegister::number_of_registers - 1) { freg = freg->successor(); + } } VectorSRegister vsreg = ::as_VectorSRegister(0); for ( ; i < ConcreteRegisterImpl::max_vsr; ) { regName[i++] = vsreg->name(); + regName[i++] = vsreg->name(); + regName[i++] = vsreg->name(); + regName[i++] = vsreg->name(); + if (reg->encoding() < VectorSRegister::number_of_registers - 1) { + vsreg = vsreg->successor(); + } } for ( ; i < ConcreteRegisterImpl::number_of_registers; ) { diff --git a/src/hotspot/cpu/ppc/vmreg_ppc.hpp b/src/hotspot/cpu/ppc/vmreg_ppc.hpp index b2d97a6d385..4e25c8b3cea 100644 --- a/src/hotspot/cpu/ppc/vmreg_ppc.hpp +++ b/src/hotspot/cpu/ppc/vmreg_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2022 SAP SE. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,12 +62,17 @@ inline FloatRegister as_FloatRegister() { inline VectorSRegister as_VectorSRegister() { assert(is_VectorSRegister(), "must be"); - return ::as_VectorSRegister(value() - ConcreteRegisterImpl::max_fpr); + return ::as_VectorSRegister((value() - ConcreteRegisterImpl::max_fpr) >> 2); } inline bool is_concrete() { assert(is_reg(), "must be"); - return is_even(value()); + if (is_Register() || is_FloatRegister()) return is_even(value()); + if (is_VectorSRegister()) { + int base = value() - ConcreteRegisterImpl::max_fpr; + return (base & 3) == 0; + } + return true; } #endif // CPU_PPC_VMREG_PPC_HPP diff --git a/src/hotspot/cpu/ppc/vmreg_ppc.inline.hpp b/src/hotspot/cpu/ppc/vmreg_ppc.inline.hpp index afaefe50c97..2424df8da01 100644 --- a/src/hotspot/cpu/ppc/vmreg_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/vmreg_ppc.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2022 SAP SE. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,8 @@ inline VMReg FloatRegister::as_VMReg() const { } inline VMReg VectorSRegister::as_VMReg() const { - return VMRegImpl::as_VMReg((encoding()) + ConcreteRegisterImpl::max_fpr); + // Four halves, multiply by 4. + return VMRegImpl::as_VMReg((encoding() << 2) + ConcreteRegisterImpl::max_fpr); } inline VMReg ConditionRegister::as_VMReg() const { diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index e036cb6b1ec..3317ccc3b53 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -671,29 +671,86 @@ class Assembler : public AbstractAssembler { #undef INSN -// Load/store register (all modes) -#define INSN(NAME, op, funct3) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - guarantee(is_simm12(offset), "offset is invalid."); \ - unsigned insn = 0; \ - int32_t val = offset & 0xfff; \ - patch((address)&insn, 6, 0, op); \ - patch((address)&insn, 14, 12, funct3); \ - patch_reg((address)&insn, 15, Rs); \ - patch_reg((address)&insn, 7, Rd); \ - patch((address)&insn, 31, 20, val); \ - emit(insn); \ - } - - INSN(lb, 0b0000011, 0b000); - INSN(_lbu, 0b0000011, 0b100); - INSN(_lh, 0b0000011, 0b001); - INSN(_lhu, 0b0000011, 0b101); - INSN(_lw, 0b0000011, 0b010); - INSN(lwu, 0b0000011, 0b110); - INSN(_ld, 0b0000011, 0b011); + private: + // Load + enum LoadWidthFunct3 : uint8_t { + LOAD_WIDTH_BYTE = 0b000, + LOAD_WIDTH_HALFWORD = 0b001, + LOAD_WIDTH_WORD = 0b010, + LOAD_WIDTH_DOUBLEWORD = 0b011, + LOAD_WIDTH_BYTE_UNSIGNED = 0b100, + LOAD_WIDTH_HALFWORD_UNSIGNED = 0b101, + LOAD_WIDTH_WORD_UNSIGNED = 0b110, + // 0b111 is reserved + }; -#undef INSN + static constexpr uint8_t OP_LOAD_MAJOR = 0b0000011; + static constexpr uint8_t OP_FP_LOAD_MAJOR = 0b0000111; + + template + void load_base(uint8_t Rd, Register Rs, const int32_t offset) { + guarantee(is_simm12(offset), "offset is invalid."); + unsigned insn = 0; + int32_t val = offset & 0xfff; + patch((address)&insn, 6, 0, op_major); + patch((address)&insn, 11, 7, Rd); + patch((address)&insn, 14, 12, width); + patch_reg((address)&insn, 15, Rs); + patch((address)&insn, 31, 20, val); + emit(insn); + } + + template + void load_base(Register Rd, Register Rs, const int32_t offset) { + load_base(Rd->raw_encoding(), Rs, offset); + } + + template + void load_base(FloatRegister Rd, Register Rs, const int32_t offset) { + load_base(Rd->raw_encoding(), Rs, offset); + } + + public: + + void lb(Register Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } + + void _lbu(Register Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } + + void _lh(Register Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } + + void _lhu(Register Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } + + void _lw(Register Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } + + void lwu(Register Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } + + void _ld(Register Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } + + void flh(FloatRegister Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } + + void flw(FloatRegister Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } + + void _fld(FloatRegister Rd, Register Rs, const int32_t offset) { + load_base(Rd, Rs, offset); + } #define INSN(NAME, op, funct3) \ void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ @@ -724,30 +781,70 @@ class Assembler : public AbstractAssembler { #undef INSN -#define INSN(NAME, REGISTER, op, funct3) \ - void NAME(REGISTER Rs1, Register Rs2, const int32_t offset) { \ - guarantee(is_simm12(offset), "offset is invalid."); \ - unsigned insn = 0; \ - uint32_t val = offset & 0xfff; \ - uint32_t low = val & 0x1f; \ - uint32_t high = (val >> 5) & 0x7f; \ - patch((address)&insn, 6, 0, op); \ - patch((address)&insn, 14, 12, funct3); \ - patch_reg((address)&insn, 15, Rs2); \ - patch_reg((address)&insn, 20, Rs1); \ - patch((address)&insn, 11, 7, low); \ - patch((address)&insn, 31, 25, high); \ - emit(insn); \ - } \ + private: - INSN(_sb, Register, 0b0100011, 0b000); - INSN(_sh, Register, 0b0100011, 0b001); - INSN(_sw, Register, 0b0100011, 0b010); - INSN(_sd, Register, 0b0100011, 0b011); - INSN(fsw, FloatRegister, 0b0100111, 0b010); - INSN(_fsd, FloatRegister, 0b0100111, 0b011); + enum StoreWidthFunct3 : uint8_t { + STORE_WIDTH_BYTE = 0b000, + STORE_WIDTH_HALFWORD = 0b001, + STORE_WIDTH_WORD = 0b010, + STORE_WIDTH_DOUBLEWORD = 0b011, + // 0b100 to 0b111 are reserved for this opcode + }; -#undef INSN + static constexpr uint8_t OP_STORE_MAJOR = 0b0100011; + static constexpr uint8_t OP_FP_STORE_MAJOR = 0b0100111; + + template + void store_base(uint8_t Rs2, Register Rs1, const int32_t offset) { + guarantee(is_simm12(offset), "offset is invalid."); + unsigned insn = 0; + uint32_t val = offset & 0xfff; + uint32_t low = val & 0x1f; + uint32_t high = (val >> 5) & 0x7f; + patch((address)&insn, 6, 0, op_code); + patch((address)&insn, 11, 7, low); + patch((address)&insn, 14, 12, width); + patch_reg((address)&insn, 15, Rs1); + patch((address)&insn, 24, 20, Rs2); + patch((address)&insn, 31, 25, high); + emit(insn); + } + + template + void store_base(Register Rs2, Register Rs1, const int32_t offset) { + store_base(Rs2->raw_encoding(), Rs1, offset); + } + + template + void store_base(FloatRegister Rs2, Register Rs1, const int32_t offset) { + store_base(Rs2->raw_encoding(), Rs1, offset); + } + + public: + + void _sb(Register Rs2, Register Rs1, const int32_t offset) { + store_base(Rs2, Rs1, offset); + } + + void _sh(Register Rs2, Register Rs1, const int32_t offset) { + store_base(Rs2, Rs1, offset); + } + + void _sw(Register Rs2, Register Rs1, const int32_t offset) { + store_base(Rs2, Rs1, offset); + } + + void _sd(Register Rs2, Register Rs1, const int32_t offset) { + store_base(Rs2, Rs1, offset); + } + + void fsw(FloatRegister Rs2, Register Rs1, const int32_t offset) { + store_base(Rs2, Rs1, offset); + } + + void _fsd(FloatRegister Rs2, Register Rs1, const int32_t offset) { + store_base(Rs2, Rs1, offset); + } #define INSN(NAME, op, funct3) \ void NAME(Register Rd, const uint32_t csr, Register Rs1) { \ @@ -864,81 +961,239 @@ class Assembler : public AbstractAssembler { #undef INSN -enum Aqrl {relaxed = 0b00, rl = 0b01, aq = 0b10, aqrl = 0b11}; - -#define INSN(NAME, op, funct3, funct7) \ - void NAME(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { \ - unsigned insn = 0; \ - patch((address)&insn, 6, 0, op); \ - patch((address)&insn, 14, 12, funct3); \ - patch_reg((address)&insn, 7, Rd); \ - patch_reg((address)&insn, 15, Rs1); \ - patch_reg((address)&insn, 20, Rs2); \ - patch((address)&insn, 31, 27, funct7); \ - patch((address)&insn, 26, 25, memory_order); \ - emit(insn); \ - } - - INSN(amoswap_w, 0b0101111, 0b010, 0b00001); - INSN(amoadd_w, 0b0101111, 0b010, 0b00000); - INSN(amoxor_w, 0b0101111, 0b010, 0b00100); - INSN(amoand_w, 0b0101111, 0b010, 0b01100); - INSN(amoor_w, 0b0101111, 0b010, 0b01000); - INSN(amomin_w, 0b0101111, 0b010, 0b10000); - INSN(amomax_w, 0b0101111, 0b010, 0b10100); - INSN(amominu_w, 0b0101111, 0b010, 0b11000); - INSN(amomaxu_w, 0b0101111, 0b010, 0b11100); - INSN(amoswap_d, 0b0101111, 0b011, 0b00001); - INSN(amoadd_d, 0b0101111, 0b011, 0b00000); - INSN(amoxor_d, 0b0101111, 0b011, 0b00100); - INSN(amoand_d, 0b0101111, 0b011, 0b01100); - INSN(amoor_d, 0b0101111, 0b011, 0b01000); - INSN(amomin_d, 0b0101111, 0b011, 0b10000); - INSN(amomax_d , 0b0101111, 0b011, 0b10100); - INSN(amominu_d, 0b0101111, 0b011, 0b11000); - INSN(amomaxu_d, 0b0101111, 0b011, 0b11100); - INSN(amocas_w, 0b0101111, 0b010, 0b00101); - INSN(amocas_d, 0b0101111, 0b011, 0b00101); -#undef INSN - -enum operand_size { int8, int16, int32, uint32, int64 }; - -#define INSN(NAME, op, funct3, funct7) \ - void NAME(Register Rd, Register Rs1, Aqrl memory_order = relaxed) { \ - unsigned insn = 0; \ - uint32_t val = memory_order & 0x3; \ - patch((address)&insn, 6, 0, op); \ - patch((address)&insn, 14, 12, funct3); \ - patch_reg((address)&insn, 7, Rd); \ - patch_reg((address)&insn, 15, Rs1); \ - patch((address)&insn, 25, 20, 0b00000); \ - patch((address)&insn, 31, 27, funct7); \ - patch((address)&insn, 26, 25, val); \ - emit(insn); \ - } - - INSN(lr_w, 0b0101111, 0b010, 0b00010); - INSN(lr_d, 0b0101111, 0b011, 0b00010); - -#undef INSN - -#define INSN(NAME, op, funct3, funct7) \ - void NAME(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = relaxed) { \ - unsigned insn = 0; \ - uint32_t val = memory_order & 0x3; \ - patch((address)&insn, 6, 0, op); \ - patch((address)&insn, 14, 12, funct3); \ - patch_reg((address)&insn, 7, Rd); \ - patch_reg((address)&insn, 15, Rs2); \ - patch_reg((address)&insn, 20, Rs1); \ - patch((address)&insn, 31, 27, funct7); \ - patch((address)&insn, 26, 25, val); \ - emit(insn); \ + enum Aqrl {relaxed = 0b00, rl = 0b01, aq = 0b10, aqrl = 0b11}; + + private: + + enum AmoWidthFunct3 : uint8_t { + AMO_WIDTH_BYTE = 0b000, // Zabha extension + AMO_WIDTH_HALFWORD = 0b001, // Zabha extension + AMO_WIDTH_WORD = 0b010, + AMO_WIDTH_DOUBLEWORD = 0b011, + AMO_WIDTH_QUADWORD = 0b100, + // 0b101 to 0b111 are reserved + }; + + enum AmoOperationFunct5 : uint8_t { + AMO_ADD = 0b00000, + AMO_SWAP = 0b00001, + AMO_LR = 0b00010, + AMO_SC = 0b00011, + AMO_XOR = 0b00100, + AMO_OR = 0b01000, + AMO_AND = 0b01100, + AMO_MIN = 0b10000, + AMO_MAX = 0b10100, + AMO_MINU = 0b11000, + AMO_MAXU = 0b11100, + AMO_CAS = 0b00101 // Zacas + }; + + static constexpr uint32_t OP_AMO_MAJOR = 0b0101111; + + template + void amo_base(Register Rd, Register Rs1, uint8_t Rs2, Aqrl memory_order = aqrl) { + assert(width > AMO_WIDTH_HALFWORD || UseZabha, "Must be"); + assert(funct5 != AMO_CAS || UseZacas, "Must be"); + unsigned insn = 0; + patch((address)&insn, 6, 0, OP_AMO_MAJOR); + patch_reg((address)&insn, 7, Rd); + patch((address)&insn, 14, 12, width); + patch_reg((address)&insn, 15, Rs1); + patch((address)&insn, 24, 20, Rs2); + patch((address)&insn, 26, 25, memory_order); + patch((address)&insn, 31, 27, funct5); + emit(insn); } - INSN(sc_w, 0b0101111, 0b010, 0b00011); - INSN(sc_d, 0b0101111, 0b011, 0b00011); -#undef INSN + template + void amo_base(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2->raw_encoding(), memory_order); + } + + public: + + void amoadd_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoadd_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoadd_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoadd_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoswap_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoswap_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoswap_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoswap_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoxor_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoxor_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoxor_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoxor_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoor_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoor_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoor_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoor_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoand_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoand_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoand_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amoand_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomin_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomin_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomin_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomin_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amominu_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amominu_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amominu_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amominu_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomax_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomax_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomax_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomax_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomaxu_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomaxu_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomaxu_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amomaxu_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + protected: + + void lr_w(Register Rd, Register Rs1, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, 0, memory_order); + } + + void lr_d(Register Rd, Register Rs1, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, 0, memory_order); + } + + void sc_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void sc_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amocas_b(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amocas_h(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amocas_w(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + void amocas_d(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { + amo_base(Rd, Rs1, Rs2, memory_order); + } + + public: + + enum operand_size { int8, int16, int32, uint32, int64 }; // Immediate Instruction #define INSN(NAME, op, funct3) \ @@ -1345,29 +1600,6 @@ enum operand_size { int8, int16, int32, uint32, int64 }; fp_base(Rd, Rs1, 0b00000, 0b000); } - private: - static constexpr unsigned int OP_LOAD_FP = 0b0000111; - - template - void fp_load(FloatRegister Rd, Register Rs, const int32_t offset) { - guarantee(is_uimm3(FpWidth), "Rounding mode is out of validity"); - guarantee(is_simm12(offset), "offset is invalid."); - unsigned insn = 0; - uint32_t val = offset & 0xfff; - patch((address)&insn, 6, 0, OP_LOAD_FP); - patch_reg((address)&insn, 7, Rd); - patch((address)&insn, 14, 12, FpWidth); - patch_reg((address)&insn, 15, Rs); - patch((address)&insn, 31, 20, val); - emit(insn); - } - - public: - - void flh(FloatRegister Rd, Register Rs, const int32_t offset) { fp_load<0b001>(Rd, Rs, offset); } - void flw(FloatRegister Rd, Register Rs, const int32_t offset) { fp_load<0b010>(Rd, Rs, offset); } - void _fld(FloatRegister Rd, Register Rs, const int32_t offset) { fp_load<0b011>(Rd, Rs, offset); } - private: template void fp_fm(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm) { @@ -1904,8 +2136,14 @@ enum VectorMask { INSN(vand_vv, 0b1010111, 0b000, 0b001001); // Vector Single-Width Integer Add and Subtract - INSN(vsub_vv, 0b1010111, 0b000, 0b000010); INSN(vadd_vv, 0b1010111, 0b000, 0b000000); + INSN(vsub_vv, 0b1010111, 0b000, 0b000010); + + // Vector Saturating Integer Add and Subtract + INSN(vsadd_vv, 0b1010111, 0b000, 0b100001); + INSN(vsaddu_vv, 0b1010111, 0b000, 0b100000); + INSN(vssub_vv, 0b1010111, 0b000, 0b100011); + INSN(vssubu_vv, 0b1010111, 0b000, 0b100010); // Vector Register Gather Instructions INSN(vrgather_vv, 0b1010111, 0b000, 0b001100); @@ -2323,6 +2561,7 @@ enum Nf { } // Vector Bit-manipulation used in Cryptography (Zvbb) Extension + INSN(vandn_vx, 0b1010111, 0b100, 0b000001); INSN(vrol_vx, 0b1010111, 0b100, 0b010101); INSN(vror_vx, 0b1010111, 0b100, 0b010100); @@ -2509,17 +2748,17 @@ enum Nf { // wrappers such as 'add' which do the compressing work through 'c_add' depending on the // the operands of the instruction and availability of the RVC hardware extension. // -// 2. 'CompressibleRegion' and 'IncompressibleRegion' are introduced to mark assembler scopes +// 2. 'CompressibleScope' and 'IncompressibleScope' are introduced to mark assembler scopes // within which instructions are qualified or unqualified to be compressed into their 16-bit // versions. An example: // -// CompressibleRegion cr(_masm); +// CompressibleScope scope(_masm); // __ add(...); // this instruction will be compressed into 'c.add' when possible // { -// IncompressibleRegion ir(_masm); +// IncompressibleScope scope(_masm); // __ add(...); // this instruction will not be compressed // { -// CompressibleRegion cr(_masm); +// CompressibleScope scope(_masm); // __ add(...); // this instruction will be compressed into 'c.add' when possible // } // } @@ -2528,40 +2767,40 @@ enum Nf { // distinguish compressed 16-bit instructions from normal 32-bit ones. private: - bool _in_compressible_region; + bool _in_compressible_scope; public: - bool in_compressible_region() const { return _in_compressible_region; } - void set_in_compressible_region(bool b) { _in_compressible_region = b; } + bool in_compressible_scope() const { return _in_compressible_scope; } + void set_in_compressible_scope(bool b) { _in_compressible_scope = b; } public: - // an abstract compressible region - class AbstractCompressibleRegion : public StackObj { + // An abstract compressible scope + class AbstractCompressibleScope : public StackObj { protected: Assembler *_masm; - bool _saved_in_compressible_region; + bool _saved_in_compressible_scope; protected: - AbstractCompressibleRegion(Assembler *_masm) + AbstractCompressibleScope(Assembler *_masm) : _masm(_masm) - , _saved_in_compressible_region(_masm->in_compressible_region()) {} + , _saved_in_compressible_scope(_masm->in_compressible_scope()) {} }; - // a compressible region - class CompressibleRegion : public AbstractCompressibleRegion { + // A compressible scope + class CompressibleScope : public AbstractCompressibleScope { public: - CompressibleRegion(Assembler *_masm) : AbstractCompressibleRegion(_masm) { - _masm->set_in_compressible_region(true); + CompressibleScope(Assembler *_masm) : AbstractCompressibleScope(_masm) { + _masm->set_in_compressible_scope(true); } - ~CompressibleRegion() { - _masm->set_in_compressible_region(_saved_in_compressible_region); + ~CompressibleScope() { + _masm->set_in_compressible_scope(_saved_in_compressible_scope); } }; - // an incompressible region - class IncompressibleRegion : public AbstractCompressibleRegion { + // An incompressible scope + class IncompressibleScope : public AbstractCompressibleScope { public: - IncompressibleRegion(Assembler *_masm) : AbstractCompressibleRegion(_masm) { - _masm->set_in_compressible_region(false); + IncompressibleScope(Assembler *_masm) : AbstractCompressibleScope(_masm) { + _masm->set_in_compressible_scope(false); } - ~IncompressibleRegion() { - _masm->set_in_compressible_region(_saved_in_compressible_region); + ~IncompressibleScope() { + _masm->set_in_compressible_scope(_saved_in_compressible_scope); } }; @@ -2576,13 +2815,13 @@ enum Nf { template void relocate(RelocationHolder const& rspec, Callback emit_insts, int format = 0) { AbstractAssembler::relocate(rspec, format); - IncompressibleRegion ir(this); // relocations + IncompressibleScope scope(this); // relocations emit_insts(); } template void relocate(relocInfo::relocType rtype, Callback emit_insts, int format = 0) { AbstractAssembler::relocate(rtype, format); - IncompressibleRegion ir(this); // relocations + IncompressibleScope scope(this); // relocations emit_insts(); } @@ -3163,7 +3402,7 @@ enum Nf { public: bool do_compress() const { - return UseRVC && in_compressible_region(); + return UseRVC && in_compressible_scope(); } bool do_compress_zcb(Register reg1 = noreg, Register reg2 = noreg) const { @@ -3178,125 +3417,95 @@ enum Nf { // -------------------------- // Load/store register // -------------------------- -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - /* lw -> c.lwsp/c.lw */ \ - if (do_compress()) { \ - if (is_c_lwswsp(Rs, Rd, offset, true)) { \ - c_lwsp(Rd, offset); \ - return; \ - } else if (is_c_lwsw(Rs, Rd, offset)) { \ - c_lw(Rd, Rs, offset); \ - return; \ - } \ - } \ - _lw(Rd, Rs, offset); \ + void lw(Register Rd, Register Rs, const int32_t offset) { + /* lw -> c.lwsp/c.lw */ + if (do_compress()) { + if (is_c_lwswsp(Rs, Rd, offset, true)) { + c_lwsp(Rd, offset); + return; + } else if (is_c_lwsw(Rs, Rd, offset)) { + c_lw(Rd, Rs, offset); + return; + } + } + _lw(Rd, Rs, offset); } - INSN(lw); - -#undef INSN - // -------------------------- -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - /* ld -> c.ldsp/c.ld */ \ - if (do_compress()) { \ - if (is_c_ldsdsp(Rs, Rd, offset, true)) { \ - c_ldsp(Rd, offset); \ - return; \ - } else if (is_c_ldsd(Rs, Rd, offset)) { \ - c_ld(Rd, Rs, offset); \ - return; \ - } \ - } \ - _ld(Rd, Rs, offset); \ + void ld(Register Rd, Register Rs, const int32_t offset) { + /* ld -> c.ldsp/c.ld */ + if (do_compress()) { + if (is_c_ldsdsp(Rs, Rd, offset, true)) { + c_ldsp(Rd, offset); + return; + } else if (is_c_ldsd(Rs, Rd, offset)) { + c_ld(Rd, Rs, offset); + return; + } + } + _ld(Rd, Rs, offset); } - INSN(ld); - -#undef INSN - // -------------------------- -#define INSN(NAME) \ - void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - /* fld -> c.fldsp/c.fld */ \ - if (do_compress()) { \ - if (is_c_fldsdsp(Rs, offset)) { \ - c_fldsp(Rd, offset); \ - return; \ - } else if (is_c_fldsd(Rs, Rd, offset)) { \ - c_fld(Rd, Rs, offset); \ - return; \ - } \ - } \ - _fld(Rd, Rs, offset); \ + void fld(FloatRegister Rd, Register Rs, const int32_t offset) { + /* fld -> c.fldsp/c.fld */ + if (do_compress()) { + if (is_c_fldsdsp(Rs, offset)) { + c_fldsp(Rd, offset); + return; + } else if (is_c_fldsd(Rs, Rd, offset)) { + c_fld(Rd, Rs, offset); + return; + } + } + _fld(Rd, Rs, offset); } - INSN(fld); - -#undef INSN - // -------------------------- -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - /* sd -> c.sdsp/c.sd */ \ - if (do_compress()) { \ - if (is_c_ldsdsp(Rs, Rd, offset, false)) { \ - c_sdsp(Rd, offset); \ - return; \ - } else if (is_c_ldsd(Rs, Rd, offset)) { \ - c_sd(Rd, Rs, offset); \ - return; \ - } \ - } \ - _sd(Rd, Rs, offset); \ + void sd(Register Rs2, Register Rs1, const int32_t offset) { + /* sd -> c.sdsp/c.sd */ + if (do_compress()) { + if (is_c_ldsdsp(Rs1, Rs2, offset, false)) { + c_sdsp(Rs2, offset); + return; + } else if (is_c_ldsd(Rs1, Rs2, offset)) { + c_sd(Rs2, Rs1, offset); + return; + } + } + _sd(Rs2, Rs1, offset); } - INSN(sd); - -#undef INSN - // -------------------------- -#define INSN(NAME) \ - void NAME(Register Rd, Register Rs, const int32_t offset) { \ - /* sw -> c.swsp/c.sw */ \ - if (do_compress()) { \ - if (is_c_lwswsp(Rs, Rd, offset, false)) { \ - c_swsp(Rd, offset); \ - return; \ - } else if (is_c_lwsw(Rs, Rd, offset)) { \ - c_sw(Rd, Rs, offset); \ - return; \ - } \ - } \ - _sw(Rd, Rs, offset); \ + void sw(Register Rs2, Register Rs1, const int32_t offset) { + /* sw -> c.swsp/c.sw */ + if (do_compress()) { + if (is_c_lwswsp(Rs1, Rs2, offset, false)) { + c_swsp(Rs2, offset); + return; + } else if (is_c_lwsw(Rs1, Rs2, offset)) { + c_sw(Rs2, Rs1, offset); + return; + } + } + _sw(Rs2, Rs1, offset); } - INSN(sw); - -#undef INSN - // -------------------------- -#define INSN(NAME) \ - void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ - /* fsd -> c.fsdsp/c.fsd */ \ - if (do_compress()) { \ - if (is_c_fldsdsp(Rs, offset)) { \ - c_fsdsp(Rd, offset); \ - return; \ - } else if (is_c_fldsd(Rs, Rd, offset)) { \ - c_fsd(Rd, Rs, offset); \ - return; \ - } \ - } \ - _fsd(Rd, Rs, offset); \ + void fsd(FloatRegister Rs2, Register Rs1, const int32_t offset) { + /* fsd -> c.fsdsp/c.fsd */ + if (do_compress()) { + if (is_c_fldsdsp(Rs1, offset)) { + c_fsdsp(Rs2, offset); + return; + } else if (is_c_fldsd(Rs1, Rs2, offset)) { + c_fsd(Rs2, Rs1, offset); + return; + } + } + _fsd(Rs2, Rs1, offset); } - INSN(fsd); - -#undef INSN - // -------------------------- // Unconditional branch instructions // -------------------------- @@ -3817,7 +4026,7 @@ enum Nf { static const unsigned long branch_range = 1 * M; static bool reachable_from_branch_at(address branch, address target) { - return uabs(target - branch) < branch_range; + return g_uabs(target - branch) < branch_range; } // Decode the given instruction, checking if it's a 16-bit compressed @@ -3831,7 +4040,7 @@ enum Nf { } } - Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_region(true) {} + Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_scope(true) {} }; #endif // CPU_RISCV_ASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp index d55521823ec..ea299181ca7 100644 --- a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp @@ -70,7 +70,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } @@ -92,7 +92,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ rt_call(Runtime1::entry_for(stub_id), ra); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { @@ -105,7 +105,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void DivByZeroStub::emit_code(LIR_Assembler* ce) { @@ -258,7 +258,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { __ far_call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { @@ -272,7 +272,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { } __ far_call(RuntimeAddress(Runtime1::entry_for(_stub))); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void ArrayCopyStub::emit_code(LIR_Assembler* ce) { diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp index 76089e8dd45..32b99f56909 100644 --- a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -61,16 +61,17 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj); - lbu(hdr, Address(hdr, Klass::misc_flags_offset())); - test_bit(temp, hdr, exact_log2(KlassFlags::_misc_is_value_based_class)); - bnez(temp, slow_case, true /* is_far */); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(disp_hdr, obj, hdr, temp, t1, slow_case); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(hdr, obj); + lbu(hdr, Address(hdr, Klass::misc_flags_offset())); + test_bit(temp, hdr, exact_log2(KlassFlags::_misc_is_value_based_class)); + bnez(temp, slow_case, /* is_far */ true); + } + Label done; // Load object header ld(hdr, Address(obj, hdr_offset)); @@ -348,7 +349,7 @@ void C1_MacroAssembler::verified_entry(bool breakAtEntry) { // first instruction with a jump. For this action to be legal we // must ensure that this first instruction is a J, JAL or NOP. // Make it a NOP. - IncompressibleRegion ir(this); // keep the nop as 4 bytes for patching. + IncompressibleScope scope(this); // keep the nop as 4 bytes for patching. assert_alignment(pc()); nop(); // 4 bytes } diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 99cbcedb8ff..77b4e26cc92 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -289,7 +289,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Label slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. sd(zr, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); } @@ -2156,6 +2156,36 @@ void C2_MacroAssembler::enc_cmove(int cmpFlag, Register op1, Register op2, Regis } } +void C2_MacroAssembler::enc_cmove_cmp_fp(int cmpFlag, FloatRegister op1, FloatRegister op2, Register dst, Register src, bool is_single) { + int op_select = cmpFlag & (~unsigned_branch_mask); + + switch (op_select) { + case BoolTest::eq: + cmov_cmp_fp_eq(op1, op2, dst, src, is_single); + break; + case BoolTest::ne: + cmov_cmp_fp_ne(op1, op2, dst, src, is_single); + break; + case BoolTest::le: + cmov_cmp_fp_le(op1, op2, dst, src, is_single); + break; + case BoolTest::ge: + assert(false, "Should go to BoolTest::le case"); + ShouldNotReachHere(); + break; + case BoolTest::lt: + cmov_cmp_fp_lt(op1, op2, dst, src, is_single); + break; + case BoolTest::gt: + assert(false, "Should go to BoolTest::lt case"); + ShouldNotReachHere(); + break; + default: + assert(false, "unsupported compare condition"); + ShouldNotReachHere(); + } +} + // Set dst to NaN if any NaN input. void C2_MacroAssembler::minmax_fp(FloatRegister dst, FloatRegister src1, FloatRegister src2, FLOAT_TYPE ft, bool is_min) { @@ -3080,7 +3110,9 @@ void C2_MacroAssembler::compare_integral_v(VectorRegister vd, VectorRegister src assert(is_integral_type(bt), "unsupported element type"); assert(vm == Assembler::v0_t ? vd != v0 : true, "should be different registers"); vsetvli_helper(bt, vector_length); - vmclr_m(vd); + if (vm == Assembler::v0_t) { + vmclr_m(vd); + } switch (cond) { case BoolTest::eq: vmseq_vv(vd, src1, src2, vm); break; case BoolTest::ne: vmsne_vv(vd, src1, src2, vm); break; @@ -3103,7 +3135,9 @@ void C2_MacroAssembler::compare_fp_v(VectorRegister vd, VectorRegister src1, Vec assert(is_floating_point_type(bt), "unsupported element type"); assert(vm == Assembler::v0_t ? vd != v0 : true, "should be different registers"); vsetvli_helper(bt, vector_length); - vmclr_m(vd); + if (vm == Assembler::v0_t) { + vmclr_m(vd); + } switch (cond) { case BoolTest::eq: vmfeq_vv(vd, src1, src2, vm); break; case BoolTest::ne: vmfne_vv(vd, src1, src2, vm); break; diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index a650174d90f..73fceea3805 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -129,6 +129,10 @@ Register op1, Register op2, Register dst, Register src); + void enc_cmove_cmp_fp(int cmpFlag, + FloatRegister op1, FloatRegister op2, + Register dst, Register src, bool is_single); + void spill(Register r, bool is64, int offset) { is64 ? sd(r, Address(sp, offset)) : sw(r, Address(sp, offset)); diff --git a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp index de3c1b17c8e..79bdc4917c9 100644 --- a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp @@ -43,7 +43,7 @@ define_pd_global(bool, TieredCompilation, COMPILER1_PRESENT(true) NOT define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, OnStackReplacePercentage, 140); -define_pd_global(intx, ConditionalMoveLimit, 0); +define_pd_global(intx, ConditionalMoveLimit, 3); define_pd_global(intx, FreqInlineSize, 325); define_pd_global(intx, MinJumpTableSize, 10); define_pd_global(intx, InteriorEntryAlignment, 16); diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp index 8ee6d11dcaf..e77375434c2 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.cpp +++ b/src/hotspot/cpu/riscv/frame_riscv.cpp @@ -670,7 +670,6 @@ void JavaFrameAnchor::make_walkable() { // already walkable? if (walkable()) { return; } vmassert(last_Java_sp() != nullptr, "not called from Java code?"); - vmassert(last_Java_pc() == nullptr, "already walkable"); _last_Java_pc = (address)_last_Java_sp[-1]; vmassert(walkable(), "something went wrong"); } diff --git a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp index 2e79c89e7b0..fb31760e20b 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp @@ -35,6 +35,53 @@ // Inline functions for RISCV frames: +#if INCLUDE_JFR + +// Static helper routines + +inline address frame::interpreter_bcp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (fp[frame::interpreter_frame_bcp_offset]); +} + +inline address frame::interpreter_return_address(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (fp[frame::return_addr_offset]); +} + +inline intptr_t* frame::interpreter_sender_sp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(fp[frame::interpreter_frame_sender_sp_offset]); +} + +inline bool frame::is_interpreter_frame_setup_at(const intptr_t* fp, const void* sp) { + assert(fp != nullptr, "invariant"); + assert(sp != nullptr, "invariant"); + return sp <= fp + frame::interpreter_frame_initial_sp_offset; +} + +inline intptr_t* frame::sender_sp(intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return fp + frame::sender_sp_offset; +} + +inline intptr_t* frame::link(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(fp[frame::link_offset]); +} + +inline address frame::return_address(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast
          (sp[-1]); +} + +inline intptr_t* frame::fp(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast(sp[-2]); +} + +#endif // INCLUDE_JFR + // Constructors: inline frame::frame() { diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index 5b3c926cfa9..7e9bea381a5 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -226,7 +226,7 @@ void BarrierSetAssembler::clear_patching_epoch() { void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slow_path, Label* continuation, Label* guard) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); - Assembler::IncompressibleRegion ir(masm); // Fixed length: see entry_barrier_offset() + Assembler::IncompressibleScope scope(masm); // Fixed length: see entry_barrier_offset() Label local_guard; NMethodPatchingType patching_type = nmethod_patching_type(); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp index 39da77181c6..f24e4f789bc 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -31,8 +31,8 @@ #include "memory/resourceArea.hpp" #include "runtime/frame.inline.hpp" #include "runtime/javaThread.hpp" -#include "runtime/sharedRuntime.hpp" #include "runtime/registerMap.hpp" +#include "runtime/sharedRuntime.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" #if INCLUDE_JVMCI diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp index 2a96bd32cf8..11c4e5dc81b 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp @@ -26,9 +26,9 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" -#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #define __ masm->masm()-> diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp index 3021351cca8..4c1056e75a5 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp @@ -23,6 +23,8 @@ * */ +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" @@ -30,10 +32,8 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" -#include "interpreter/interpreter.hpp" #include "interpreter/interp_masm.hpp" +#include "interpreter/interpreter.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" #ifdef COMPILER1 diff --git a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp index 1f2f0146f04..9df0a431c45 100644 --- a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp @@ -22,8 +22,8 @@ * questions. */ -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zAddress.hpp" #include "gc/z/zBarrierSetAssembler.hpp" #include "gc/z/zGlobals.hpp" @@ -36,9 +36,11 @@ #include #endif // LINUX -// Default value if probe is not implemented for a certain platform: 128TB -static const size_t DEFAULT_MAX_ADDRESS_BIT = 47; -// Minimum value returned, if probing fails: 64GB +// Default value if probing is not implemented for a certain platform +// Max address bit is restricted by implicit assumptions in the code, for instance +// the bit layout of ZForwardingEntry or Partial array entry (see ZMarkStackEntry) in mark stack +static const size_t DEFAULT_MAX_ADDRESS_BIT = 46; +// Minimum value returned, if probing fail static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; static size_t probe_valid_max_address_bit() { diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index 3ef084d30fc..d67e05bbb6d 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -107,6 +107,7 @@ define_pd_global(intx, InlineSmallCode, 1000); product(bool, UseZfh, false, DIAGNOSTIC, "Use Zfh instructions") \ product(bool, UseZfhmin, false, DIAGNOSTIC, "Use Zfhmin instructions") \ product(bool, UseZacas, false, EXPERIMENTAL, "Use Zacas instructions") \ + product(bool, UseZabha, false, EXPERIMENTAL, "Use UseZabha instructions") \ product(bool, UseZcb, false, EXPERIMENTAL, "Use Zcb instructions") \ product(bool, UseZic64b, false, EXPERIMENTAL, "Use Zic64b instructions") \ product(bool, UseZicbom, false, EXPERIMENTAL, "Use Zicbom instructions") \ diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp index f1f9414d98a..fae34a9c770 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -497,9 +497,10 @@ void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { // remove activation // -// Apply stack watermark barrier. // Unlock the receiver if this is a synchronized method. // Unlock any Java monitors from synchronized blocks. +// Apply stack watermark barrier. +// Notify JVMTI. // Remove the activation from the stack. // // If there are locked Java monitors @@ -509,32 +510,14 @@ void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { // installs IllegalMonitorStateException // Else // no error processing -void InterpreterMacroAssembler::remove_activation( - TosState state, - bool throw_monitor_exception, - bool install_monitor_exception, - bool notify_jvmdi) { +void InterpreterMacroAssembler::remove_activation(TosState state, + bool throw_monitor_exception, + bool install_monitor_exception, + bool notify_jvmdi) { // Note: Registers x13 may be in use for the // result check if synchronized method Label unlocked, unlock, no_unlock; - // The below poll is for the stack watermark barrier. It allows fixing up frames lazily, - // that would normally not be safe to use. Such bad returns into unsafe territory of - // the stack, will call InterpreterRuntime::at_unwind. - Label slow_path; - Label fast_path; - safepoint_poll(slow_path, true /* at_return */, false /* acquire */, false /* in_nmethod */); - j(fast_path); - - bind(slow_path); - push(state); - set_last_Java_frame(esp, fp, (address)pc(), t0); - super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), xthread); - reset_last_Java_frame(true); - pop(state); - - bind(fast_path); - // get the value of _do_not_unlock_if_synchronized into x13 const Address do_not_unlock_if_synchronized(xthread, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); @@ -655,10 +638,27 @@ void InterpreterMacroAssembler::remove_activation( bind(no_unlock); - // jvmti support - if (notify_jvmdi) { - notify_method_exit(state, NotifyJVMTI); // preserve TOSCA + JFR_ONLY(enter_jfr_critical_section();) + + // The below poll is for the stack watermark barrier. It allows fixing up frames lazily, + // that would normally not be safe to use. Such bad returns into unsafe territory of + // the stack, will call InterpreterRuntime::at_unwind. + Label slow_path; + Label fast_path; + safepoint_poll(slow_path, true /* at_return */, false /* acquire */, false /* in_nmethod */); + j(fast_path); + + bind(slow_path); + push(state); + set_last_Java_frame(esp, fp, pc(), t0); + super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), xthread); + reset_last_Java_frame(true); + pop(state); + bind(fast_path); + // JVMTI support. Make sure the safepoint poll test is issued prior. + if (notify_jvmdi) { + notify_method_exit(state, NotifyJVMTI); // preserve TOSCA } else { notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA } @@ -677,9 +677,13 @@ void InterpreterMacroAssembler::remove_activation( subw(t0, t0, StackOverflow::stack_guard_enabled); beqz(t0, no_reserved_zone_enabling); + // look for an overflow into the stack reserved zone, i.e. + // interpreter_frame_sender_sp <= JavaThread::reserved_stack_activation ld(t0, Address(xthread, JavaThread::reserved_stack_activation_offset())); ble(t1, t0, no_reserved_zone_enabling); + JFR_ONLY(leave_jfr_critical_section();) + call_VM_leaf( CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), xthread); call_VM(noreg, CAST_FROM_FN_PTR(address, @@ -689,11 +693,14 @@ void InterpreterMacroAssembler::remove_activation( bind(no_reserved_zone_enabling); } + // remove frame anchor + leave(); + + JFR_ONLY(leave_jfr_critical_section();) + // restore sender esp mv(esp, t1); - // remove frame anchor - leave(); // If we're returning to interpreted code we will shortly be // adjusting SP to allow some space for ESP. If we're returning to // compiled code the saved sender SP was saved in sender_sp, so this @@ -701,6 +708,19 @@ void InterpreterMacroAssembler::remove_activation( andi(sp, esp, -16); } +#if INCLUDE_JFR +void InterpreterMacroAssembler::enter_jfr_critical_section() { + const Address sampling_critical_section(xthread, in_bytes(SAMPLING_CRITICAL_SECTION_OFFSET_JFR)); + mv(t0, true); + sb(t0, sampling_critical_section); +} + +void InterpreterMacroAssembler::leave_jfr_critical_section() { + const Address sampling_critical_section(xthread, in_bytes(SAMPLING_CRITICAL_SECTION_OFFSET_JFR)); + sb(zr, sampling_critical_section); +} +#endif // INCLUDE_JFR + // Lock object // // Args: @@ -736,17 +756,18 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) // Load object pointer into obj_reg c_rarg3 ld(obj_reg, Address(lock_reg, obj_offset)); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, obj_reg); - lbu(tmp, Address(tmp, Klass::misc_flags_offset())); - test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); - bnez(tmp, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(lock_reg, obj_reg, tmp, tmp2, tmp3, slow_case); j(done); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, obj_reg); + lbu(tmp, Address(tmp, Klass::misc_flags_offset())); + test_bit(tmp, tmp, exact_log2(KlassFlags::_misc_is_value_based_class)); + bnez(tmp, slow_case); + } + // Load (object->mark() | 1) into swap_reg ld(t0, Address(obj_reg, oopDesc::mark_offset_in_bytes())); ori(swap_reg, t0, 1); @@ -934,47 +955,29 @@ void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - int constant, - bool decrement) { - increment_mdp_data_at(mdp_in, noreg, constant, decrement); + int constant) { + increment_mdp_data_at(mdp_in, noreg, constant); } void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - Register reg, - int constant, - bool decrement) { + Register index, + int constant) { assert(ProfileInterpreter, "must be profiling interpreter"); - // %%% this does 64bit counters at best it is wasting space - // at worst it is a rare bug when counters overflow - assert_different_registers(t1, t0, mdp_in, reg); + assert_different_registers(t1, t0, mdp_in, index); Address addr1(mdp_in, constant); Address addr2(t1, 0); Address &addr = addr1; - if (reg != noreg) { + if (index != noreg) { la(t1, addr1); - add(t1, t1, reg); + add(t1, t1, index); addr = addr2; } - if (decrement) { - ld(t0, addr); - subi(t0, t0, DataLayout::counter_increment); - Label L; - bltz(t0, L); // skip store if counter underflow - sd(t0, addr); - bind(L); - } else { - assert(DataLayout::counter_increment == 1, - "flow-free idiom only works with 1"); - ld(t0, addr); - addi(t0, t0, DataLayout::counter_increment); - Label L; - blez(t0, L); // skip store if counter overflow - sd(t0, addr); - bind(L); - } + ld(t0, addr); + addi(t0, t0, DataLayout::counter_increment); + sd(t0, addr); } void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, @@ -1514,7 +1517,7 @@ void InterpreterMacroAssembler::call_VM_leaf_base(address entry_point, int number_of_arguments) { // interpreter specific // - // Note: No need to save/restore rbcp & rlocals pointer since these + // Note: No need to save/restore xbcp & xlocals pointer since these // are callee saved registers and no blocking/ GC can happen // in leaf calls. #ifdef ASSERT diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp index b94140ea990..891db16b243 100644 --- a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp @@ -233,11 +233,8 @@ class InterpreterMacroAssembler: public MacroAssembler { void verify_method_data_pointer(); void set_mdp_data_at(Register mdp_in, int constant, Register value); - void increment_mdp_data_at(Address data, bool decrement = false); - void increment_mdp_data_at(Register mdp_in, int constant, - bool decrement = false); - void increment_mdp_data_at(Register mdp_in, Register reg, int constant, - bool decrement = false); + void increment_mdp_data_at(Register mdp_in, int constant); + void increment_mdp_data_at(Register mdp_in, Register index, int constant); void increment_mask_and_jump(Address counter_addr, int increment, Address mask, Register tmp1, Register tmp2, @@ -290,6 +287,9 @@ class InterpreterMacroAssembler: public MacroAssembler { void notify_method_entry(); void notify_method_exit(TosState state, NotifyMethodExitMode mode); + JFR_ONLY(void enter_jfr_critical_section();) + JFR_ONLY(void leave_jfr_critical_section();) + virtual void _call_Unimplemented(address call_site) { save_bcp(); set_last_Java_frame(esp, fp, (address) pc(), t0); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b5c311c341d..c755d9ae23d 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -256,7 +256,7 @@ void MacroAssembler::dec_held_monitor_count(Register tmp) { } int MacroAssembler::align(int modulus, int extra_offset) { - CompressibleRegion cr(this); + CompressibleScope scope(this); intptr_t before = offset(); while ((offset() + extra_offset) % modulus != 0) { nop(); } return (int)(offset() - before); @@ -417,7 +417,7 @@ void MacroAssembler::set_last_Java_frame(Register last_java_sp, set_last_Java_frame(last_java_sp, last_java_fp, target(L), tmp); } else { L.add_patch_at(code(), locator()); - IncompressibleRegion ir(this); // the label address will be patched back. + IncompressibleScope scope(this); // the label address will be patched back. set_last_Java_frame(last_java_sp, last_java_fp, pc() /* Patched later */, tmp); } } @@ -564,7 +564,7 @@ void MacroAssembler::_verify_oop(Register reg, const char* s, const char* file, // The length of the instruction sequence emitted should not depend // on the address of the char buffer so that the size of mach nodes for // scratch emit and normal emit matches. - IncompressibleRegion ir(this); // Fixed length + IncompressibleScope scope(this); // Fixed length movptr(t0, (address) b); } @@ -604,7 +604,7 @@ void MacroAssembler::_verify_oop_addr(Address addr, const char* s, const char* f // The length of the instruction sequence emitted should not depend // on the address of the char buffer so that the size of mach nodes for // scratch emit and normal emit matches. - IncompressibleRegion ir(this); // Fixed length + IncompressibleScope scope(this); // Fixed length movptr(t0, (address) b); } @@ -775,7 +775,7 @@ void MacroAssembler::unimplemented(const char* what) { } void MacroAssembler::emit_static_call_stub() { - IncompressibleRegion ir(this); // Fixed length: see CompiledDirectCall::to_interp_stub_size(). + IncompressibleScope scope(this); // Fixed length: see CompiledDirectCall::to_interp_stub_size(). // CompiledDirectCall::set_to_interpreted knows the // exact layout of this stub. @@ -907,7 +907,7 @@ void MacroAssembler::la(Register Rd, const Address &adr) { } void MacroAssembler::la(Register Rd, Label &label) { - IncompressibleRegion ir(this); // the label address may be patched back. + IncompressibleScope scope(this); // the label address may be patched back. wrap_label(Rd, label, &MacroAssembler::la); } @@ -971,7 +971,7 @@ void MacroAssembler::j(const address dest, Register temp) { int64_t distance = dest - pc(); // We can't patch C, i.e. if Label wasn't bound we need to patch this jump. - IncompressibleRegion ir(this); + IncompressibleScope scope(this); if (is_simm21(distance) && ((distance % 2) == 0)) { Assembler::jal(x0, distance); } else { @@ -1267,6 +1267,130 @@ void MacroAssembler::cmov_gtu(Register cmp1, Register cmp2, Register dst, Regist bind(no_set); } +// ----------- cmove, compare float ----------- + +// Move src to dst only if cmp1 == cmp2, +// otherwise leave dst unchanged, including the case where one of them is NaN. +// Clarification: +// java code : cmp1 != cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 eq cmp2), dst, src +void MacroAssembler::cmov_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) { + if (UseZicond) { + if (is_single) { + feq_s(t0, cmp1, cmp2); + } else { + feq_d(t0, cmp1, cmp2); + } + czero_nez(dst, dst, t0); + czero_eqz(t0 , src, t0); + orr(dst, dst, t0); + return; + } + Label no_set; + if (is_single) { + // jump if cmp1 != cmp2, including the case of NaN + // not jump (i.e. move src to dst) if cmp1 == cmp2 + float_bne(cmp1, cmp2, no_set); + } else { + double_bne(cmp1, cmp2, no_set); + } + mv(dst, src); + bind(no_set); +} + +// Keep dst unchanged only if cmp1 == cmp2, +// otherwise move src to dst, including the case where one of them is NaN. +// Clarification: +// java code : cmp1 == cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 ne cmp2), dst, src +void MacroAssembler::cmov_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) { + if (UseZicond) { + if (is_single) { + feq_s(t0, cmp1, cmp2); + } else { + feq_d(t0, cmp1, cmp2); + } + czero_eqz(dst, dst, t0); + czero_nez(t0 , src, t0); + orr(dst, dst, t0); + return; + } + Label no_set; + if (is_single) { + // jump if cmp1 == cmp2 + // not jump (i.e. move src to dst) if cmp1 != cmp2, including the case of NaN + float_beq(cmp1, cmp2, no_set); + } else { + double_beq(cmp1, cmp2, no_set); + } + mv(dst, src); + bind(no_set); +} + +// When cmp1 <= cmp2 or any of them is NaN then dst = src, otherwise, dst = dst +// Clarification +// scenario 1: +// java code : cmp2 < cmp1 ? dst : src +// transformed to : CMove dst, (cmp1 le cmp2), dst, src +// scenario 2: +// java code : cmp1 > cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 le cmp2), dst, src +void MacroAssembler::cmov_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) { + if (UseZicond) { + if (is_single) { + flt_s(t0, cmp2, cmp1); + } else { + flt_d(t0, cmp2, cmp1); + } + czero_eqz(dst, dst, t0); + czero_nez(t0 , src, t0); + orr(dst, dst, t0); + return; + } + Label no_set; + if (is_single) { + // jump if cmp1 > cmp2 + // not jump (i.e. move src to dst) if cmp1 <= cmp2 or either is NaN + float_bgt(cmp1, cmp2, no_set); + } else { + double_bgt(cmp1, cmp2, no_set); + } + mv(dst, src); + bind(no_set); +} + +// When cmp1 < cmp2 or any of them is NaN then dst = src, otherwise, dst = dst +// Clarification +// scenario 1: +// java code : cmp2 <= cmp1 ? dst : src +// transformed to : CMove dst, (cmp1 lt cmp2), dst, src +// scenario 2: +// java code : cmp1 >= cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 lt cmp2), dst, src +void MacroAssembler::cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single) { + if (UseZicond) { + if (is_single) { + fle_s(t0, cmp2, cmp1); + } else { + fle_d(t0, cmp2, cmp1); + } + czero_eqz(dst, dst, t0); + czero_nez(t0 , src, t0); + orr(dst, dst, t0); + return; + } + Label no_set; + if (is_single) { + // jump if cmp1 >= cmp2 + // not jump (i.e. move src to dst) if cmp1 < cmp2 or either is NaN + float_bge(cmp1, cmp2, no_set); + } else { + double_bge(cmp1, cmp2, no_set); + } + mv(dst, src); + bind(no_set); +} + // Float compare branch instructions #define INSN(NAME, FLOATCMP, BRANCH) \ @@ -1682,7 +1806,7 @@ void MacroAssembler::vector_update_crc32(Register crc, Register buf, Register le for (int i = 0; i < N; i++) { vmv_x_s(tmp2, vcrc); // in vmv_x_s, the value is sign-extended to SEW bits, but we need zero-extended here. - zext_w(tmp2, tmp2); + zext(tmp2, tmp2, 32); vslidedown_vi(vcrc, vcrc, 1); xorr(crc, crc, tmp2); for (int j = 0; j < W; j++) { @@ -3615,16 +3739,16 @@ void MacroAssembler::check_klass_subtype(Register sub_klass, bind(L_failure); } -void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool acquire, bool in_nmethod) { - ld(t0, Address(xthread, JavaThread::polling_word_offset())); +void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool acquire, bool in_nmethod, Register tmp_reg) { + ld(tmp_reg, Address(xthread, JavaThread::polling_word_offset())); if (acquire) { membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); } if (at_return) { - bgtu(in_nmethod ? sp : fp, t0, slow_path, /* is_far */ true); + bgtu(in_nmethod ? sp : fp, tmp_reg, slow_path, /* is_far */ true); } else { - test_bit(t0, t0, exact_log2(SafepointMechanism::poll_bit())); - bnez(t0, slow_path, true /* is_far */); + test_bit(tmp_reg, tmp_reg, exact_log2(SafepointMechanism::poll_bit())); + bnez(tmp_reg, slow_path, /* is_far */ true); } } @@ -3674,7 +3798,7 @@ void MacroAssembler::cmpxchg_obj_header(Register oldv, Register newv, Register o void MacroAssembler::load_reserved(Register dst, Register addr, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl acquire) { switch (size) { case int64: @@ -3695,15 +3819,15 @@ void MacroAssembler::load_reserved(Register dst, void MacroAssembler::store_conditional(Register dst, Register new_val, Register addr, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl release) { switch (size) { case int64: - sc_d(dst, new_val, addr, release); + sc_d(dst, addr, new_val, release); break; case int32: case uint32: - sc_w(dst, new_val, addr, release); + sc_w(dst, addr, new_val, release); break; default: ShouldNotReachHere(); @@ -3712,7 +3836,7 @@ void MacroAssembler::store_conditional(Register dst, void MacroAssembler::cmpxchg_narrow_value_helper(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Register shift, Register mask, Register aligned_addr) { assert(size == int8 || size == int16, "unsupported operand size"); @@ -3742,10 +3866,11 @@ void MacroAssembler::cmpxchg_narrow_value_helper(Register addr, Register expecte // which are forced to work with 4-byte aligned address. void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release, Register result, bool result_as_bool, Register tmp1, Register tmp2, Register tmp3) { + assert(!(UseZacas && UseZabha), "Use amocas"); assert_different_registers(addr, expected, new_val, result, tmp1, tmp2, tmp3, t0, t1); Register scratch0 = t0, aligned_addr = t1; @@ -3778,13 +3903,13 @@ void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected, notr(scratch1, mask); bind(retry); - lr_w(result, aligned_addr, acquire); + load_reserved(result, aligned_addr, operand_size::int32, acquire); andr(scratch0, result, mask); bne(scratch0, expected, fail); andr(scratch0, result, scratch1); // scratch1 is ~mask orr(scratch0, scratch0, new_val); - sc_w(scratch0, scratch0, aligned_addr, release); + store_conditional(scratch0, scratch0, aligned_addr, operand_size::int32, release); bnez(scratch0, retry); } @@ -3816,10 +3941,11 @@ void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected, // failed. void MacroAssembler::weak_cmpxchg_narrow_value(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release, Register result, Register tmp1, Register tmp2, Register tmp3) { + assert(!(UseZacas && UseZabha), "Use amocas"); assert_different_registers(addr, expected, new_val, result, tmp1, tmp2, tmp3, t0, t1); Register scratch0 = t0, aligned_addr = t1; @@ -3850,13 +3976,13 @@ void MacroAssembler::weak_cmpxchg_narrow_value(Register addr, Register expected, } else { notr(scratch1, mask); - lr_w(result, aligned_addr, acquire); + load_reserved(result, aligned_addr, operand_size::int32, acquire); andr(scratch0, result, mask); bne(scratch0, expected, fail); andr(scratch0, result, scratch1); // scratch1 is ~mask orr(scratch0, scratch0, new_val); - sc_w(scratch0, scratch0, aligned_addr, release); + store_conditional(scratch0, scratch0, aligned_addr, operand_size::int32, release); bnez(scratch0, fail); } @@ -3873,10 +3999,10 @@ void MacroAssembler::weak_cmpxchg_narrow_value(Register addr, Register expected, void MacroAssembler::cmpxchg(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release, Register result, bool result_as_bool) { - assert(size != int8 && size != int16, "unsupported operand size"); + assert((UseZacas && UseZabha) || (size != int8 && size != int16), "unsupported operand size"); assert_different_registers(addr, t0); assert_different_registers(expected, t0); assert_different_registers(new_val, t0); @@ -3934,10 +4060,10 @@ void MacroAssembler::cmpxchg(Register addr, Register expected, void MacroAssembler::weak_cmpxchg(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release, Register result) { - + assert((UseZacas && UseZabha) || (size != int8 && size != int16), "unsupported operand size"); assert_different_registers(addr, t0); assert_different_registers(expected, t0); assert_different_registers(new_val, t0); @@ -4010,7 +4136,7 @@ ATOMIC_XCHGU(xchgalwu, xchgalw) #undef ATOMIC_XCHGU void MacroAssembler::atomic_cas(Register prev, Register newv, Register addr, - enum operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release) { + Assembler::operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release) { switch (size) { case int64: amocas_d(prev, addr, newv, (Assembler::Aqrl)(acquire | release)); @@ -4022,6 +4148,12 @@ void MacroAssembler::atomic_cas(Register prev, Register newv, Register addr, amocas_w(prev, addr, newv, (Assembler::Aqrl)(acquire | release)); zext(prev, prev, 32); break; + case int16: + amocas_h(prev, addr, newv, (Assembler::Aqrl)(acquire | release)); + break; + case int8: + amocas_b(prev, addr, newv, (Assembler::Aqrl)(acquire | release)); + break; default: ShouldNotReachHere(); } @@ -4853,7 +4985,7 @@ address MacroAssembler::reloc_call(Address entry, Register tmp) { address MacroAssembler::ic_call(address entry, jint method_index) { RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); - IncompressibleRegion ir(this); // relocations + IncompressibleScope scope(this); // relocations movptr(t0, (address)Universe::non_oop_word(), t1); assert_cond(entry != nullptr); return reloc_call(Address(entry, rh)); @@ -4866,7 +4998,7 @@ int MacroAssembler::ic_check_size() { } int MacroAssembler::ic_check(int end_alignment) { - IncompressibleRegion ir(this); + IncompressibleScope scope(this); Register receiver = j_rarg0; Register data = t0; @@ -5779,17 +5911,19 @@ void MacroAssembler::fill_words(Register base, Register cnt, Register value) { andi(t0, cnt, unroll - 1); sub(cnt, cnt, t0); - // align 8, so first sd n % 8 = mod, next loop sd 8 * n. shadd(base, t0, base, t1, 3); la(t1, entry); - slli(t0, t0, 2); // sd_inst_nums * 4; t0 is cnt % 8, so t1 = t1 - sd_inst_nums * 4, 4 is sizeof(inst) + slli(t0, t0, 2); sub(t1, t1, t0); jr(t1); bind(loop); addi(base, base, unroll * wordSize); - for (int i = -unroll; i < 0; i++) { - sd(value, Address(base, i * 8)); + { + IncompressibleScope scope(this); // Fixed length + for (int i = -unroll; i < 0; i++) { + sd(value, Address(base, i * 8)); + } } bind(entry); subi(cnt, cnt, unroll); @@ -5996,10 +6130,14 @@ void MacroAssembler::zero_memory(Register addr, Register len, Register tmp) { slli(t0, t0, 2); sub(t1, t1, t0); jr(t1); + bind(loop); sub(len, len, unroll); - for (int i = -unroll; i < 0; i++) { - sd(zr, Address(tmp, i * wordSize)); + { + IncompressibleScope scope(this); // Fixed length + for (int i = -unroll; i < 0; i++) { + sd(zr, Address(tmp, i * wordSize)); + } } bind(entry); add(tmp, tmp, unroll * wordSize); @@ -6362,10 +6500,17 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe ld(mark, Address(obj, oopDesc::mark_offset_in_bytes())); if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. sd(zr, Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes())))); } + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp1, obj); + lbu(tmp1, Address(tmp1, Klass::misc_flags_offset())); + test_bit(tmp1, tmp1, exact_log2(KlassFlags::_misc_is_value_based_class)); + bnez(tmp1, slow, /* is_far */ true); + } + // Check if the lock-stack is full. lwu(top, Address(xthread, JavaThread::lock_stack_top_offset())); mv(t, (unsigned)LockStack::end_offset()); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index b390fb236c2..7fa7f931044 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -44,7 +44,7 @@ class MacroAssembler: public Assembler { MacroAssembler(CodeBuffer* code) : Assembler(code) {} - void safepoint_poll(Label& slow_path, bool at_return, bool acquire, bool in_nmethod); + void safepoint_poll(Label& slow_path, bool at_return, bool acquire, bool in_nmethod, Register tmp_reg = t0); // Alignment int align(int modulus, int extra_offset = 0); @@ -657,11 +657,16 @@ class MacroAssembler: public Assembler { void cmov_gt(Register cmp1, Register cmp2, Register dst, Register src); void cmov_gtu(Register cmp1, Register cmp2, Register dst, Register src); + void cmov_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + void cmov_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + void cmov_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + void cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + public: // We try to follow risc-v asm menomics. // But as we don't layout a reachable GOT, // we often need to resort to movptr, li <48imm>. - // https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md + // https://github.com/riscv-non-isa/riscv-asm-manual/blob/main/src/asm-manual.adoc // Hotspot only use the standard calling convention using x1/ra. // The alternative calling convection using x5/t0 is not used. @@ -744,7 +749,7 @@ class MacroAssembler: public Assembler { guarantee(rtype == relocInfo::internal_word_type, \ "only internal_word_type relocs make sense here"); \ relocate(InternalAddress(dest).rspec()); \ - IncompressibleRegion ir(this); /* relocations */ + IncompressibleScope scope(this); /* relocations */ #define INSN(NAME) \ void NAME(Register Rs1, Register Rs2, const address dest) { \ @@ -965,7 +970,7 @@ class MacroAssembler: public Assembler { guarantee(rtype == relocInfo::internal_word_type, \ "only internal_word_type relocs make sense here"); \ relocate(InternalAddress(dest).rspec()); \ - IncompressibleRegion ir(this); /* relocations */ + IncompressibleScope scope(this); /* relocations */ #define INSN(NAME) \ void NAME(Register Rd, address dest) { \ @@ -1182,26 +1187,26 @@ class MacroAssembler: public Assembler { void cmpxchgptr(Register oldv, Register newv, Register addr, Register tmp, Label &succeed, Label *fail); void cmpxchg(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release, Register result, bool result_as_bool = false); void weak_cmpxchg(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release, Register result); void cmpxchg_narrow_value_helper(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Register shift, Register mask, Register aligned_addr); void cmpxchg_narrow_value(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release, Register result, bool result_as_bool, Register tmp1, Register tmp2, Register tmp3); void weak_cmpxchg_narrow_value(Register addr, Register expected, Register new_val, - enum operand_size size, + Assembler::operand_size size, Assembler::Aqrl acquire, Assembler::Aqrl release, Register result, Register tmp1, Register tmp2, Register tmp3); @@ -1218,7 +1223,7 @@ class MacroAssembler: public Assembler { void atomic_xchgwu(Register prev, Register newv, Register addr); void atomic_xchgalwu(Register prev, Register newv, Register addr); - void atomic_cas(Register prev, Register newv, Register addr, enum operand_size size, + void atomic_cas(Register prev, Register newv, Register addr, Assembler::operand_size size, Assembler::Aqrl acquire = Assembler::relaxed, Assembler::Aqrl release = Assembler::relaxed); // Emit a far call/jump. Only invalidates the tmp register which @@ -1631,8 +1636,8 @@ class MacroAssembler: public Assembler { int bitset_to_regs(unsigned int bitset, unsigned char* regs); Address add_memory_helper(const Address dst, Register tmp); - void load_reserved(Register dst, Register addr, enum operand_size size, Assembler::Aqrl acquire); - void store_conditional(Register dst, Register new_val, Register addr, enum operand_size size, Assembler::Aqrl release); + void load_reserved(Register dst, Register addr, Assembler::operand_size size, Assembler::Aqrl acquire); + void store_conditional(Register dst, Register new_val, Register addr, Assembler::operand_size size, Assembler::Aqrl release); public: void lightweight_lock(Register basic_lock, Register obj, Register tmp1, Register tmp2, Register tmp3, Label& slow); diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index 6f20d54b222..31947b520d0 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -479,7 +479,7 @@ void NativeJump::patch_verified_entry(address entry, address verified_entry, add void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { CodeBuffer cb(code_pos, instruction_size); MacroAssembler a(&cb); - Assembler::IncompressibleRegion ir(&a); // Fixed length: see NativeGeneralJump::get_instruction_size() + Assembler::IncompressibleScope scope(&a); // Fixed length: see NativeGeneralJump::get_instruction_size() int32_t offset = 0; a.movptr(t1, entry, offset, t0); // lui, lui, slli, add diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp index 295e92bbc1b..d8f5fa57816 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -300,7 +300,7 @@ class NativeGeneralJump: public NativeJump { inline NativeGeneralJump* nativeGeneralJump_at(address addr) { assert_cond(addr != nullptr); NativeGeneralJump* jump = (NativeGeneralJump*)(addr); - debug_only(jump->verify();) + DEBUG_ONLY(jump->verify();) return jump; } diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index aca2f4dd488..e838ee184fb 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1295,7 +1295,7 @@ uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { #endif void MachNopNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc*) const { - Assembler::CompressibleRegion cr(masm); // nops shall be 2-byte under RVC for alignment purposes. + Assembler::CompressibleScope scope(masm); // nops shall be 2-byte under RVC for alignment purposes. for (int i = 0; i < _count; i++) { __ nop(); } @@ -1371,7 +1371,7 @@ void MachPrologNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc *ra_) const { // insert a nop at the start of the prolog so we can patch in a // branch if we need to invalidate the method later { - Assembler::IncompressibleRegion ir(masm); // keep the nop as 4 bytes for patching. + Assembler::IncompressibleScope scope(masm); // keep the nop as 4 bytes for patching. MacroAssembler::assert_alignment(__ pc()); __ nop(); // 4 bytes } @@ -1596,7 +1596,8 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r __ unspill(as_VectorRegister(Matcher::_regEncode[dst_lo]), ra_->reg2offset(src_lo)); } else if (src_lo_rc == rc_vector && dst_lo_rc == rc_vector) { // vpr to vpr - __ vmv1r_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo])); + __ vsetvli_helper(T_BYTE, MaxVectorSize); + __ vmv_v_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo])); } else { ShouldNotReachHere(); } @@ -1614,7 +1615,8 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r __ unspill_vmask(as_VectorRegister(Matcher::_regEncode[dst_lo]), ra_->reg2offset(src_lo)); } else if (src_lo_rc == rc_vector && dst_lo_rc == rc_vector) { // vmask to vmask - __ vmv1r_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo])); + __ vsetvli_helper(T_BYTE, MaxVectorSize >> 3); + __ vmv_v_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo])); } else { ShouldNotReachHere(); } @@ -1752,7 +1754,7 @@ void BoxLockNode::format(PhaseRegAlloc *ra_, outputStream *st) const { #endif void BoxLockNode::emit(C2_MacroAssembler *masm, PhaseRegAlloc *ra_) const { - Assembler::IncompressibleRegion ir(masm); // Fixed length: see BoxLockNode::size() + Assembler::IncompressibleScope scope(masm); // Fixed length: see BoxLockNode::size() assert_cond(ra_ != nullptr); int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); @@ -1880,18 +1882,6 @@ bool Matcher::match_rule_supported(int opcode) { case Op_EncodeISOArray: return UseRVV; - // Current test shows that, it brings performance gain when MaxVectorSize >= 32, but brings - // regression when MaxVectorSize == 16. So only enable the intrinsic when MaxVectorSize >= 32. - case Op_RoundVF: - return UseRVV && MaxVectorSize >= 32; - - // For double, current test shows that even with MaxVectorSize == 32, there is still some regression. - // Although there is no hardware to verify it for now, from the trend of performance data on hardwares - // (with vlenb == 16 and 32 respectively), it's promising to bring better performance rather than - // regression for double when MaxVectorSize == 64+. So only enable the intrinsic when MaxVectorSize >= 64. - case Op_RoundVD: - return UseRVV && MaxVectorSize >= 64; - case Op_PopCountI: case Op_PopCountL: return UsePopCountInstruction; @@ -1914,8 +1904,6 @@ bool Matcher::match_rule_supported(int opcode) { case Op_FmaF: case Op_FmaD: - case Op_FmaVF: - case Op_FmaVD: return UseFMA; case Op_ConvHF2F: @@ -1930,9 +1918,15 @@ bool Matcher::match_rule_supported(int opcode) { case Op_MaxHF: case Op_MinHF: case Op_MulHF: - case Op_SubHF: case Op_SqrtHF: + case Op_SubHF: return UseZfh; + + case Op_CMoveF: + case Op_CMoveD: + case Op_CMoveP: + case Op_CMoveN: + return false; } return true; // Per default match rules are supported. @@ -1944,11 +1938,11 @@ const RegMask* Matcher::predicate_reg_mask(void) { // Vector calling convention not yet implemented. bool Matcher::supports_vector_calling_convention(void) { - return EnableVectorSupport && UseVectorStubs; + return EnableVectorSupport; } OptoRegPair Matcher::vector_return_value(uint ideal_reg) { - assert(EnableVectorSupport && UseVectorStubs, "sanity"); + assert(EnableVectorSupport, "sanity"); assert(ideal_reg == Op_VecA, "sanity"); // check more info at https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc int lo = V8_num; @@ -2310,42 +2304,6 @@ encode %{ } %} - enc_class riscv_enc_cmpxchgw(iRegINoSp res, memory mem, iRegI oldval, iRegI newval) %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, - /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - - enc_class riscv_enc_cmpxchgn(iRegINoSp res, memory mem, iRegI oldval, iRegI newval) %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, - /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - - enc_class riscv_enc_cmpxchg(iRegINoSp res, memory mem, iRegL oldval, iRegL newval) %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, - /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - - enc_class riscv_enc_cmpxchgw_acq(iRegINoSp res, memory mem, iRegI oldval, iRegI newval) %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, - /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - - enc_class riscv_enc_cmpxchgn_acq(iRegINoSp res, memory mem, iRegI oldval, iRegI newval) %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, - /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - - enc_class riscv_enc_cmpxchg_acq(iRegINoSp res, memory mem, iRegL oldval, iRegL newval) %{ - __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, - /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, - /*result as bool*/ true); - %} - // compare and branch instruction encodings enc_class riscv_enc_j(label lbl) %{ @@ -2395,7 +2353,7 @@ encode %{ %} enc_class riscv_enc_java_static_call(method meth) %{ - Assembler::IncompressibleRegion ir(masm); // Fixed length: see ret_addr_offset + Assembler::IncompressibleScope scope(masm); // Fixed length: see ret_addr_offset address addr = (address)$meth$$method; address call = nullptr; @@ -2442,7 +2400,7 @@ encode %{ %} enc_class riscv_enc_java_dynamic_call(method meth) %{ - Assembler::IncompressibleRegion ir(masm); // Fixed length: see ret_addr_offset + Assembler::IncompressibleScope scope(masm); // Fixed length: see ret_addr_offset int method_index = resolved_method_index(masm); address call = __ ic_call((address)$meth$$method, method_index); if (call == nullptr) { @@ -2461,7 +2419,7 @@ encode %{ %} enc_class riscv_enc_java_to_runtime(method meth) %{ - Assembler::IncompressibleRegion ir(masm); // Fixed length: see ret_addr_offset + Assembler::IncompressibleScope scope(masm); // Fixed length: see ret_addr_offset // Some calls to generated routines (arraycopy code) are scheduled by C2 // as runtime calls. if so we can call them using a far call (they will be @@ -5256,18 +5214,20 @@ instruct prefetchalloc( memory mem ) %{ // standard CompareAndSwapX when we are using barriers // these have higher priority than the rules selected by a predicate -instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct compareAndSwapB_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ + predicate(!UseZabha || !UseZacas); + match(Set res (CompareAndSwapB mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 10 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); format %{ "cmpxchg $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapB" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapB_narrow" %} ins_encode %{ @@ -5279,18 +5239,42 @@ instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R1 ins_pipe(pipe_slow); %} -instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ + predicate(UseZabha && UseZacas); + + match(Set res (CompareAndSwapB mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapB" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result as bool */); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapS_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +%{ + predicate(!UseZabha || !UseZacas); + match(Set res (CompareAndSwapS mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 11 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); format %{ "cmpxchg $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapS" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapS_narrow" %} ins_encode %{ @@ -5302,18 +5286,44 @@ instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R1 ins_pipe(pipe_slow); %} +instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + predicate(UseZabha && UseZacas); + + match(Set res (CompareAndSwapS mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapS" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result as bool */); + %} + + ins_pipe(pipe_slow); +%} + instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ match(Set res (CompareAndSwapI mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval\n\t" "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapI" %} - ins_encode(riscv_enc_cmpxchgw(res, mem, oldval, newval)); + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} ins_pipe(pipe_slow); %} @@ -5322,14 +5332,18 @@ instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval %{ match(Set res (CompareAndSwapL mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval\n\t" "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapL" %} - ins_encode(riscv_enc_cmpxchg(res, mem, oldval, newval)); + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} ins_pipe(pipe_slow); %} @@ -5340,14 +5354,18 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval match(Set res (CompareAndSwapP mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval\n\t" "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapP" %} - ins_encode(riscv_enc_cmpxchg(res, mem, oldval, newval)); + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} ins_pipe(pipe_slow); %} @@ -5355,35 +5373,40 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 8 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval\n\t" "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapN" %} - ins_encode(riscv_enc_cmpxchgn(res, mem, oldval, newval)); + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} ins_pipe(pipe_slow); %} // alternative CompareAndSwapX when we are eliding barriers -instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct compareAndSwapBAcq_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate((!UseZabha || !UseZacas) && needs_acquiring_load_reserved(n)); match(Set res (CompareAndSwapB mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 10 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapBAcq" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapBAcq_narrow" %} ins_encode %{ @@ -5395,20 +5418,42 @@ instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI ins_pipe(pipe_slow); %} -instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate((UseZabha && UseZacas) && needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndSwapB mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapBAcq" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result as bool */); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapSAcq_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +%{ + predicate((!UseZabha || !UseZacas) && needs_acquiring_load_reserved(n)); match(Set res (CompareAndSwapS mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 11 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval\n\t" - "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapSAcq" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapSAcq_narrow" %} ins_encode %{ @@ -5420,20 +5465,46 @@ instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI ins_pipe(pipe_slow); %} +instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + predicate((UseZabha && UseZacas) && needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndSwapS mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapSAcq" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result as bool */); + %} + + ins_pipe(pipe_slow); +%} + instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ predicate(needs_acquiring_load_reserved(n)); match(Set res (CompareAndSwapI mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval\n\t" "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapIAcq" %} - ins_encode(riscv_enc_cmpxchgw_acq(res, mem, oldval, newval)); + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} ins_pipe(pipe_slow); %} @@ -5444,14 +5515,18 @@ instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL new match(Set res (CompareAndSwapL mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval\n\t" "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapLAcq" %} - ins_encode(riscv_enc_cmpxchg_acq(res, mem, oldval, newval)); + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} ins_pipe(pipe_slow); %} @@ -5462,14 +5537,18 @@ instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP new match(Set res (CompareAndSwapP mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval\n\t" "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapPAcq" %} - ins_encode(riscv_enc_cmpxchg_acq(res, mem, oldval, newval)); + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} ins_pipe(pipe_slow); %} @@ -5480,14 +5559,18 @@ instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN new match(Set res (CompareAndSwapN mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + ALU_COST * 8 + BRANCH_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval\n\t" "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapNAcq" %} - ins_encode(riscv_enc_cmpxchgn_acq(res, mem, oldval, newval)); + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} ins_pipe(pipe_slow); %} @@ -5498,17 +5581,19 @@ instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN new // no trailing StoreLoad barrier emitted by C2. Unfortunately we // can't check the type of memory ordering here, so we always emit a // sc_d(w) with rl bit set. -instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct compareAndExchangeB_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ + predicate(!UseZabha || !UseZacas); + match(Set res (CompareAndExchangeB mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 5); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ - "cmpxchg $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeB" + "cmpxchg $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeB_narrow" %} ins_encode %{ @@ -5520,17 +5605,39 @@ instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI_R12 oldval, iReg ins_pipe(pipe_slow); %} -instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ + predicate(UseZabha && UseZacas); + + match(Set res (CompareAndExchangeB mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeB" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeS_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +%{ + predicate(!UseZabha || !UseZacas); + match(Set res (CompareAndExchangeS mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 6); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ - "cmpxchg $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeS" + "cmpxchg $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeS_narrow" %} ins_encode %{ @@ -5542,13 +5649,31 @@ instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI_R12 oldval, iReg ins_pipe(pipe_slow); %} +instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + predicate(UseZabha && UseZacas); + + match(Set res (CompareAndExchangeS mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeS" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ match(Set res (CompareAndExchangeI mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); - - effect(TEMP_DEF res); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeI" @@ -5566,9 +5691,7 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne %{ match(Set res (CompareAndExchangeL mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); - - effect(TEMP_DEF res); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeL" @@ -5585,11 +5708,10 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval) %{ predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndExchangeN mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 3); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); - effect(TEMP_DEF res); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeN" @@ -5606,11 +5728,10 @@ instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN ne instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval) %{ predicate(n->as_LoadStore()->barrier_data() == 0); - match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - effect(TEMP_DEF res); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeP" @@ -5624,19 +5745,19 @@ instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP ne ins_pipe(pipe_slow); %} -instruct compareAndExchangeBAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct compareAndExchangeBAcq_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate((!UseZabha || !UseZacas) && needs_acquiring_load_reserved(n)); match(Set res (CompareAndExchangeB mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 5); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ - "cmpxchg_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeBAcq" + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeBAcq_narrow" %} ins_encode %{ @@ -5648,19 +5769,39 @@ instruct compareAndExchangeBAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, i ins_pipe(pipe_slow); %} -instruct compareAndExchangeSAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct compareAndExchangeBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate((UseZabha && UseZacas) && needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndExchangeB mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeBAcq" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeSAcq_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +%{ + predicate((!UseZabha || !UseZacas) && needs_acquiring_load_reserved(n)); match(Set res (CompareAndExchangeS mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 6); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ - "cmpxchg_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeSAcq" + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeSAcq_narrow" %} ins_encode %{ @@ -5672,15 +5813,33 @@ instruct compareAndExchangeSAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, i ins_pipe(pipe_slow); %} +instruct compareAndExchangeSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + predicate((UseZabha && UseZacas) && needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndExchangeS mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeSAcq" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + instruct compareAndExchangeIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ predicate(needs_acquiring_load_reserved(n)); match(Set res (CompareAndExchangeI mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); - - effect(TEMP_DEF res); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeIAcq" @@ -5700,9 +5859,7 @@ instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL match(Set res (CompareAndExchangeL mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); - - effect(TEMP_DEF res); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeLAcq" @@ -5722,9 +5879,7 @@ instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN match(Set res (CompareAndExchangeN mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); - - effect(TEMP_DEF res); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeNAcq" @@ -5744,9 +5899,7 @@ instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP match(Set res (CompareAndExchangeP mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); - - effect(TEMP_DEF res); + ins_cost(2 * VOLATILE_REF_COST); format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangePAcq" @@ -5760,18 +5913,20 @@ instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP ins_pipe(pipe_slow); %} -instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct weakCompareAndSwapB_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ + predicate(!UseZabha || !UseZacas); + match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 6); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ "weak_cmpxchg $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval\n\t" - "# $res == 1 when success, #@weakCompareAndSwapB" + "# $res == 1 when success, #@weakCompareAndSwapB_narrow" %} ins_encode %{ @@ -5783,18 +5938,41 @@ instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI_R12 oldval, iReg ins_pipe(pipe_slow); %} -instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ + predicate(UseZabha && UseZacas); + + match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "weak_cmpxchg $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "# $res == 1 when success, #@weakCompareAndSwapB" + %} + + ins_encode %{ + __ weak_cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapS_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +%{ + predicate(!UseZabha || !UseZacas); + match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 7); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ "weak_cmpxchg $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval\n\t" - "# $res == 1 when success, #@weakCompareAndSwapS" + "# $res == 1 when success, #@weakCompareAndSwapS_narrow" %} ins_encode %{ @@ -5806,11 +5984,32 @@ instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI_R12 oldval, iReg ins_pipe(pipe_slow); %} +instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + predicate(UseZabha && UseZacas); + + match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "weak_cmpxchg $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "# $res == 1 when success, #@weakCompareAndSwapS" + %} + + ins_encode %{ + __ weak_cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + ins_cost(2 * VOLATILE_REF_COST); format %{ "weak_cmpxchg $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval\n\t" @@ -5829,7 +6028,7 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne %{ match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + ins_cost(2 * VOLATILE_REF_COST); format %{ "weak_cmpxchg $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval\n\t" @@ -5847,9 +6046,10 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "weak_cmpxchg $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval\n\t" @@ -5867,9 +6067,10 @@ instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN ne instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval) %{ predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + ins_cost(2 * VOLATILE_REF_COST); format %{ "weak_cmpxchg $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval\n\t" @@ -5884,20 +6085,20 @@ instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP ne ins_pipe(pipe_slow); %} -instruct weakCompareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct weakCompareAndSwapBAcq_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate((!UseZabha || !UseZacas) && needs_acquiring_load_reserved(n)); match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 6); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ "weak_cmpxchg_acq $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval\n\t" - "# $res == 1 when success, #@weakCompareAndSwapBAcq" + "# $res == 1 when success, #@weakCompareAndSwapBAcq_narrow" %} ins_encode %{ @@ -5909,20 +6110,41 @@ instruct weakCompareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, i ins_pipe(pipe_slow); %} -instruct weakCompareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, - iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +instruct weakCompareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate((UseZabha && UseZacas) && needs_acquiring_load_reserved(n)); + + match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "weak_cmpxchg_acq $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "# $res == 1 when success, #@weakCompareAndSwapBAcq" + %} + + ins_encode %{ + __ weak_cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapSAcq_narrow(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, rFlagsReg cr) +%{ + predicate((!UseZabha || !UseZacas) && needs_acquiring_load_reserved(n)); match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 7); + ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); format %{ "weak_cmpxchg_acq $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval\n\t" - "# $res == 1 when success, #@weakCompareAndSwapSAcq" + "# $res == 1 when success, #@weakCompareAndSwapSAcq_narrow" %} ins_encode %{ @@ -5934,13 +6156,34 @@ instruct weakCompareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, i ins_pipe(pipe_slow); %} +instruct weakCompareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + predicate((UseZabha && UseZacas) && needs_acquiring_load_reserved(n)); + + match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ + "weak_cmpxchg_acq $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "# $res == 1 when success, #@weakCompareAndSwapSAcq" + %} + + ins_encode %{ + __ weak_cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + instruct weakCompareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) %{ predicate(needs_acquiring_load_reserved(n)); match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + ins_cost(2 * VOLATILE_REF_COST); format %{ "weak_cmpxchg_acq $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval\n\t" @@ -5961,7 +6204,7 @@ instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + ins_cost(2 * VOLATILE_REF_COST); format %{ "weak_cmpxchg_acq $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval\n\t" @@ -5982,7 +6225,7 @@ instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 4); + ins_cost(2 * VOLATILE_REF_COST); format %{ "weak_cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval\n\t" @@ -6003,7 +6246,7 @@ instruct weakCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); - ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + ins_cost(2 * VOLATILE_REF_COST); format %{ "weak_cmpxchg_acq $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval\n\t" @@ -6445,7 +6688,6 @@ instruct addI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immIAdd src2) %{ format %{ "addiw $dst, $src1, $src2\t#@addI_reg_imm" %} ins_encode %{ - int32_t con = (int32_t)$src2$$constant; __ addiw(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant); @@ -6507,7 +6749,6 @@ instruct addP_reg_imm(iRegPNoSp dst, iRegP src1, immLAdd src2) %{ format %{ "addi $dst, $src1, $src2\t# ptr, #@addP_reg_imm" %} ins_encode %{ - // src2 is imm, so actually call the addi __ addi(as_Register($dst$$reg), as_Register($src1$$reg), $src2$$constant); @@ -6829,7 +7070,7 @@ instruct UmodL(iRegLNoSp dst, iRegL src1, iRegL src2) %{ // Integer Shifts // Shift Left Register -// In RV64I, only the low 5 bits of src2 are considered for the shift amount +// Only the low 5 bits of src2 are considered for the shift amount, all other bits are ignored. instruct lShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (LShiftI src1 src2)); ins_cost(ALU_COST); @@ -6862,7 +7103,7 @@ instruct lShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ %} // Shift Right Logical Register -// In RV64I, only the low 5 bits of src2 are considered for the shift amount +// Only the low 5 bits of src2 are considered for the shift amount, all other bits are ignored. instruct urShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (URShiftI src1 src2)); ins_cost(ALU_COST); @@ -6895,7 +7136,7 @@ instruct urShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ %} // Shift Right Arithmetic Register -// In RV64I, only the low 5 bits of src2 are considered for the shift amount +// Only the low 5 bits of src2 are considered for the shift amount, all other bits are ignored. instruct rShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ match(Set dst (RShiftI src1 src2)); ins_cost(ALU_COST); @@ -6930,7 +7171,7 @@ instruct rShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ // Long Shifts // Shift Left Register -// In RV64I, only the low 6 bits of src2 are considered for the shift amount +// Only the low 6 bits of src2 are considered for the shift amount, all other bits are ignored. instruct lShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ match(Set dst (LShiftL src1 src2)); @@ -6965,7 +7206,7 @@ instruct lShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ %} // Shift Right Logical Register -// In RV64I, only the low 6 bits of src2 are considered for the shift amount +// Only the low 6 bits of src2 are considered for the shift amount, all other bits are ignored. instruct urShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ match(Set dst (URShiftL src1 src2)); @@ -7018,7 +7259,7 @@ instruct urShiftP_reg_imm(iRegLNoSp dst, iRegP src1, immI src2) %{ %} // Shift Right Arithmetic Register -// In RV64I, only the low 6 bits of src2 are considered for the shift amount +// Only the low 6 bits of src2 are considered for the shift amount, all other bits are ignored. instruct rShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ match(Set dst (RShiftL src1 src2)); @@ -9940,12 +10181,15 @@ instruct far_cmpP_narrowOop_imm0_branch(cmpOpEqNe cmp, iRegN op1, immP0 zero, la // ============================================================================ // Conditional Move Instructions + +// --------- CMoveI --------- + instruct cmovI_cmpI(iRegINoSp dst, iRegI src, iRegI op1, iRegI op2, cmpOp cop) %{ match(Set dst (CMoveI (Binary cop (CmpI op1 op2)) (Binary dst src))); ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpI\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpI\n\t" %} ins_encode %{ @@ -9962,7 +10206,7 @@ instruct cmovI_cmpU(iRegINoSp dst, iRegI src, iRegI op1, iRegI op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpU\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpU\n\t" %} ins_encode %{ @@ -9979,7 +10223,7 @@ instruct cmovI_cmpL(iRegINoSp dst, iRegI src, iRegL op1, iRegL op2, cmpOp cop) % ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpL\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpL\n\t" %} ins_encode %{ @@ -9996,7 +10240,7 @@ instruct cmovI_cmpUL(iRegINoSp dst, iRegI src, iRegL op1, iRegL op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpUL\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpUL\n\t" %} ins_encode %{ @@ -10008,12 +10252,46 @@ instruct cmovI_cmpUL(iRegINoSp dst, iRegI src, iRegL op1, iRegL op2, cmpOpU cop) ins_pipe(pipe_class_compare); %} +instruct cmovI_cmpF(iRegINoSp dst, iRegI src, fRegF op1, fRegF op2, cmpOp cop) %{ + match(Set dst (CMoveI (Binary cop (CmpF op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpF\n\t" + %} + + ins_encode %{ + __ enc_cmove_cmp_fp($cop$$cmpcode, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovI_cmpD(iRegINoSp dst, iRegI src, fRegD op1, fRegD op2, cmpOp cop) %{ + match(Set dst (CMoveI (Binary cop (CmpD op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpD\n\t" + %} + + ins_encode %{ + __ enc_cmove_cmp_fp($cop$$cmpcode | C2_MacroAssembler::double_branch_mask, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + instruct cmovI_cmpN(iRegINoSp dst, iRegI src, iRegN op1, iRegN op2, cmpOpU cop) %{ match(Set dst (CMoveI (Binary cop (CmpN op1 op2)) (Binary dst src))); ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpN\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpN\n\t" %} ins_encode %{ @@ -10030,7 +10308,7 @@ instruct cmovI_cmpP(iRegINoSp dst, iRegI src, iRegP op1, iRegP op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpP\n\t" + "CMoveI $dst, ($op1 $cop $op2), $dst, $src\t#@cmovI_cmpP\n\t" %} ins_encode %{ @@ -10042,12 +10320,14 @@ instruct cmovI_cmpP(iRegINoSp dst, iRegI src, iRegP op1, iRegP op2, cmpOpU cop) ins_pipe(pipe_class_compare); %} +// --------- CMoveL --------- + instruct cmovL_cmpL(iRegLNoSp dst, iRegL src, iRegL op1, iRegL op2, cmpOp cop) %{ match(Set dst (CMoveL (Binary cop (CmpL op1 op2)) (Binary dst src))); ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpL\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpL\n\t" %} ins_encode %{ @@ -10064,7 +10344,7 @@ instruct cmovL_cmpUL(iRegLNoSp dst, iRegL src, iRegL op1, iRegL op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpUL\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpUL\n\t" %} ins_encode %{ @@ -10081,7 +10361,7 @@ instruct cmovL_cmpI(iRegLNoSp dst, iRegL src, iRegI op1, iRegI op2, cmpOp cop) % ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpI\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpI\n\t" %} ins_encode %{ @@ -10098,7 +10378,7 @@ instruct cmovL_cmpU(iRegLNoSp dst, iRegL src, iRegI op1, iRegI op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpU\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpU\n\t" %} ins_encode %{ @@ -10110,12 +10390,46 @@ instruct cmovL_cmpU(iRegLNoSp dst, iRegL src, iRegI op1, iRegI op2, cmpOpU cop) ins_pipe(pipe_class_compare); %} +instruct cmovL_cmpF(iRegLNoSp dst, iRegL src, fRegF op1, fRegF op2, cmpOp cop) %{ + match(Set dst (CMoveL (Binary cop (CmpF op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpF\n\t" + %} + + ins_encode %{ + __ enc_cmove_cmp_fp($cop$$cmpcode, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovL_cmpD(iRegLNoSp dst, iRegL src, fRegD op1, fRegD op2, cmpOp cop) %{ + match(Set dst (CMoveL (Binary cop (CmpD op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpD\n\t" + %} + + ins_encode %{ + __ enc_cmove_cmp_fp($cop$$cmpcode | C2_MacroAssembler::double_branch_mask, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + instruct cmovL_cmpN(iRegLNoSp dst, iRegL src, iRegN op1, iRegN op2, cmpOpU cop) %{ match(Set dst (CMoveL (Binary cop (CmpN op1 op2)) (Binary dst src))); ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpN\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpN\n\t" %} ins_encode %{ @@ -10132,7 +10446,7 @@ instruct cmovL_cmpP(iRegLNoSp dst, iRegL src, iRegP op1, iRegP op2, cmpOpU cop) ins_cost(ALU_COST + BRANCH_COST); format %{ - "CMove $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpP\n\t" + "CMoveL $dst, ($op1 $cop $op2), $dst, $src\t#@cmovL_cmpP\n\t" %} ins_encode %{ diff --git a/src/hotspot/cpu/riscv/riscv_b.ad b/src/hotspot/cpu/riscv/riscv_b.ad index ed9fca13a1b..beac10ec03d 100644 --- a/src/hotspot/cpu/riscv/riscv_b.ad +++ b/src/hotspot/cpu/riscv/riscv_b.ad @@ -25,7 +25,8 @@ // RISCV Bit-Manipulation Extension Architecture Description File -instruct rorI_imm_b(iRegINoSp dst, iRegI src, immI shift) %{ +// Rotate Right Word Immediate +instruct rorI_imm_b(iRegINoSp dst, iRegIorL2I src, immI shift) %{ predicate(UseZbb); match(Set dst (RotateRight src shift)); @@ -39,6 +40,7 @@ instruct rorI_imm_b(iRegINoSp dst, iRegI src, immI shift) %{ ins_pipe(ialu_reg_shift); %} +// Rotate Right Immediate instruct rorL_imm_b(iRegLNoSp dst, iRegL src, immI shift) %{ predicate(UseZbb); match(Set dst (RotateRight src shift)); @@ -53,7 +55,9 @@ instruct rorL_imm_b(iRegLNoSp dst, iRegL src, immI shift) %{ ins_pipe(ialu_reg_shift); %} -instruct rorI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ +// Rotate Right Word Register +// Only the low 5 bits of shift value are used, all other bits are ignored. +instruct rorI_reg_b(iRegINoSp dst, iRegIorL2I src, iRegIorL2I shift) %{ predicate(UseZbb); match(Set dst (RotateRight src shift)); @@ -65,7 +69,9 @@ instruct rorI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ ins_pipe(ialu_reg_reg); %} -instruct rorL_reg_b(iRegLNoSp dst, iRegL src, iRegI shift) %{ +// Rotate Right Register +// Only the low 6 bits of shift value are used, all other bits are ignored. +instruct rorL_reg_b(iRegLNoSp dst, iRegL src, iRegIorL2I shift) %{ predicate(UseZbb); match(Set dst (RotateRight src shift)); @@ -77,7 +83,9 @@ instruct rorL_reg_b(iRegLNoSp dst, iRegL src, iRegI shift) %{ ins_pipe(ialu_reg_reg); %} -instruct rolI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ +// Rotate Left Word Register +// Only the low 5 bits of shift value are used, all other bits are ignored. +instruct rolI_reg_b(iRegINoSp dst, iRegIorL2I src, iRegIorL2I shift) %{ predicate(UseZbb); match(Set dst (RotateLeft src shift)); @@ -89,7 +97,9 @@ instruct rolI_reg_b(iRegINoSp dst, iRegI src, iRegI shift) %{ ins_pipe(ialu_reg_reg); %} -instruct rolL_reg_b(iRegLNoSp dst, iRegL src, iRegI shift) %{ +// Rotate Left Register +// Only the low 6 bits of shift value are used, all other bits are ignored. +instruct rolL_reg_b(iRegLNoSp dst, iRegL src, iRegIorL2I shift) %{ predicate(UseZbb); match(Set dst (RotateLeft src shift)); diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 9b135215b3d..8b5759ce11c 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -89,13 +89,12 @@ source %{ return UseZvbb; case Op_LoadVectorGather: case Op_LoadVectorGatherMasked: + case Op_StoreVectorScatter: + case Op_StoreVectorScatterMasked: if (is_subword_type(bt)) { return false; } break; - case Op_VectorCastHF2F: - case Op_VectorCastF2HF: - return UseZvfh; case Op_VectorLoadShuffle: case Op_VectorRearrange: // vlen >= 4 is required, because min vector size for byte is 4 on riscv, @@ -111,6 +110,32 @@ source %{ if (vlen < 4) { return false; } + case Op_VectorCastHF2F: + case Op_VectorCastF2HF: + case Op_AddVHF: + case Op_DivVHF: + case Op_MaxVHF: + case Op_MinVHF: + case Op_MulVHF: + case Op_SqrtVHF: + case Op_SubVHF: + return UseZvfh; + case Op_FmaVHF: + return UseZvfh && UseFMA; + case Op_FmaVF: + case Op_FmaVD: + return UseFMA; + + // For float, current test shows that, it brings performance gain when vlen >= 8, but brings + // regression when vlen == 4. So only enable this intrinsic when vlen >= 8. + // For double, current test shows that even with vlen == 4, there is still some regression. + // Although there is no hardware to verify it, from the trend of performance data on hardwares + // (with vlen == 2 and 4 respectively), it's promising to bring better performance rather than + // regression for double when vlen == 8. So only enable this intrinsic when vlen >= 8. + case Op_RoundVF: + case Op_RoundVD: + return vlen >= 8; + default: break; } @@ -140,16 +165,11 @@ source %{ } %} -definitions %{ - int_def VEC_COST (200, 200); -%} - // All VEC instructions // vector load/store instruct loadV(vReg dst, vmemA mem) %{ match(Set dst (LoadVector mem)); - ins_cost(VEC_COST); format %{ "loadV $dst, $mem\t# vector (rvv)" %} ins_encode %{ VectorRegister dst_reg = as_VectorRegister($dst$$reg); @@ -161,7 +181,6 @@ instruct loadV(vReg dst, vmemA mem) %{ instruct storeV(vReg src, vmemA mem) %{ match(Set mem (StoreVector mem src)); - ins_cost(VEC_COST); format %{ "storeV $mem, $src\t# vector (rvv)" %} ins_encode %{ VectorRegister src_reg = as_VectorRegister($src$$reg); @@ -249,7 +268,6 @@ instruct vmaskcmp_fp(vRegMask dst, vReg src1, vReg src2, immI cond) %{ predicate(Matcher::vector_element_basic_type(n) == T_FLOAT || Matcher::vector_element_basic_type(n) == T_DOUBLE); match(Set dst (VectorMaskCmp (Binary src1 src2) cond)); - effect(TEMP_DEF dst); format %{ "vmaskcmp_fp $dst, $src1, $src2, $cond" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -284,7 +302,6 @@ instruct vabs(vReg dst, vReg src, vReg tmp) %{ match(Set dst (AbsVS src)); match(Set dst (AbsVI src)); match(Set dst (AbsVL src)); - ins_cost(VEC_COST); effect(TEMP tmp); format %{ "vabs $dst, $src\t# KILL $tmp" %} ins_encode %{ @@ -299,7 +316,6 @@ instruct vabs(vReg dst, vReg src, vReg tmp) %{ instruct vabs_fp(vReg dst, vReg src) %{ match(Set dst (AbsVF src)); match(Set dst (AbsVD src)); - ins_cost(VEC_COST); format %{ "vabs_fp $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -316,7 +332,6 @@ instruct vabs_masked(vReg dst_src, vRegMask_V0 v0, vReg tmp) %{ match(Set dst_src (AbsVS dst_src v0)); match(Set dst_src (AbsVI dst_src v0)); match(Set dst_src (AbsVL dst_src v0)); - ins_cost(VEC_COST); effect(TEMP tmp); format %{ "vabs_masked $dst_src, $dst_src, $v0\t# KILL $tmp" %} ins_encode %{ @@ -333,7 +348,6 @@ instruct vabs_masked(vReg dst_src, vRegMask_V0 v0, vReg tmp) %{ instruct vabs_fp_masked(vReg dst_src, vRegMask_V0 v0) %{ match(Set dst_src (AbsVF dst_src v0)); match(Set dst_src (AbsVD dst_src v0)); - ins_cost(VEC_COST); format %{ "vabs_fp_masked $dst_src, $dst_src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -350,7 +364,6 @@ instruct vadd(vReg dst, vReg src1, vReg src2) %{ match(Set dst (AddVS src1 src2)); match(Set dst (AddVI src1 src2)); match(Set dst (AddVL src1 src2)); - ins_cost(VEC_COST); format %{ "vadd $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -362,10 +375,23 @@ instruct vadd(vReg dst, vReg src1, vReg src2) %{ ins_pipe(pipe_slow); %} +instruct vadd_hfp(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (AddVHF src1 src2)); + format %{ "vadd_hfp $dst, $src1, $src2" %} + ins_encode %{ + assert(UseZvfh, "must"); + assert(Matcher::vector_element_basic_type(this) == T_SHORT, "must"); + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vfadd_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + instruct vadd_fp(vReg dst, vReg src1, vReg src2) %{ match(Set dst (AddVF src1 src2)); match(Set dst (AddVD src1 src2)); - ins_cost(VEC_COST); format %{ "vadd_fp $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -384,7 +410,6 @@ instruct vadd_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (AddVS (Binary dst_src1 src2) v0)); match(Set dst_src1 (AddVI (Binary dst_src1 src2) v0)); match(Set dst_src1 (AddVL (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vadd_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -399,7 +424,6 @@ instruct vadd_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ instruct vadd_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (AddVF (Binary dst_src1 src2) v0)); match(Set dst_src1 (AddVD (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vadd_fp_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -413,11 +437,11 @@ instruct vadd_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate add (unpredicated) -instruct vadd_immI(vReg dst, vReg src1, immI5 con) %{ +instruct vadd_vi(vReg dst, vReg src1, immI5 con) %{ match(Set dst (AddVB src1 (Replicate con))); match(Set dst (AddVS src1 (Replicate con))); match(Set dst (AddVI src1 (Replicate con))); - format %{ "vadd_immI $dst, $src1, $con" %} + format %{ "vadd_vi $dst, $src1, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -428,9 +452,9 @@ instruct vadd_immI(vReg dst, vReg src1, immI5 con) %{ ins_pipe(pipe_slow); %} -instruct vadd_immL(vReg dst, vReg src1, immL5 con) %{ +instruct vaddL_vi(vReg dst, vReg src1, immL5 con) %{ match(Set dst (AddVL src1 (Replicate con))); - format %{ "vadd_immL $dst, $src1, $con" %} + format %{ "vaddL_vi $dst, $src1, $con" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vadd_vi(as_VectorRegister($dst$$reg), @@ -442,11 +466,11 @@ instruct vadd_immL(vReg dst, vReg src1, immL5 con) %{ // vector-scalar add (unpredicated) -instruct vadd_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ +instruct vadd_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ match(Set dst (AddVB src1 (Replicate src2))); match(Set dst (AddVS src1 (Replicate src2))); match(Set dst (AddVI src1 (Replicate src2))); - format %{ "vadd_regI $dst, $src1, $src2" %} + format %{ "vadd_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -457,9 +481,9 @@ instruct vadd_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ ins_pipe(pipe_slow); %} -instruct vadd_regL(vReg dst, vReg src1, iRegL src2) %{ +instruct vaddL_vx(vReg dst, vReg src1, iRegL src2) %{ match(Set dst (AddVL src1 (Replicate src2))); - format %{ "vadd_regL $dst, $src1, $src2" %} + format %{ "vaddL_vx $dst, $src1, $src2" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vadd_vx(as_VectorRegister($dst$$reg), @@ -471,11 +495,11 @@ instruct vadd_regL(vReg dst, vReg src1, iRegL src2) %{ // vector-immediate add (predicated) -instruct vadd_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ +instruct vadd_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ match(Set dst_src (AddVB (Binary dst_src (Replicate con)) v0)); match(Set dst_src (AddVS (Binary dst_src (Replicate con)) v0)); match(Set dst_src (AddVI (Binary dst_src (Replicate con)) v0)); - format %{ "vadd_immI_masked $dst_src, $dst_src, $con" %} + format %{ "vadd_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -486,9 +510,9 @@ instruct vadd_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vadd_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ +instruct vaddL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ match(Set dst_src (AddVL (Binary dst_src (Replicate con)) v0)); - format %{ "vadd_immL_masked $dst_src, $dst_src, $con" %} + format %{ "vaddL_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vadd_vi(as_VectorRegister($dst_src$$reg), @@ -500,11 +524,11 @@ instruct vadd_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar add (predicated) -instruct vadd_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ +instruct vadd_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ match(Set dst_src (AddVB (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (AddVS (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (AddVI (Binary dst_src (Replicate src2)) v0)); - format %{ "vadd_regI_masked $dst_src, $dst_src, $src2" %} + format %{ "vadd_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -515,9 +539,9 @@ instruct vadd_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vadd_regL_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ +instruct vaddL_vx_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ match(Set dst_src (AddVL (Binary dst_src (Replicate src2)) v0)); - format %{ "vadd_regL_masked $dst_src, $dst_src, $src2" %} + format %{ "vaddL_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vadd_vx(as_VectorRegister($dst_src$$reg), @@ -534,7 +558,6 @@ instruct vsub(vReg dst, vReg src1, vReg src2) %{ match(Set dst (SubVS src1 src2)); match(Set dst (SubVI src1 src2)); match(Set dst (SubVL src1 src2)); - ins_cost(VEC_COST); format %{ "vsub $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -545,10 +568,22 @@ instruct vsub(vReg dst, vReg src1, vReg src2) %{ ins_pipe(pipe_slow); %} +instruct vsub_hfp(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (SubVHF src1 src2)); + format %{ "vsub_hfp $dst, $src1, $src2" %} + ins_encode %{ + assert(UseZvfh, "must"); + assert(Matcher::vector_element_basic_type(this) == T_SHORT, "must"); + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vfsub_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + instruct vsub_fp(vReg dst, vReg src1, vReg src2) %{ match(Set dst (SubVF src1 src2)); match(Set dst (SubVD src1 src2)); - ins_cost(VEC_COST); format %{ "vsub_fp $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -566,7 +601,6 @@ instruct vsub_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (SubVS (Binary dst_src1 src2) v0)); match(Set dst_src1 (SubVI (Binary dst_src1 src2) v0)); match(Set dst_src1 (SubVL (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vsub_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -580,7 +614,6 @@ instruct vsub_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ instruct vsub_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (SubVF (Binary dst_src1 src2) v0)); match(Set dst_src1 (SubVD (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vsub_fp_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -593,11 +626,11 @@ instruct vsub_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-scalar sub (unpredicated) -instruct vsub_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ +instruct vsub_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ match(Set dst (SubVB src1 (Replicate src2))); match(Set dst (SubVS src1 (Replicate src2))); match(Set dst (SubVI src1 (Replicate src2))); - format %{ "vsub_regI $dst, $src1, $src2" %} + format %{ "vsub_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -608,9 +641,9 @@ instruct vsub_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ ins_pipe(pipe_slow); %} -instruct vsub_regL(vReg dst, vReg src1, iRegL src2) %{ +instruct vsubL_vx(vReg dst, vReg src1, iRegL src2) %{ match(Set dst (SubVL src1 (Replicate src2))); - format %{ "vsub_regL $dst, $src1, $src2" %} + format %{ "vsubL_vx $dst, $src1, $src2" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vsub_vx(as_VectorRegister($dst$$reg), @@ -622,11 +655,11 @@ instruct vsub_regL(vReg dst, vReg src1, iRegL src2) %{ // vector-scalar sub (predicated) -instruct vsub_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ +instruct vsub_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ match(Set dst_src (SubVB (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (SubVS (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (SubVI (Binary dst_src (Replicate src2)) v0)); - format %{ "vsub_regI_masked $dst_src, $dst_src, $src2" %} + format %{ "vsub_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -637,9 +670,9 @@ instruct vsub_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vsub_regL_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ +instruct vsubL_vx_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ match(Set dst_src (SubVL (Binary dst_src (Replicate src2)) v0)); - format %{ "vsub_regL_masked $dst_src, $dst_src, $src2" %} + format %{ "vsubL_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vsub_vx(as_VectorRegister($dst_src$$reg), @@ -649,11 +682,140 @@ instruct vsub_regL_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} +// -------- vector saturating integer operations + +// vector saturating signed integer addition + +instruct vsadd(vReg dst, vReg src1, vReg src2) %{ + predicate(n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV src1 src2)); + format %{ "vsadd $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vsadd_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector saturating unsigned integer addition + +instruct vsaddu(vReg dst, vReg src1, vReg src2) %{ + predicate(n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingAddV src1 src2)); + format %{ "vsaddu $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vsaddu_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector saturating signed integer addition (predicated) + +instruct vsadd_masked(vReg dst_src, vReg src1, vRegMask_V0 v0) %{ + predicate(n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned()); + match(Set dst_src (SaturatingAddV (Binary dst_src src1) v0)); + format %{ "vsadd_masked $dst_src, $dst_src, $src1, $v0" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vsadd_vv(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + as_VectorRegister($src1$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +// vector saturating unsigned integer addition (predicated) + +instruct vsaddu_masked(vReg dst_src, vReg src1, vRegMask_V0 v0) %{ + predicate(n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned()); + match(Set dst_src (SaturatingAddV (Binary dst_src src1) v0)); + format %{ "vsaddu_masked $dst_src, $dst_src, $src1, $v0" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vsaddu_vv(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + as_VectorRegister($src1$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +// vector saturating signed integer subtraction + +instruct vssub(vReg dst, vReg src1, vReg src2) %{ + predicate(n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingSubV src1 src2)); + format %{ "vssub $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vssub_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector saturating unsigned integer subtraction + +instruct vssubu(vReg dst, vReg src1, vReg src2) %{ + predicate(n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned()); + match(Set dst (SaturatingSubV src1 src2)); + format %{ "vssubu $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vssubu_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector saturating signed integer subtraction (predicated) + +instruct vssub_masked(vReg dst_src, vReg src1, vRegMask_V0 v0) %{ + predicate(n->is_SaturatingVector() && !n->as_SaturatingVector()->is_unsigned()); + match(Set dst_src (SaturatingSubV (Binary dst_src src1) v0)); + format %{ "vssub_masked $dst_src, $dst_src, $src1, $v0" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vssub_vv(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + as_VectorRegister($src1$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +// vector saturating unsigned integer subtraction (predicated) + +instruct vssubu_masked(vReg dst_src, vReg src1, vRegMask_V0 v0) %{ + predicate(n->is_SaturatingVector() && n->as_SaturatingVector()->is_unsigned()); + match(Set dst_src (SaturatingSubV (Binary dst_src src1) v0)); + format %{ "vssubu_masked $dst_src, $dst_src, $src1, $v0" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vssubu_vv(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + as_VectorRegister($src1$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + // vector and instruct vand(vReg dst, vReg src1, vReg src2) %{ match(Set dst (AndV src1 src2)); - ins_cost(VEC_COST); format %{ "vand $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -669,7 +831,6 @@ instruct vand(vReg dst, vReg src1, vReg src2) %{ instruct vand_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (AndV (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vand_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -683,30 +844,30 @@ instruct vand_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate and (unpredicated) -instruct vand_immI(vReg dst_src, immI5 con) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); - match(Set dst_src (AndV dst_src (Replicate con))); - format %{ "vand_immI $dst_src, $dst_src, $con" %} +instruct vand_vi(vReg dst, vReg src1, immI5 con) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst (AndV src1 (Replicate con))); + format %{ "vand_vi $dst, $src1, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vand_vi(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), + __ vand_vi(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), $con$$constant); %} ins_pipe(pipe_slow); %} -instruct vand_immL(vReg dst_src, immL5 con) %{ +instruct vandL_vi(vReg dst, vReg src1, immL5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); - match(Set dst_src (AndV dst_src (Replicate con))); - format %{ "vand_immL $dst_src, $dst_src, $con" %} + match(Set dst (AndV src1 (Replicate con))); + format %{ "vandL_vi $dst, $src1, $con" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); - __ vand_vi(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), + __ vand_vi(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), $con$$constant); %} ins_pipe(pipe_slow); @@ -714,43 +875,43 @@ instruct vand_immL(vReg dst_src, immL5 con) %{ // vector-scalar and (unpredicated) -instruct vand_regI(vReg dst_src, iRegIorL2I src) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); - match(Set dst_src (AndV dst_src (Replicate src))); - format %{ "vand_regI $dst_src, $dst_src, $src" %} +instruct vand_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst (AndV src1 (Replicate src2))); + format %{ "vand_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vand_vx(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), - as_Register($src$$reg)); + __ vand_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); %} ins_pipe(pipe_slow); %} -instruct vand_regL(vReg dst_src, iRegL src) %{ +instruct vandL_vx(vReg dst, vReg src1, iRegL src2) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); - match(Set dst_src (AndV dst_src (Replicate src))); - format %{ "vand_regL $dst_src, $dst_src, $src" %} + match(Set dst (AndV src1 (Replicate src2))); + format %{ "vandL_vx $dst, $src1, $src2" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); - __ vand_vx(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), - as_Register($src$$reg)); + __ vand_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); %} ins_pipe(pipe_slow); %} // vector-immediate and (predicated) -instruct vand_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); +instruct vand_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); match(Set dst_src (AndV (Binary dst_src (Replicate con)) v0)); - format %{ "vand_immI_masked $dst_src, $dst_src, $con" %} + format %{ "vand_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -761,10 +922,10 @@ instruct vand_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vand_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ +instruct vandL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (AndV (Binary dst_src (Replicate con)) v0)); - format %{ "vand_immL_masked $dst_src, $dst_src, $con" %} + format %{ "vandL_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vand_vi(as_VectorRegister($dst_src$$reg), @@ -776,12 +937,12 @@ instruct vand_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar and (predicated) -instruct vand_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); +instruct vand_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); match(Set dst_src (AndV (Binary dst_src (Replicate src)) v0)); - format %{ "vand_regI_masked $dst_src, $dst_src, $src" %} + format %{ "vand_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -792,10 +953,10 @@ instruct vand_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vand_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ +instruct vandL_vx_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (AndV (Binary dst_src (Replicate src)) v0)); - format %{ "vand_regL_masked $dst_src, $dst_src, $src" %} + format %{ "vandL_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vand_vx(as_VectorRegister($dst_src$$reg), @@ -809,7 +970,6 @@ instruct vand_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ instruct vor(vReg dst, vReg src1, vReg src2) %{ match(Set dst (OrV src1 src2)); - ins_cost(VEC_COST); format %{ "vor $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -825,7 +985,6 @@ instruct vor(vReg dst, vReg src1, vReg src2) %{ instruct vor_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (OrV (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vor_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -839,30 +998,30 @@ instruct vor_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate or (unpredicated) -instruct vor_immI(vReg dst_src, immI5 con) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); - match(Set dst_src (OrV dst_src (Replicate con))); - format %{ "vor_immI $dst_src, $dst_src, $con" %} +instruct vor_vi(vReg dst, vReg src1, immI5 con) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst (OrV src1 (Replicate con))); + format %{ "vor_vi $dst, $src1, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vor_vi(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), + __ vor_vi(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), $con$$constant); %} ins_pipe(pipe_slow); %} -instruct vor_immL(vReg dst_src, immL5 con) %{ +instruct vorL_vi(vReg dst, vReg src1, immL5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); - match(Set dst_src (OrV dst_src (Replicate con))); - format %{ "vor_immL $dst_src, $dst_src, $con" %} + match(Set dst (OrV src1 (Replicate con))); + format %{ "vorL_vi $dst, $src1, $con" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); - __ vor_vi(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), + __ vor_vi(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), $con$$constant); %} ins_pipe(pipe_slow); @@ -870,43 +1029,43 @@ instruct vor_immL(vReg dst_src, immL5 con) %{ // vector-scalar or (unpredicated) -instruct vor_regI(vReg dst_src, iRegIorL2I src) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); - match(Set dst_src (OrV dst_src (Replicate src))); - format %{ "vor_regI $dst_src, $dst_src, $src" %} +instruct vor_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst (OrV src1 (Replicate src2))); + format %{ "vor_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vor_vx(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), - as_Register($src$$reg)); + __ vor_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); %} ins_pipe(pipe_slow); %} -instruct vor_regL(vReg dst_src, iRegL src) %{ +instruct vorL_vx(vReg dst, vReg src1, iRegL src2) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); - match(Set dst_src (OrV dst_src (Replicate src))); - format %{ "vor_regL $dst_src, $dst_src, $src" %} + match(Set dst (OrV src1 (Replicate src2))); + format %{ "vorL_vx $dst, $src1, $src2" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); - __ vor_vx(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), - as_Register($src$$reg)); + __ vor_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); %} ins_pipe(pipe_slow); %} // vector-immediate or (predicated) -instruct vor_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); +instruct vor_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); match(Set dst_src (OrV (Binary dst_src (Replicate con)) v0)); - format %{ "vor_immI_masked $dst_src, $dst_src, $con" %} + format %{ "vor_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -917,10 +1076,10 @@ instruct vor_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vor_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ +instruct vorL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (OrV (Binary dst_src (Replicate con)) v0)); - format %{ "vor_immL_masked $dst_src, $dst_src, $con" %} + format %{ "vorL_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vor_vi(as_VectorRegister($dst_src$$reg), @@ -932,12 +1091,12 @@ instruct vor_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar or (predicated) -instruct vor_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); +instruct vor_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); match(Set dst_src (OrV (Binary dst_src (Replicate src)) v0)); - format %{ "vor_regI_masked $dst_src, $dst_src, $src" %} + format %{ "vor_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -948,10 +1107,10 @@ instruct vor_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vor_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ +instruct vorL_vx_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (OrV (Binary dst_src (Replicate src)) v0)); - format %{ "vor_regL_masked $dst_src, $dst_src, $src" %} + format %{ "vorL_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vor_vx(as_VectorRegister($dst_src$$reg), @@ -965,7 +1124,6 @@ instruct vor_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ instruct vxor(vReg dst, vReg src1, vReg src2) %{ match(Set dst (XorV src1 src2)); - ins_cost(VEC_COST); format %{ "vxor $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -981,7 +1139,6 @@ instruct vxor(vReg dst, vReg src1, vReg src2) %{ instruct vxor_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (XorV (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vxor_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -995,30 +1152,30 @@ instruct vxor_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-immediate xor (unpredicated) -instruct vxor_immI(vReg dst_src, immI5 con) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); - match(Set dst_src (XorV dst_src (Replicate con))); - format %{ "vxor_immI $dst_src, $dst_src, $con" %} +instruct vxor_vi(vReg dst, vReg src1, immI5 con) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst (XorV src1 (Replicate con))); + format %{ "vxor_vi $dst, $src1, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vxor_vi(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), + __ vxor_vi(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), $con$$constant); %} ins_pipe(pipe_slow); %} -instruct vxor_immL(vReg dst_src, immL5 con) %{ +instruct vxorL_vi(vReg dst, vReg src1, immL5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); - match(Set dst_src (XorV dst_src (Replicate con))); - format %{ "vxor_immL $dst_src, $dst_src, $con" %} + match(Set dst (XorV src1 (Replicate con))); + format %{ "vxorL_vi $dst, $src1, $con" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); - __ vxor_vi(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), + __ vxor_vi(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), $con$$constant); %} ins_pipe(pipe_slow); @@ -1026,43 +1183,43 @@ instruct vxor_immL(vReg dst_src, immL5 con) %{ // vector-scalar xor (unpredicated) -instruct vxor_regI(vReg dst_src, iRegIorL2I src) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); - match(Set dst_src (XorV dst_src (Replicate src))); - format %{ "vxor_regI $dst_src, $dst_src, $src" %} +instruct vxor_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst (XorV src1 (Replicate src2))); + format %{ "vxor_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vxor_vx(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), - as_Register($src$$reg)); + __ vxor_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); %} ins_pipe(pipe_slow); %} -instruct vxor_regL(vReg dst_src, iRegL src) %{ +instruct vxorL_vx(vReg dst, vReg src1, iRegL src2) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); - match(Set dst_src (XorV dst_src (Replicate src))); - format %{ "vxor_regL $dst_src, $dst_src, $src" %} + match(Set dst (XorV src1 (Replicate src2))); + format %{ "vxorL_vx $dst, $src1, $src2" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); - __ vxor_vx(as_VectorRegister($dst_src$$reg), - as_VectorRegister($dst_src$$reg), - as_Register($src$$reg)); + __ vxor_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); %} ins_pipe(pipe_slow); %} // vector-immediate xor (predicated) -instruct vxor_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); +instruct vxor_vi_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); match(Set dst_src (XorV (Binary dst_src (Replicate con)) v0)); - format %{ "vxor_immI_masked $dst_src, $dst_src, $con" %} + format %{ "vxor_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1073,10 +1230,10 @@ instruct vxor_immI_masked(vReg dst_src, immI5 con, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vxor_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ +instruct vxorL_vi_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (XorV (Binary dst_src (Replicate con)) v0)); - format %{ "vxor_immL_masked $dst_src, $dst_src, $con" %} + format %{ "vxorL_vi_masked $dst_src, $dst_src, $con, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vxor_vi(as_VectorRegister($dst_src$$reg), @@ -1088,12 +1245,12 @@ instruct vxor_immL_masked(vReg dst_src, immL5 con, vRegMask_V0 v0) %{ // vector-scalar xor (predicated) -instruct vxor_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); +instruct vxor_vx_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); match(Set dst_src (XorV (Binary dst_src (Replicate src)) v0)); - format %{ "vxor_regI_masked $dst_src, $dst_src, $src" %} + format %{ "vxor_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1104,10 +1261,10 @@ instruct vxor_regI_masked(vReg dst_src, iRegIorL2I src, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vxor_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ +instruct vxorL_vx_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src (XorV (Binary dst_src (Replicate src)) v0)); - format %{ "vxor_regL_masked $dst_src, $dst_src, $src" %} + format %{ "vxorL_vx_masked $dst_src, $dst_src, $src, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vxor_vx(as_VectorRegister($dst_src$$reg), @@ -1121,16 +1278,38 @@ instruct vxor_regL_masked(vReg dst_src, iRegL src, vRegMask_V0 v0) %{ // vector and not +instruct vand_notB(vReg dst, vReg src1, vReg src2, immI_M1 m1) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_BYTE); + match(Set dst (AndV src1 (XorV src2 (Replicate m1)))); + format %{ "vand_notB $dst, $src1, $src2" %} + ins_encode %{ + __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); + __ vandn_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notS(vReg dst, vReg src1, vReg src2, immI_M1 m1) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst (AndV src1 (XorV src2 (Replicate m1)))); + format %{ "vand_notS $dst, $src1, $src2" %} + ins_encode %{ + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vandn_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + instruct vand_notI(vReg dst, vReg src1, vReg src2, immI_M1 m1) %{ - predicate(UseZvbb); - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_INT); match(Set dst (AndV src1 (XorV src2 (Replicate m1)))); format %{ "vand_notI $dst, $src1, $src2" %} ins_encode %{ - BasicType bt = Matcher::vector_element_basic_type(this); - __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vsetvli_helper(T_INT, Matcher::vector_length(this)); __ vandn_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg)); @@ -1139,8 +1318,7 @@ instruct vand_notI(vReg dst, vReg src1, vReg src2, immI_M1 m1) %{ %} instruct vand_notL(vReg dst, vReg src1, vReg src2, immL_M1 m1) %{ - predicate(UseZvbb); - predicate(Matcher::vector_element_basic_type(n) == T_LONG); + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst (AndV src1 (XorV src2 (Replicate m1)))); format %{ "vand_notL $dst, $src1, $src2" %} ins_encode %{ @@ -1152,16 +1330,40 @@ instruct vand_notL(vReg dst, vReg src1, vReg src2, immL_M1 m1) %{ ins_pipe(pipe_slow); %} +instruct vand_notB_masked(vReg dst_src1, vReg src2, immI_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_BYTE); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (Replicate m1))) v0)); + format %{ "vand_notB_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); + __ vandn_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notS_masked(vReg dst_src1, vReg src2, immI_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (Replicate m1))) v0)); + format %{ "vand_notS_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vandn_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + instruct vand_notI_masked(vReg dst_src1, vReg src2, immI_M1 m1, vRegMask_V0 v0) %{ - predicate(UseZvbb); - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_INT); match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (Replicate m1))) v0)); format %{ "vand_notI_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ - BasicType bt = Matcher::vector_element_basic_type(this); - __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vsetvli_helper(T_INT, Matcher::vector_length(this)); __ vandn_vv(as_VectorRegister($dst_src1$$reg), as_VectorRegister($dst_src1$$reg), as_VectorRegister($src2$$reg), @@ -1171,8 +1373,7 @@ instruct vand_notI_masked(vReg dst_src1, vReg src2, immI_M1 m1, vRegMask_V0 v0) %} instruct vand_notL_masked(vReg dst_src1, vReg src2, immL_M1 m1, vRegMask_V0 v0) %{ - predicate(UseZvbb); - predicate(Matcher::vector_element_basic_type(n) == T_LONG); + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst_src1 (AndV (Binary dst_src1 (XorV src2 (Replicate m1))) v0)); format %{ "vand_notL_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ @@ -1185,16 +1386,124 @@ instruct vand_notL_masked(vReg dst_src1, vReg src2, immL_M1 m1, vRegMask_V0 v0) ins_pipe(pipe_slow); %} +instruct vand_notB_vx(vReg dst, vReg src1, iRegIorL2I src2, immI_M1 m1) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_BYTE); + match(Set dst (AndV src1 (Replicate (XorI src2 m1)))); + format %{ "vand_notB_vx $dst, $src1, $src2" %} + ins_encode %{ + __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notS_vx(vReg dst, vReg src1, iRegIorL2I src2, immI_M1 m1) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst (AndV src1 (Replicate (XorI src2 m1)))); + format %{ "vand_notS_vx $dst, $src1, $src2" %} + ins_encode %{ + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notI_vx(vReg dst, vReg src1, iRegIorL2I src2, immI_M1 m1) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst (AndV src1 (Replicate (XorI src2 m1)))); + format %{ "vand_notI_vx $dst, $src1, $src2" %} + ins_encode %{ + __ vsetvli_helper(T_INT, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notL_vx(vReg dst, vReg src1, iRegL src2, immL_M1 m1) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_LONG); + match(Set dst (AndV src1 (Replicate (XorL src2 m1)))); + format %{ "vand_notL_vx $dst, $src1, $src2" %} + ins_encode %{ + __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_Register($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notB_vx_masked(vReg dst_src1, iRegIorL2I src2, immI_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_BYTE); + match(Set dst_src1 (AndV (Binary dst_src1 (Replicate (XorI src2 m1))) v0)); + format %{ "vand_notB_vx_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_Register($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notS_vx_masked(vReg dst_src1, iRegIorL2I src2, immI_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst_src1 (AndV (Binary dst_src1 (Replicate (XorI src2 m1))) v0)); + format %{ "vand_notS_vx_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_Register($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notI_vx_masked(vReg dst_src1, iRegIorL2I src2, immI_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_INT); + match(Set dst_src1 (AndV (Binary dst_src1 (Replicate (XorI src2 m1))) v0)); + format %{ "vand_notI_vx_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + __ vsetvli_helper(T_INT, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_Register($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vand_notL_vx_masked(vReg dst_src1, iRegL src2, immL_M1 m1, vRegMask_V0 v0) %{ + predicate(UseZvbb && Matcher::vector_element_basic_type(n) == T_LONG); + match(Set dst_src1 (AndV (Binary dst_src1 (Replicate (XorL src2 m1))) v0)); + format %{ "vand_notL_vx_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); + __ vandn_vx(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($dst_src1$$reg), + as_Register($src2$$reg), + Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + // ------------------------------ Vector not ----------------------------------- // vector not -instruct vnotI(vReg dst, vReg src, immI_M1 m1) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); +instruct vnot(vReg dst, vReg src, immI_M1 m1) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); match(Set dst (XorV src (Replicate m1))); - format %{ "vnotI $dst, $src" %} + format %{ "vnot $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1220,12 +1529,12 @@ instruct vnotL(vReg dst, vReg src, immL_M1 m1) %{ // vector not - predicated -instruct vnotI_masked(vReg dst_src, immI_M1 m1, vRegMask_V0 v0) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); +instruct vnot_masked(vReg dst_src, immI_M1 m1, vRegMask_V0 v0) %{ + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); match(Set dst_src (XorV (Binary dst_src (Replicate m1)) v0)); - format %{ "vnotI_masked $dst_src, $dst_src, $v0" %} + format %{ "vnot_masked $dst_src, $dst_src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1251,10 +1560,23 @@ instruct vnotL_masked(vReg dst_src, immI_M1 m1, vRegMask_V0 v0) %{ // vector float div +instruct vdiv_hfp(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (DivVHF src1 src2)); + format %{ "vdiv_hfp $dst, $src1, $src2" %} + ins_encode %{ + assert(UseZvfh, "must"); + assert(Matcher::vector_element_basic_type(this) == T_SHORT, "must"); + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vfdiv_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + instruct vdiv_fp(vReg dst, vReg src1, vReg src2) %{ match(Set dst (DivVF src1 src2)); match(Set dst (DivVD src1 src2)); - ins_cost(VEC_COST); format %{ "vdiv_fp $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1271,7 +1593,6 @@ instruct vdiv_fp(vReg dst, vReg src1, vReg src2) %{ instruct vdiv_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (DivVF (Binary dst_src1 src2) v0)); match(Set dst_src1 (DivVD (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vdiv_fp_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1289,7 +1610,6 @@ instruct vmax(vReg dst, vReg src1, vReg src2) %{ predicate(Matcher::vector_element_basic_type(n) != T_FLOAT && Matcher::vector_element_basic_type(n) != T_DOUBLE); match(Set dst (MaxV src1 src2)); - ins_cost(VEC_COST); format %{ "vmax $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1304,7 +1624,6 @@ instruct vmin(vReg dst, vReg src1, vReg src2) %{ predicate(Matcher::vector_element_basic_type(n) != T_FLOAT && Matcher::vector_element_basic_type(n) != T_DOUBLE); match(Set dst (MinV src1 src2)); - ins_cost(VEC_COST); format %{ "vmin $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1321,7 +1640,6 @@ instruct vmax_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) != T_FLOAT && Matcher::vector_element_basic_type(n) != T_DOUBLE); match(Set dst_src1 (MaxV (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vmax_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1336,7 +1654,6 @@ instruct vmin_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ predicate(Matcher::vector_element_basic_type(n) != T_FLOAT && Matcher::vector_element_basic_type(n) != T_DOUBLE); match(Set dst_src1 (MinV (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vmin_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1347,6 +1664,92 @@ instruct vmin_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} +// vector unsigned integer max/min + +instruct vmaxu(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (UMaxV src1 src2)); + format %{ "vmaxu $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmaxu_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vminu(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (UMinV src1 src2)); + format %{ "vminu $dst, $src1, $src2" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vminu_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector unsigned integer max/min - predicated + +instruct vmaxu_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ + match(Set dst_src1 (UMaxV (Binary dst_src1 src2) v0)); + format %{ "vmaxu_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vmaxu_vv(as_VectorRegister($dst_src1$$reg), as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vminu_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ + match(Set dst_src1 (UMinV (Binary dst_src1 src2) v0)); + format %{ "vminu_masked $dst_src1, $dst_src1, $src2, $v0" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + assert(is_integral_type(bt), "unsupported type"); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vminu_vv(as_VectorRegister($dst_src1$$reg), as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +// vector float-point max/min (half precision) + +instruct vmax_hfp(vReg dst, vReg src1, vReg src2, vRegMask_V0 v0) %{ + match(Set dst (MaxVHF src1 src2)); + effect(TEMP_DEF dst, TEMP v0); + format %{ "vmax_hfp $dst, $src1, $src2" %} + ins_encode %{ + assert(UseZvfh, "must"); + assert(Matcher::vector_element_basic_type(this) == T_SHORT, "must"); + __ minmax_fp_v(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg), + T_SHORT, false /* is_min */, Matcher::vector_length(this)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmin_hfp(vReg dst, vReg src1, vReg src2, vRegMask_V0 v0) %{ + match(Set dst (MinVHF src1 src2)); + effect(TEMP_DEF dst, TEMP v0); + format %{ "vmin_hfp $dst, $src1, $src2" %} + ins_encode %{ + assert(UseZvfh, "must"); + assert(Matcher::vector_element_basic_type(this) == T_SHORT, "must"); + __ minmax_fp_v(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg), + T_SHORT, true /* is_min */, Matcher::vector_length(this)); + %} + ins_pipe(pipe_slow); +%} + // vector float-point max/min instruct vmax_fp(vReg dst, vReg src1, vReg src2, vRegMask_V0 v0) %{ @@ -1354,7 +1757,6 @@ instruct vmax_fp(vReg dst, vReg src1, vReg src2, vRegMask_V0 v0) %{ Matcher::vector_element_basic_type(n) == T_DOUBLE); match(Set dst (MaxV src1 src2)); effect(TEMP_DEF dst, TEMP v0); - ins_cost(VEC_COST); format %{ "vmax_fp $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1370,7 +1772,6 @@ instruct vmin_fp(vReg dst, vReg src1, vReg src2, vRegMask_V0 v0) %{ Matcher::vector_element_basic_type(n) == T_DOUBLE); match(Set dst (MinV src1 src2)); effect(TEMP_DEF dst, TEMP v0); - ins_cost(VEC_COST); format %{ "vmin_fp $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1388,7 +1789,6 @@ instruct vmax_fp_masked(vReg dst_src1, vReg src2, vRegMask vmask, vReg tmp1, vRe Matcher::vector_element_basic_type(n) == T_DOUBLE); match(Set dst_src1 (MaxV (Binary dst_src1 src2) vmask)); effect(TEMP_DEF dst_src1, TEMP tmp1, TEMP tmp2, TEMP v0); - ins_cost(VEC_COST); format %{ "vmax_fp_masked $dst_src1, $dst_src1, $src2, $vmask\t# KILL $tmp1, $tmp2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1405,7 +1805,6 @@ instruct vmin_fp_masked(vReg dst_src1, vReg src2, vRegMask vmask, vReg tmp1, vRe Matcher::vector_element_basic_type(n) == T_DOUBLE); match(Set dst_src1 (MinV (Binary dst_src1 src2) vmask)); effect(TEMP_DEF dst_src1, TEMP tmp1, TEMP tmp2, TEMP v0); - ins_cost(VEC_COST); format %{ "vmin_fp_masked $dst_src1, $dst_src1, $src2, $vmask\t# KILL $tmp1, $tmp2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1419,11 +1818,25 @@ instruct vmin_fp_masked(vReg dst_src1, vReg src2, vRegMask vmask, vReg tmp1, vRe // vector fmla +// dst_src1 = src2 * src3 + dst_src1 (half precision) +instruct vhfmla(vReg dst_src1, vReg src2, vReg src3) %{ + match(Set dst_src1 (FmaVHF dst_src1 (Binary src2 src3))); + format %{ "vhfmla $dst_src1, $dst_src1, $src2, $src3" %} + ins_encode %{ + assert(UseFMA, "Needs FMA instructions support."); + assert(UseZvfh, "must"); + assert(Matcher::vector_element_basic_type(this) == T_SHORT, "must"); + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vfmacc_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + // dst_src1 = src2 * src3 + dst_src1 instruct vfmla(vReg dst_src1, vReg src2, vReg src3) %{ match(Set dst_src1 (FmaVF dst_src1 (Binary src2 src3))); match(Set dst_src1 (FmaVD dst_src1 (Binary src2 src3))); - ins_cost(VEC_COST); format %{ "vfmla $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ assert(UseFMA, "Needs FMA instructions support."); @@ -1458,7 +1871,6 @@ instruct vfmadd_masked(vReg dst_src1, vReg src2, vReg src3, vRegMask_V0 v0) %{ // "(-src2) * src3 + dst_src1" has been idealized to "src3 * (-src2) + dst_src1" instruct vfmlsF(vReg dst_src1, vReg src2, vReg src3) %{ match(Set dst_src1 (FmaVF dst_src1 (Binary src2 (NegVF src3)))); - ins_cost(VEC_COST); format %{ "vfmlsF $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ assert(UseFMA, "Needs FMA instructions support."); @@ -1473,7 +1885,6 @@ instruct vfmlsF(vReg dst_src1, vReg src2, vReg src3) %{ // "(-src2) * src3 + dst_src1" has been idealized to "src3 * (-src2) + dst_src1" instruct vfmlsD(vReg dst_src1, vReg src2, vReg src3) %{ match(Set dst_src1 (FmaVD dst_src1 (Binary src2 (NegVD src3)))); - ins_cost(VEC_COST); format %{ "vfmlsD $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ assert(UseFMA, "Needs FMA instructions support."); @@ -1507,7 +1918,6 @@ instruct vfnmsub_masked(vReg dst_src1, vReg src2, vReg src3, vRegMask_V0 v0) %{ // "(-src2) * src3 - dst_src1" has been idealized to "src3 * (-src2) - dst_src1" instruct vfnmlaF(vReg dst_src1, vReg src2, vReg src3) %{ match(Set dst_src1 (FmaVF (NegVF dst_src1) (Binary src2 (NegVF src3)))); - ins_cost(VEC_COST); format %{ "vfnmlaF $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ assert(UseFMA, "Needs FMA instructions support."); @@ -1522,7 +1932,6 @@ instruct vfnmlaF(vReg dst_src1, vReg src2, vReg src3) %{ // "(-src2) * src3 - dst_src1" has been idealized to "src3 * (-src2) - dst_src1" instruct vfnmlaD(vReg dst_src1, vReg src2, vReg src3) %{ match(Set dst_src1 (FmaVD (NegVD dst_src1) (Binary src2 (NegVD src3)))); - ins_cost(VEC_COST); format %{ "vfnmlaD $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ assert(UseFMA, "Needs FMA instructions support."); @@ -1555,7 +1964,6 @@ instruct vfnmadd_masked(vReg dst_src1, vReg src2, vReg src3, vRegMask_V0 v0) %{ // dst_src1 = src2 * src3 - dst_src1 instruct vfnmlsF(vReg dst_src1, vReg src2, vReg src3) %{ match(Set dst_src1 (FmaVF (NegVF dst_src1) (Binary src2 src3))); - ins_cost(VEC_COST); format %{ "vfnmlsF $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ assert(UseFMA, "Needs FMA instructions support."); @@ -1569,7 +1977,6 @@ instruct vfnmlsF(vReg dst_src1, vReg src2, vReg src3) %{ // dst_src1 = -dst_src1 + src2 * src3 instruct vfnmlsD(vReg dst_src1, vReg src2, vReg src3) %{ match(Set dst_src1 (FmaVD (NegVD dst_src1) (Binary src2 src3))); - ins_cost(VEC_COST); format %{ "vfnmlsD $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ assert(UseFMA, "Needs FMA instructions support."); @@ -1605,7 +2012,6 @@ instruct vmla(vReg dst_src1, vReg src2, vReg src3) %{ match(Set dst_src1 (AddVS dst_src1 (MulVS src2 src3))); match(Set dst_src1 (AddVI dst_src1 (MulVI src2 src3))); match(Set dst_src1 (AddVL dst_src1 (MulVL src2 src3))); - ins_cost(VEC_COST); format %{ "vmla $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1641,7 +2047,6 @@ instruct vmls(vReg dst_src1, vReg src2, vReg src3) %{ match(Set dst_src1 (SubVS dst_src1 (MulVS src2 src3))); match(Set dst_src1 (SubVI dst_src1 (MulVI src2 src3))); match(Set dst_src1 (SubVL dst_src1 (MulVL src2 src3))); - ins_cost(VEC_COST); format %{ "vmls $dst_src1, $dst_src1, $src2, $src3" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1676,7 +2081,6 @@ instruct vmul(vReg dst, vReg src1, vReg src2) %{ match(Set dst (MulVS src1 src2)); match(Set dst (MulVI src1 src2)); match(Set dst (MulVL src1 src2)); - ins_cost(VEC_COST); format %{ "vmul $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1687,10 +2091,22 @@ instruct vmul(vReg dst, vReg src1, vReg src2) %{ ins_pipe(pipe_slow); %} +instruct vmul_hfp(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (MulVHF src1 src2)); + format %{ "vmul_hfp $dst, $src1, $src2" %} + ins_encode %{ + assert(UseZvfh, "must"); + assert(Matcher::vector_element_basic_type(this) == T_SHORT, "must"); + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vfmul_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + instruct vmul_fp(vReg dst, vReg src1, vReg src2) %{ match(Set dst (MulVF src1 src2)); match(Set dst (MulVD src1 src2)); - ins_cost(VEC_COST); format %{ "vmul_fp $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1708,7 +2124,6 @@ instruct vmul_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (MulVS (Binary dst_src1 src2) v0)); match(Set dst_src1 (MulVI (Binary dst_src1 src2) v0)); match(Set dst_src1 (MulVL (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vmul_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1722,7 +2137,6 @@ instruct vmul_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ instruct vmul_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ match(Set dst_src1 (MulVF (Binary dst_src1 src2) v0)); match(Set dst_src1 (MulVD (Binary dst_src1 src2) v0)); - ins_cost(VEC_COST); format %{ "vmul_fp_masked $dst_src1, $dst_src1, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1735,11 +2149,11 @@ instruct vmul_fp_masked(vReg dst_src1, vReg src2, vRegMask_V0 v0) %{ // vector-scalar mul (unpredicated) -instruct vmul_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ +instruct vmul_vx(vReg dst, vReg src1, iRegIorL2I src2) %{ match(Set dst (MulVB src1 (Replicate src2))); match(Set dst (MulVS src1 (Replicate src2))); match(Set dst (MulVI src1 (Replicate src2))); - format %{ "vmul_regI $dst, $src1, $src2" %} + format %{ "vmul_vx $dst, $src1, $src2" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1750,9 +2164,9 @@ instruct vmul_regI(vReg dst, vReg src1, iRegIorL2I src2) %{ ins_pipe(pipe_slow); %} -instruct vmul_regL(vReg dst, vReg src1, iRegL src2) %{ +instruct vmulL_vx(vReg dst, vReg src1, iRegL src2) %{ match(Set dst (MulVL src1 (Replicate src2))); - format %{ "vmul_regL $dst, $src1, $src2" %} + format %{ "vmulL_vx $dst, $src1, $src2" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vmul_vx(as_VectorRegister($dst$$reg), @@ -1764,11 +2178,11 @@ instruct vmul_regL(vReg dst, vReg src1, iRegL src2) %{ // vector-scalar mul (predicated) -instruct vmul_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ +instruct vmul_vx_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ match(Set dst_src (MulVB (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (MulVS (Binary dst_src (Replicate src2)) v0)); match(Set dst_src (MulVI (Binary dst_src (Replicate src2)) v0)); - format %{ "vmul_regI_masked $dst_src, $dst_src, $src2" %} + format %{ "vmul_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -1779,9 +2193,9 @@ instruct vmul_regI_masked(vReg dst_src, iRegIorL2I src2, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vmul_regL_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ +instruct vmulL_vx_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ match(Set dst_src (MulVL (Binary dst_src (Replicate src2)) v0)); - format %{ "vmul_regL_masked $dst_src, $dst_src, $src2" %} + format %{ "vmulL_vx_masked $dst_src, $dst_src, $src2, $v0" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); __ vmul_vx(as_VectorRegister($dst_src$$reg), @@ -1796,7 +2210,6 @@ instruct vmul_regL_masked(vReg dst_src, iRegL src2, vRegMask_V0 v0) %{ instruct vneg(vReg dst, vReg src) %{ match(Set dst (NegVI src)); match(Set dst (NegVL src)); - ins_cost(VEC_COST); format %{ "vneg $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1811,7 +2224,6 @@ instruct vneg(vReg dst, vReg src) %{ instruct vneg_masked(vReg dst_src, vRegMask_V0 v0) %{ match(Set dst_src (NegVI dst_src v0)); match(Set dst_src (NegVL dst_src v0)); - ins_cost(VEC_COST); format %{ "vneg_masked $dst_src, $dst_src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1827,7 +2239,6 @@ instruct vneg_masked(vReg dst_src, vRegMask_V0 v0) %{ instruct vfneg(vReg dst, vReg src) %{ match(Set dst (NegVF src)); match(Set dst (NegVD src)); - ins_cost(VEC_COST); format %{ "vfneg $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1842,7 +2253,6 @@ instruct vfneg(vReg dst, vReg src) %{ instruct vfneg_masked(vReg dst_src, vRegMask_V0 v0) %{ match(Set dst_src (NegVF dst_src v0)); match(Set dst_src (NegVD dst_src v0)); - ins_cost(VEC_COST); format %{ "vfneg_masked $dst_src, $dst_src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -1855,14 +2265,13 @@ instruct vfneg_masked(vReg dst_src, vRegMask_V0 v0) %{ // vector and reduction -instruct reduce_andI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct reduce_and(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (AndReductionV src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "reduce_andI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "reduce_and $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -1876,7 +2285,6 @@ instruct reduce_andL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (AndReductionV src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_andL $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -1889,14 +2297,13 @@ instruct reduce_andL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector and reduction - predicated -instruct reduce_andI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct reduce_and_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (AndReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "reduce_andI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "reduce_and_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -1911,7 +2318,6 @@ instruct reduce_andL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0 predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (AndReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_andL_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -1925,14 +2331,13 @@ instruct reduce_andL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0 // vector or reduction -instruct reduce_orI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct reduce_or(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (OrReductionV src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "reduce_orI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "reduce_or $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -1946,7 +2351,6 @@ instruct reduce_orL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (OrReductionV src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_orL $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -1959,14 +2363,13 @@ instruct reduce_orL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector or reduction - predicated -instruct reduce_orI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct reduce_or_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (OrReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "reduce_orI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "reduce_or_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -1981,7 +2384,6 @@ instruct reduce_orL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0, predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (OrReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_orL_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -1995,14 +2397,13 @@ instruct reduce_orL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0, // vector xor reduction -instruct reduce_xorI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct reduce_xor(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (XorReductionV src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "reduce_xorI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "reduce_xor $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2016,7 +2417,6 @@ instruct reduce_xorL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (XorReductionV src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_xorL $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -2029,14 +2429,13 @@ instruct reduce_xorL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector xor reduction - predicated -instruct reduce_xorI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct reduce_xor_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (XorReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "reduce_xorI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "reduce_xor_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2051,7 +2450,6 @@ instruct reduce_xorL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0 predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (XorReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_xorL_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -2065,14 +2463,13 @@ instruct reduce_xorL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0 // vector add reduction -instruct reduce_addI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct reduce_add(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (AddReductionVI src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "reduce_addI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "reduce_add $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2086,7 +2483,6 @@ instruct reduce_addL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (AddReductionVL src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_addL $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -2109,7 +2505,6 @@ instruct reduce_addF_ordered(fRegF dst, fRegF src1, vReg src2, vReg tmp) %{ predicate(n->as_Reduction()->requires_strict_order()); match(Set dst (AddReductionVF src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_addF_ordered $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ __ vsetvli_helper(T_FLOAT, Matcher::vector_length(this, $src2)); @@ -2125,7 +2520,6 @@ instruct reduce_addF_unordered(fRegF dst, fRegF src1, vReg src2, vReg tmp) %{ predicate(!n->as_Reduction()->requires_strict_order()); match(Set dst (AddReductionVF src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_addF_unordered $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ __ vsetvli_helper(T_FLOAT, Matcher::vector_length(this, $src2)); @@ -2141,7 +2535,6 @@ instruct reduce_addD_ordered(fRegD dst, fRegD src1, vReg src2, vReg tmp) %{ predicate(n->as_Reduction()->requires_strict_order()); match(Set dst (AddReductionVD src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_addD_ordered $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ __ vsetvli_helper(T_DOUBLE, Matcher::vector_length(this, $src2)); @@ -2157,7 +2550,6 @@ instruct reduce_addD_unordered(fRegD dst, fRegD src1, vReg src2, vReg tmp) %{ predicate(!n->as_Reduction()->requires_strict_order()); match(Set dst (AddReductionVD src1 src2)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_addD_unordered $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ __ vsetvli_helper(T_DOUBLE, Matcher::vector_length(this, $src2)); @@ -2171,14 +2563,13 @@ instruct reduce_addD_unordered(fRegD dst, fRegD src1, vReg src2, vReg tmp) %{ // vector add reduction - predicated -instruct reduce_addI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct reduce_add_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (AddReductionVI (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "reduce_addI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "reduce_add_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2193,7 +2584,6 @@ instruct reduce_addL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0 predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (AddReductionVL (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_addL_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -2208,7 +2598,6 @@ instruct reduce_addL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v0 instruct reduce_addF_masked(fRegF dst, fRegF src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ match(Set dst (AddReductionVF (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_addF_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ __ vsetvli_helper(T_FLOAT, Matcher::vector_length(this, $src2)); @@ -2223,7 +2612,6 @@ instruct reduce_addF_masked(fRegF dst, fRegF src1, vReg src2, vRegMask_V0 v0, vR instruct reduce_addD_masked(fRegD dst, fRegD src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ match(Set dst (AddReductionVD (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "reduce_addD_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ __ vsetvli_helper(T_DOUBLE, Matcher::vector_length(this, $src2)); @@ -2237,14 +2625,13 @@ instruct reduce_addD_masked(fRegD dst, fRegD src1, vReg src2, vRegMask_V0 v0, vR // vector integer max reduction -instruct vreduce_maxI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct vreduce_max(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (MaxReductionV src1 src2)); - ins_cost(VEC_COST); effect(TEMP tmp); - format %{ "vreduce_maxI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "vreduce_max $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2257,7 +2644,6 @@ instruct vreduce_maxI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ instruct vreduce_maxL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (MaxReductionV src1 src2)); - ins_cost(VEC_COST); effect(TEMP tmp); format %{ "vreduce_maxL $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ @@ -2271,14 +2657,13 @@ instruct vreduce_maxL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector integer max reduction - predicated -instruct vreduce_maxI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct vreduce_max_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (MaxReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "vreduce_maxI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "vreduce_max_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2293,7 +2678,6 @@ instruct vreduce_maxL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (MaxReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "vreduce_maxL_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -2307,14 +2691,13 @@ instruct vreduce_maxL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v // vector integer min reduction -instruct vreduce_minI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ +instruct vreduce_min(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (MinReductionV src1 src2)); - ins_cost(VEC_COST); effect(TEMP tmp); - format %{ "vreduce_minI $dst, $src1, $src2\t# KILL $tmp" %} + format %{ "vreduce_min $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2327,7 +2710,6 @@ instruct vreduce_minI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ instruct vreduce_minL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (MinReductionV src1 src2)); - ins_cost(VEC_COST); effect(TEMP tmp); format %{ "vreduce_minL $dst, $src1, $src2\t# KILL $tmp" %} ins_encode %{ @@ -2341,14 +2723,13 @@ instruct vreduce_minL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ // vector integer min reduction - predicated -instruct vreduce_minI_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ +instruct vreduce_min_masked(iRegINoSp dst, iRegIorL2I src1, vReg src2, vRegMask_V0 v0, vReg tmp) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_BYTE || Matcher::vector_element_basic_type(n->in(2)) == T_SHORT || Matcher::vector_element_basic_type(n->in(2)) == T_INT); match(Set dst (MinReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); - format %{ "vreduce_minI_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} + format %{ "vreduce_min_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); __ reduce_integral_v($dst$$Register, $src1$$Register, @@ -2363,7 +2744,6 @@ instruct vreduce_minL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v predicate(Matcher::vector_element_basic_type(n->in(2)) == T_LONG); match(Set dst (MinReductionV (Binary src1 src2) v0)); effect(TEMP tmp); - ins_cost(VEC_COST); format %{ "vreduce_minL_masked $dst, $src1, $src2, $v0\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this, $src2); @@ -2380,7 +2760,6 @@ instruct vreduce_minL_masked(iRegLNoSp dst, iRegL src1, vReg src2, vRegMask_V0 v instruct vreduce_maxF(fRegF dst, fRegF src1, vReg src2, vReg tmp1, vReg tmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT); match(Set dst (MaxReductionV src1 src2)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); format %{ "vreduce_maxF $dst, $src1, $src2, $tmp1, $tmp2" %} ins_encode %{ @@ -2395,7 +2774,6 @@ instruct vreduce_maxF(fRegF dst, fRegF src1, vReg src2, vReg tmp1, vReg tmp2) %{ instruct vreduce_maxD(fRegD dst, fRegD src1, vReg src2, vReg tmp1, vReg tmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE); match(Set dst (MaxReductionV src1 src2)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); format %{ "vreduce_maxD $dst, $src1, $src2, $tmp1, $tmp2" %} ins_encode %{ @@ -2412,7 +2790,6 @@ instruct vreduce_maxD(fRegD dst, fRegD src1, vReg src2, vReg tmp1, vReg tmp2) %{ instruct vreduce_maxF_masked(fRegF dst, fRegF src1, vReg src2, vRegMask_V0 v0, vReg tmp1, vReg tmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT); match(Set dst (MaxReductionV (Binary src1 src2) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); format %{ "vreduce_maxF_masked $dst, $src1, $src2, $v0\t# KILL $tmp1, $tmp2" %} ins_encode %{ @@ -2428,7 +2805,6 @@ instruct vreduce_maxF_masked(fRegF dst, fRegF src1, vReg src2, vRegMask_V0 v0, v instruct vreduce_maxD_masked(fRegD dst, fRegD src1, vReg src2, vRegMask_V0 v0, vReg tmp1, vReg tmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE); match(Set dst (MaxReductionV (Binary src1 src2) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); format %{ "vreduce_maxD_masked $dst, $src1, $src2, $v0\t# KILL $tmp1, $tmp2" %} ins_encode %{ @@ -2446,7 +2822,6 @@ instruct vreduce_maxD_masked(fRegD dst, fRegD src1, vReg src2, vRegMask_V0 v0, v instruct vreduce_minF(fRegF dst, fRegF src1, vReg src2, vReg tmp1, vReg tmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT); match(Set dst (MinReductionV src1 src2)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); format %{ "vreduce_minF $dst, $src1, $src2, $tmp1, $tmp2" %} ins_encode %{ @@ -2461,7 +2836,6 @@ instruct vreduce_minF(fRegF dst, fRegF src1, vReg src2, vReg tmp1, vReg tmp2) %{ instruct vreduce_minD(fRegD dst, fRegD src1, vReg src2, vReg tmp1, vReg tmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE); match(Set dst (MinReductionV src1 src2)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); format %{ "vreduce_minD $dst, $src1, $src2, $tmp1, $tmp2" %} ins_encode %{ @@ -2478,7 +2852,6 @@ instruct vreduce_minD(fRegD dst, fRegD src1, vReg src2, vReg tmp1, vReg tmp2) %{ instruct vreduce_minF_masked(fRegF dst, fRegF src1, vReg src2, vRegMask_V0 v0, vReg tmp1, vReg tmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_FLOAT); match(Set dst (MinReductionV (Binary src1 src2) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); format %{ "vreduce_minF_masked $dst, $src1, $src2, $v0\t# KILL $tmp1, $tmp2" %} ins_encode %{ @@ -2494,7 +2867,6 @@ instruct vreduce_minF_masked(fRegF dst, fRegF src1, vReg src2, vRegMask_V0 v0, v instruct vreduce_minD_masked(fRegD dst, fRegD src1, vReg src2, vRegMask_V0 v0, vReg tmp1, vReg tmp2) %{ predicate(Matcher::vector_element_basic_type(n->in(2)) == T_DOUBLE); match(Set dst (MinReductionV (Binary src1 src2) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); format %{ "vreduce_minD_masked $dst, $src1, $src2, $v0\t# KILL $tmp1, $tmp2" %} ins_encode %{ @@ -2573,7 +2945,6 @@ instruct reduce_mulL_masked(iRegLNoSp dst, iRegL isrc, vReg vsrc, instruct replicate(vReg dst, iRegIorL2I src) %{ predicate(Matcher::is_non_long_integral_vector(n)); match(Set dst (Replicate src)); - ins_cost(VEC_COST); format %{ "replicate $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -2586,7 +2957,6 @@ instruct replicate(vReg dst, iRegIorL2I src) %{ instruct replicateL(vReg dst, iRegL src) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst (Replicate src)); - ins_cost(VEC_COST); format %{ "replicateL $dst, $src" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -2598,7 +2968,6 @@ instruct replicateL(vReg dst, iRegL src) %{ instruct replicate_imm5(vReg dst, immI5 con) %{ predicate(Matcher::is_non_long_integral_vector(n)); match(Set dst (Replicate con)); - ins_cost(VEC_COST); format %{ "replicate_imm5 $dst, $con" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -2611,7 +2980,6 @@ instruct replicate_imm5(vReg dst, immI5 con) %{ instruct replicateL_imm5(vReg dst, immL5 con) %{ predicate(Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst (Replicate con)); - ins_cost(VEC_COST); format %{ "replicateL_imm5 $dst, $con" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -2620,10 +2988,21 @@ instruct replicateL_imm5(vReg dst, immL5 con) %{ ins_pipe(pipe_slow); %} +instruct replicateHF(vReg dst, fRegF src) %{ + predicate(Matcher::vector_element_basic_type(n) == T_SHORT); + match(Set dst (Replicate src)); + format %{ "replicateHF $dst, $src" %} + ins_encode %{ + assert(UseZvfh, "must"); + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vfmv_v_f(as_VectorRegister($dst$$reg), $src$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + instruct replicateF(vReg dst, fRegF src) %{ predicate(Matcher::vector_element_basic_type(n) == T_FLOAT); match(Set dst (Replicate src)); - ins_cost(VEC_COST); format %{ "replicateF $dst, $src" %} ins_encode %{ __ vsetvli_helper(T_FLOAT, Matcher::vector_length(this)); @@ -2635,7 +3014,6 @@ instruct replicateF(vReg dst, fRegF src) %{ instruct replicateD(vReg dst, fRegD src) %{ predicate(Matcher::vector_element_basic_type(n) == T_DOUBLE); match(Set dst (Replicate src)); - ins_cost(VEC_COST); format %{ "replicateD $dst, $src" %} ins_encode %{ __ vsetvli_helper(T_DOUBLE, Matcher::vector_length(this)); @@ -2674,7 +3052,6 @@ instruct replicateD(vReg dst, fRegD src) %{ instruct vasrB(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ match(Set dst (RShiftVB src shift)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP v0); format %{ "vasrB $dst, $src, $shift" %} ins_encode %{ @@ -2693,7 +3070,6 @@ instruct vasrB(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ instruct vasrS(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ match(Set dst (RShiftVS src shift)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP v0); format %{ "vasrS $dst, $src, $shift" %} ins_encode %{ @@ -2712,7 +3088,6 @@ instruct vasrS(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ instruct vasrI(vReg dst, vReg src, vReg shift) %{ match(Set dst (RShiftVI src shift)); - ins_cost(VEC_COST); format %{ "vasrI $dst, $src, $shift" %} ins_encode %{ __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -2724,7 +3099,6 @@ instruct vasrI(vReg dst, vReg src, vReg shift) %{ instruct vasrL(vReg dst, vReg src, vReg shift) %{ match(Set dst (RShiftVL src shift)); - ins_cost(VEC_COST); format %{ "vasrL $dst, $src, $shift" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -2736,7 +3110,6 @@ instruct vasrL(vReg dst, vReg src, vReg shift) %{ instruct vasrB_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVB (Binary dst_src shift) vmask)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src, TEMP v0); format %{ "vasrB_masked $dst_src, $dst_src, $shift, $vmask\t# KILL $v0" %} ins_encode %{ @@ -2754,7 +3127,6 @@ instruct vasrB_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) instruct vasrS_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVS (Binary dst_src shift) vmask)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src, TEMP v0); format %{ "vasrS_masked $dst_src, $dst_src, $shift, $vmask\t# KILL $v0" %} ins_encode %{ @@ -2772,7 +3144,6 @@ instruct vasrS_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) instruct vasrI_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVI (Binary dst_src shift) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src); format %{ "vasrI_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ @@ -2785,7 +3156,6 @@ instruct vasrI_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ instruct vasrL_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVL (Binary dst_src shift) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src); format %{ "vasrL_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ @@ -2798,7 +3168,6 @@ instruct vasrL_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ instruct vlslB(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ match(Set dst (LShiftVB src shift)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP v0); format %{ "vlslB $dst, $src, $shift" %} ins_encode %{ @@ -2817,7 +3186,6 @@ instruct vlslB(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ instruct vlslS(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ match(Set dst (LShiftVS src shift)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP v0); format %{ "vlslS $dst, $src, $shift" %} ins_encode %{ @@ -2836,7 +3204,6 @@ instruct vlslS(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ instruct vlslI(vReg dst, vReg src, vReg shift) %{ match(Set dst (LShiftVI src shift)); - ins_cost(VEC_COST); format %{ "vlslI $dst, $src, $shift" %} ins_encode %{ __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -2848,7 +3215,6 @@ instruct vlslI(vReg dst, vReg src, vReg shift) %{ instruct vlslL(vReg dst, vReg src, vReg shift) %{ match(Set dst (LShiftVL src shift)); - ins_cost(VEC_COST); format %{ "vlslL $dst, $src, $shift" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -2860,7 +3226,6 @@ instruct vlslL(vReg dst, vReg src, vReg shift) %{ instruct vlslB_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVB (Binary dst_src shift) vmask)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src, TEMP v0); format %{ "vlslB_masked $dst_src, $dst_src, $shift, $vmask\t# KILL $v0" %} ins_encode %{ @@ -2881,7 +3246,6 @@ instruct vlslB_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) instruct vlslS_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVS (Binary dst_src shift) vmask)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src, TEMP v0); format %{ "vlslS_masked $dst_src, $dst_src, $shift, $vmask\t# KILL $v0" %} ins_encode %{ @@ -2902,7 +3266,6 @@ instruct vlslS_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) instruct vlslI_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVI (Binary dst_src shift) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src); format %{ "vlslI_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ @@ -2915,7 +3278,6 @@ instruct vlslI_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ instruct vlslL_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVL (Binary dst_src shift) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src); format %{ "vlslL_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ @@ -2928,7 +3290,6 @@ instruct vlslL_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ instruct vlsrB(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ match(Set dst (URShiftVB src shift)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP v0); format %{ "vlsrB $dst, $src, $shift" %} ins_encode %{ @@ -2947,7 +3308,6 @@ instruct vlsrB(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ instruct vlsrS(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ match(Set dst (URShiftVS src shift)); - ins_cost(VEC_COST); effect(TEMP_DEF dst, TEMP v0); format %{ "vlsrS $dst, $src, $shift" %} ins_encode %{ @@ -2966,7 +3326,6 @@ instruct vlsrS(vReg dst, vReg src, vReg shift, vRegMask_V0 v0) %{ instruct vlsrI(vReg dst, vReg src, vReg shift) %{ match(Set dst (URShiftVI src shift)); - ins_cost(VEC_COST); format %{ "vlsrI $dst, $src, $shift" %} ins_encode %{ __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -2978,7 +3337,6 @@ instruct vlsrI(vReg dst, vReg src, vReg shift) %{ instruct vlsrL(vReg dst, vReg src, vReg shift) %{ match(Set dst (URShiftVL src shift)); - ins_cost(VEC_COST); format %{ "vlsrL $dst, $src, $shift" %} ins_encode %{ __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -2990,7 +3348,6 @@ instruct vlsrL(vReg dst, vReg src, vReg shift) %{ instruct vlsrB_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVB (Binary dst_src shift) vmask)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src, TEMP v0); format %{ "vlsrB_masked $dst_src, $dst_src, $shift, $vmask\t# KILL $v0" %} ins_encode %{ @@ -3011,7 +3368,6 @@ instruct vlsrB_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) instruct vlsrS_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVS (Binary dst_src shift) vmask)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src, TEMP v0); format %{ "vlsrS_masked $dst_src, $dst_src, $shift, $vmask\t# KILL $v0" %} ins_encode %{ @@ -3032,7 +3388,6 @@ instruct vlsrS_masked(vReg dst_src, vReg shift, vRegMask vmask, vRegMask_V0 v0) instruct vlsrI_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVI (Binary dst_src shift) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src); format %{ "vlsrI_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ @@ -3045,7 +3400,6 @@ instruct vlsrI_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ instruct vlsrL_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVL (Binary dst_src shift) v0)); - ins_cost(VEC_COST); effect(TEMP_DEF dst_src); format %{ "vlsrL_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ @@ -3056,10 +3410,9 @@ instruct vlsrL_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vasrB_imm(vReg dst, vReg src, immI shift) %{ +instruct vasrB_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RShiftVB src (RShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vasrB_imm $dst, $src, $shift" %} + format %{ "vasrB_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); @@ -3074,10 +3427,9 @@ instruct vasrB_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vasrS_imm(vReg dst, vReg src, immI shift) %{ +instruct vasrS_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RShiftVS src (RShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vasrS_imm $dst, $src, $shift" %} + format %{ "vasrS_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); @@ -3092,10 +3444,9 @@ instruct vasrS_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vasrI_imm(vReg dst, vReg src, immI shift) %{ +instruct vasrI_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RShiftVI src (RShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vasrI_imm $dst, $src, $shift" %} + format %{ "vasrI_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -3109,11 +3460,10 @@ instruct vasrI_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vasrL_imm(vReg dst, vReg src, immI shift) %{ +instruct vasrL_vi(vReg dst, vReg src, immI shift) %{ predicate((n->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst (RShiftVL src (RShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vasrL_imm $dst, $src, $shift" %} + format %{ "vasrL_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -3127,10 +3477,9 @@ instruct vasrL_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vasrB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vasrB_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVB (Binary dst_src (RShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vasrB_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vasrB_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3144,10 +3493,9 @@ instruct vasrB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vasrS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vasrS_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVS (Binary dst_src (RShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vasrS_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vasrS_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3161,10 +3509,9 @@ instruct vasrS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vasrI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vasrI_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RShiftVI (Binary dst_src (RShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vasrI_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vasrI_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3177,11 +3524,10 @@ instruct vasrI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vasrL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vasrL_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ predicate((n->in(1)->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst_src (RShiftVL (Binary dst_src (RShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vasrL_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vasrL_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3194,10 +3540,9 @@ instruct vasrL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlsrB_imm(vReg dst, vReg src, immI shift) %{ +instruct vlsrB_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (URShiftVB src (RShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vlsrB_imm $dst, $src, $shift" %} + format %{ "vlsrB_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); @@ -3216,10 +3561,9 @@ instruct vlsrB_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlsrS_imm(vReg dst, vReg src, immI shift) %{ +instruct vlsrS_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (URShiftVS src (RShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vlsrS_imm $dst, $src, $shift" %} + format %{ "vlsrS_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); @@ -3238,10 +3582,9 @@ instruct vlsrS_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlsrI_imm(vReg dst, vReg src, immI shift) %{ +instruct vlsrI_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (URShiftVI src (RShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vlsrI_imm $dst, $src, $shift" %} + format %{ "vlsrI_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -3255,11 +3598,10 @@ instruct vlsrI_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlsrL_imm(vReg dst, vReg src, immI shift) %{ +instruct vlsrL_vi(vReg dst, vReg src, immI shift) %{ predicate((n->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst (URShiftVL src (RShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vlsrL_imm $dst, $src, $shift" %} + format %{ "vlsrL_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -3273,10 +3615,9 @@ instruct vlsrL_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlsrB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlsrB_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVB (Binary dst_src (RShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vlsrB_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlsrB_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3294,10 +3635,9 @@ instruct vlsrB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlsrS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlsrS_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVS (Binary dst_src (RShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vlsrS_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlsrS_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3315,10 +3655,9 @@ instruct vlsrS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlsrI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlsrI_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (URShiftVI (Binary dst_src (RShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vlsrI_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlsrI_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3331,11 +3670,10 @@ instruct vlsrI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlsrL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlsrL_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ predicate((n->in(1)->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst_src (URShiftVL (Binary dst_src (RShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vlsrL_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlsrL_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; if (con == 0) { @@ -3348,10 +3686,9 @@ instruct vlsrL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlslB_imm(vReg dst, vReg src, immI shift) %{ +instruct vlslB_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (LShiftVB src (LShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vlslB_imm $dst, $src, $shift" %} + format %{ "vlslB_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); @@ -3365,10 +3702,9 @@ instruct vlslB_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlslS_imm(vReg dst, vReg src, immI shift) %{ +instruct vlslS_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (LShiftVS src (LShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vlslS_imm $dst, $src, $shift" %} + format %{ "vlslS_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); @@ -3382,10 +3718,9 @@ instruct vlslS_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlslI_imm(vReg dst, vReg src, immI shift) %{ +instruct vlslI_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (LShiftVI src (LShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vlslI_imm $dst, $src, $shift" %} + format %{ "vlslI_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -3394,11 +3729,10 @@ instruct vlslI_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlslL_imm(vReg dst, vReg src, immI shift) %{ +instruct vlslL_vi(vReg dst, vReg src, immI shift) %{ predicate((n->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst (LShiftVL src (LShiftCntV shift))); - ins_cost(VEC_COST); - format %{ "vlslL_imm $dst, $src, $shift" %} + format %{ "vlslL_vi $dst, $src, $shift" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -3407,10 +3741,9 @@ instruct vlslL_imm(vReg dst, vReg src, immI shift) %{ ins_pipe(pipe_slow); %} -instruct vlslB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlslB_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVB (Binary dst_src (LShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vlslB_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlslB_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_BYTE, Matcher::vector_length(this)); @@ -3425,10 +3758,9 @@ instruct vlslB_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlslS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlslS_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVS (Binary dst_src (LShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vlslS_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlslS_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); @@ -3443,10 +3775,9 @@ instruct vlslS_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlslI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlslI_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (LShiftVI (Binary dst_src (LShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vlslI_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlslI_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_INT, Matcher::vector_length(this)); @@ -3456,11 +3787,10 @@ instruct vlslI_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vlslL_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vlslL_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ predicate((n->in(1)->in(2)->in(1)->get_int() & 0x3f) < 32); match(Set dst_src (LShiftVL (Binary dst_src (LShiftCntV shift)) v0)); - ins_cost(VEC_COST); - format %{ "vlslL_imm_masked $dst_src, $dst_src, $shift, $v0" %} + format %{ "vlslL_vi_masked $dst_src, $dst_src, $shift, $v0" %} ins_encode %{ uint32_t con = (unsigned)$shift$$constant & 0x1f; __ vsetvli_helper(T_LONG, Matcher::vector_length(this)); @@ -3499,9 +3829,10 @@ instruct vrotate_right(vReg dst, vReg src, vReg shift) %{ ins_pipe(pipe_slow); %} -instruct vrotate_right_reg(vReg dst, vReg src, iRegIorL2I shift) %{ +// Only the low log2(SEW) bits of shift value are used, all other bits are ignored. +instruct vrotate_right_vx(vReg dst, vReg src, iRegIorL2I shift) %{ match(Set dst (RotateRightV src (Replicate shift))); - format %{ "vrotate_right_reg $dst, $src, $shift\t" %} + format %{ "vrotate_right_vx $dst, $src, $shift\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3511,9 +3842,9 @@ instruct vrotate_right_reg(vReg dst, vReg src, iRegIorL2I shift) %{ ins_pipe(pipe_slow); %} -instruct vrotate_right_imm(vReg dst, vReg src, immI shift) %{ +instruct vrotate_right_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RotateRightV src shift)); - format %{ "vrotate_right_imm $dst, $src, $shift\t" %} + format %{ "vrotate_right_vi $dst, $src, $shift\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); uint32_t bits = type2aelembytes(bt) * 8; @@ -3531,7 +3862,7 @@ instruct vrotate_right_imm(vReg dst, vReg src, immI shift) %{ instruct vrotate_right_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateRightV (Binary dst_src shift) v0)); - format %{ "vrotate_right_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_right_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3541,9 +3872,10 @@ instruct vrotate_right_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vrotate_right_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ +// Only the low log2(SEW) bits of shift value are used, all other bits are ignored. +instruct vrotate_right_vx_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateRightV (Binary dst_src (Replicate shift)) v0)); - format %{ "vrotate_right_reg_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_right_vx_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3553,9 +3885,9 @@ instruct vrotate_right_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0 ins_pipe(pipe_slow); %} -instruct vrotate_right_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vrotate_right_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateRightV (Binary dst_src shift) v0)); - format %{ "vrotate_right_imm_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_right_vi_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); uint32_t bits = type2aelembytes(bt) * 8; @@ -3584,9 +3916,10 @@ instruct vrotate_left(vReg dst, vReg src, vReg shift) %{ ins_pipe(pipe_slow); %} -instruct vrotate_left_reg(vReg dst, vReg src, iRegIorL2I shift) %{ +// Only the low log2(SEW) bits of shift value are used, all other bits are ignored. +instruct vrotate_left_vx(vReg dst, vReg src, iRegIorL2I shift) %{ match(Set dst (RotateLeftV src (Replicate shift))); - format %{ "vrotate_left_reg $dst, $src, $shift\t" %} + format %{ "vrotate_left_vx $dst, $src, $shift\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3596,9 +3929,9 @@ instruct vrotate_left_reg(vReg dst, vReg src, iRegIorL2I shift) %{ ins_pipe(pipe_slow); %} -instruct vrotate_left_imm(vReg dst, vReg src, immI shift) %{ +instruct vrotate_left_vi(vReg dst, vReg src, immI shift) %{ match(Set dst (RotateLeftV src shift)); - format %{ "vrotate_left_imm $dst, $src, $shift\t" %} + format %{ "vrotate_left_vi $dst, $src, $shift\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); uint32_t bits = type2aelembytes(bt) * 8; @@ -3617,7 +3950,7 @@ instruct vrotate_left_imm(vReg dst, vReg src, immI shift) %{ instruct vrotate_left_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateLeftV (Binary dst_src shift) v0)); - format %{ "vrotate_left_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_left_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3627,9 +3960,10 @@ instruct vrotate_left_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ ins_pipe(pipe_slow); %} -instruct vrotate_left_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ +// Only the low log2(SEW) bits of shift value are used, all other bits are ignored. +instruct vrotate_left_vx_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateLeftV (Binary dst_src (Replicate shift)) v0)); - format %{ "vrotate_left_reg_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_left_vx_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -3639,9 +3973,9 @@ instruct vrotate_left_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) ins_pipe(pipe_slow); %} -instruct vrotate_left_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ +instruct vrotate_left_vi_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ match(Set dst_src (RotateLeftV (Binary dst_src shift) v0)); - format %{ "vrotate_left_imm_masked $dst_src, $dst_src, $shift, v0.t\t" %} + format %{ "vrotate_left_vi_masked $dst_src, $dst_src, $shift, $v0\t" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); uint32_t bits = type2aelembytes(bt) * 8; @@ -3659,10 +3993,21 @@ instruct vrotate_left_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ // vector sqrt +instruct vsqrt_hfp(vReg dst, vReg src) %{ + match(Set dst (SqrtVHF src)); + format %{ "vsqrt_hfp $dst, $src" %} + ins_encode %{ + assert(UseZvfh, "must"); + assert(Matcher::vector_element_basic_type(this) == T_SHORT, "must"); + __ vsetvli_helper(T_SHORT, Matcher::vector_length(this)); + __ vfsqrt_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + instruct vsqrt_fp(vReg dst, vReg src) %{ match(Set dst (SqrtVF src)); match(Set dst (SqrtVD src)); - ins_cost(VEC_COST); format %{ "vsqrt_fp $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -3677,7 +4022,6 @@ instruct vsqrt_fp(vReg dst, vReg src) %{ instruct vsqrt_fp_masked(vReg dst_src, vRegMask_V0 v0) %{ match(Set dst_src (SqrtVF dst_src v0)); match(Set dst_src (SqrtVD dst_src v0)); - ins_cost(VEC_COST); format %{ "vsqrt_fp_masked $dst_src, $dst_src, $v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -3976,7 +4320,6 @@ instruct vclearArray_reg_reg(iRegL_R29 cnt, iRegP_R28 base, Universe dummy, // Vector Load Const instruct vloadcon(vReg dst, immI0 src) %{ match(Set dst (VectorLoadConst src)); - ins_cost(VEC_COST); format %{ "vloadcon $dst\t# generate iota indices" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -4237,8 +4580,8 @@ instruct vcvtStoB(vReg dst, vReg src) %{ %} instruct vcvtStoX(vReg dst, vReg src) %{ - predicate((Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_LONG)); + predicate(Matcher::vector_element_basic_type(n) == T_INT || + Matcher::vector_element_basic_type(n) == T_LONG); match(Set dst (VectorCastS2X src)); effect(TEMP_DEF dst); format %{ "vcvtStoX $dst, $src" %} @@ -4251,8 +4594,8 @@ instruct vcvtStoX(vReg dst, vReg src) %{ %} instruct vcvtStoX_fp(vReg dst, vReg src) %{ - predicate((Matcher::vector_element_basic_type(n) == T_FLOAT || - Matcher::vector_element_basic_type(n) == T_DOUBLE)); + predicate(Matcher::vector_element_basic_type(n) == T_FLOAT || + Matcher::vector_element_basic_type(n) == T_DOUBLE); match(Set dst (VectorCastS2X src)); effect(TEMP_DEF dst); format %{ "vcvtStoX_fp $dst, $src" %} @@ -4349,9 +4692,9 @@ instruct vcvtItoD(vReg dst, vReg src) %{ // VectorCastL2X instruct vcvtLtoI(vReg dst, vReg src) %{ - predicate(Matcher::vector_element_basic_type(n) == T_INT || - Matcher::vector_element_basic_type(n) == T_BYTE || - Matcher::vector_element_basic_type(n) == T_SHORT); + predicate(Matcher::vector_element_basic_type(n) == T_BYTE || + Matcher::vector_element_basic_type(n) == T_SHORT || + Matcher::vector_element_basic_type(n) == T_INT); match(Set dst (VectorCastL2X src)); format %{ "vcvtLtoI $dst, $src" %} ins_encode %{ @@ -4845,7 +5188,6 @@ instruct vconvF2HF(vReg dst, vReg src, vReg vtmp, vRegMask_V0 v0, iRegINoSp tmp) instruct vpopcount_masked(vReg dst_src, vRegMask_V0 v0) %{ match(Set dst_src (PopCountVI dst_src v0)); match(Set dst_src (PopCountVL dst_src v0)); - ins_cost(VEC_COST); format %{ "vcpop_v $dst_src, $dst_src, $v0\t# vcpop_v with mask" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -4859,7 +5201,6 @@ instruct vpopcount_masked(vReg dst_src, vRegMask_V0 v0) %{ instruct vpopcount(vReg dst, vReg src) %{ match(Set dst (PopCountVI src)); match(Set dst (PopCountVL src)); - ins_cost(VEC_COST); format %{ "vcpop_v $dst, $src\t# vcpop_v without mask" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -4874,7 +5215,6 @@ instruct vpopcount(vReg dst, vReg src) %{ instruct vcountLeadingZeros_masked(vReg dst_src, vRegMask_V0 v0) %{ match(Set dst_src (CountLeadingZerosV dst_src v0)); - ins_cost(VEC_COST); format %{ "vcount_leading_zeros_masked $dst_src, $dst_src, v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -4887,7 +5227,6 @@ instruct vcountLeadingZeros_masked(vReg dst_src, vRegMask_V0 v0) %{ instruct vcountLeadingZeros(vReg dst, vReg src) %{ match(Set dst (CountLeadingZerosV src)); - ins_cost(VEC_COST); format %{ "vcount_leading_zeros $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -4902,7 +5241,6 @@ instruct vcountLeadingZeros(vReg dst, vReg src) %{ instruct vcountTrailingZeros_masked(vReg dst_src, vRegMask_V0 v0) %{ match(Set dst_src (CountTrailingZerosV dst_src v0)); - ins_cost(VEC_COST); format %{ "vcount_trailing_zeros_masked $dst_src, $dst_src, v0" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -4915,7 +5253,6 @@ instruct vcountTrailingZeros_masked(vReg dst_src, vRegMask_V0 v0) %{ instruct vcountTrailingZeros(vReg dst, vReg src) %{ match(Set dst (CountTrailingZerosV src)); - ins_cost(VEC_COST); format %{ "vcount_trailing_zeros $dst, $src" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); @@ -5087,14 +5424,14 @@ instruct populateindex(vReg dst, iRegIorL2I src1, iRegIorL2I src2, vReg tmp) %{ // BYTE, SHORT, INT -instruct insertI_index_lt32(vReg dst, vReg src, iRegIorL2I val, immI idx, vRegMask_V0 v0) %{ +instruct insert_index_lt32(vReg dst, vReg src, iRegIorL2I val, immI idx, vRegMask_V0 v0) %{ predicate(n->in(2)->get_int() < 32 && (Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT || Matcher::vector_element_basic_type(n) == T_INT)); match(Set dst (VectorInsert (Binary src val) idx)); effect(TEMP v0); - format %{ "insertI_index_lt32 $dst, $src, $val, $idx" %} + format %{ "insert_index_lt32 $dst, $src, $val, $idx" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); @@ -5106,14 +5443,14 @@ instruct insertI_index_lt32(vReg dst, vReg src, iRegIorL2I val, immI idx, vRegMa ins_pipe(pipe_slow); %} -instruct insertI_index(vReg dst, vReg src, iRegIorL2I val, iRegIorL2I idx, vReg tmp, vRegMask_V0 v0) %{ +instruct insert_index(vReg dst, vReg src, iRegIorL2I val, iRegIorL2I idx, vReg tmp, vRegMask_V0 v0) %{ predicate(n->in(2)->get_int() >= 32 && (Matcher::vector_element_basic_type(n) == T_BYTE || Matcher::vector_element_basic_type(n) == T_SHORT || Matcher::vector_element_basic_type(n) == T_INT)); match(Set dst (VectorInsert (Binary src val) idx)); effect(TEMP tmp, TEMP v0); - format %{ "insertI_index $dst, $src, $val, $idx\t# KILL $tmp" %} + format %{ "insert_index $dst, $src, $val, $idx\t# KILL $tmp" %} ins_encode %{ BasicType bt = Matcher::vector_element_basic_type(this); __ vsetvli_helper(bt, Matcher::vector_length(this)); diff --git a/src/hotspot/cpu/riscv/runtime_riscv.cpp b/src/hotspot/cpu/riscv/runtime_riscv.cpp index 44a8e35e285..7c8ca853bc4 100644 --- a/src/hotspot/cpu/riscv/runtime_riscv.cpp +++ b/src/hotspot/cpu/riscv/runtime_riscv.cpp @@ -63,6 +63,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); assert_cond(masm != nullptr); @@ -282,6 +285,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); assert_cond(masm != nullptr); diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 10790841490..391be81c1ae 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -596,12 +596,13 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, } // --------------------------------------------------------------- -AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs, - AdapterFingerPrint* fingerprint) { + +void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + AdapterHandlerEntry* handler) { address i2c_entry = __ pc(); gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); @@ -658,7 +659,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); - return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); + handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); + return; } int SharedRuntime::vector_calling_convention(VMRegPair *regs, @@ -1323,7 +1325,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // First instruction must be a nop as it may need to be patched on deoptimisation { - Assembler::IncompressibleRegion ir(masm); // keep the nop as 4 bytes for patching. + Assembler::IncompressibleScope scope(masm); // keep the nop as 4 bytes for patching. MacroAssembler::assert_alignment(__ pc()); __ nop(); // 4 bytes } @@ -1466,7 +1468,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // If we have to make this method not-entrant we'll overwrite its // first instruction with a jump. { - Assembler::IncompressibleRegion ir(masm); // keep the nop as 4 bytes for patching. + Assembler::IncompressibleScope scope(masm); // keep the nop as 4 bytes for patching. MacroAssembler::assert_alignment(__ pc()); __ nop(); // 4 bytes } @@ -1892,6 +1894,24 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ leave(); + #if INCLUDE_JFR + // We need to do a poll test after unwind in case the sampler + // managed to sample the native frame after returning to Java. + Label L_return; + __ ld(t0, Address(xthread, JavaThread::polling_word_offset())); + address poll_test_pc = __ pc(); + __ relocate(relocInfo::poll_return_type); + __ test_bit(t0, t0, log2i_exact(SafepointMechanism::poll_bit())); + __ beqz(t0, L_return); + assert(SharedRuntime::polling_page_return_handler_blob() != nullptr, + "polling page return stub not created yet"); + address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point(); + __ la(t0, InternalAddress(poll_test_pc)); + __ sd(t0, Address(xthread, JavaThread::saved_exception_pc_offset())); + __ far_jump(RuntimeAddress(stub)); + __ bind(L_return); +#endif // INCLUDE_JFR + // Any exception pending? Label exception_pending; __ ld(t0, Address(xthread, in_bytes(Thread::pending_exception_offset()))); diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 4527a32926f..c58f6bc338d 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2025, Red Hat Inc. All rights reserved. - * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2025, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -886,7 +886,7 @@ class StubGenerator: public StubCodeGenerator { void copy_memory_v(Register s, Register d, Register count, int step) { bool is_backward = step < 0; - int granularity = uabs(step); + int granularity = g_uabs(step); const Register src = x30, dst = x31, vl = x14, cnt = x15, tmp1 = x16, tmp2 = x17; assert_different_registers(s, d, cnt, vl, tmp1, tmp2); @@ -948,7 +948,7 @@ class StubGenerator: public StubCodeGenerator { } bool is_backwards = step < 0; - int granularity = uabs(step); + int granularity = g_uabs(step); const Register src = x30, dst = x31, cnt = x15, tmp3 = x16, tmp4 = x17, tmp5 = x14, tmp6 = x13; const Register gct1 = x28, gct2 = x29, gct3 = t2; @@ -1633,6 +1633,126 @@ class StubGenerator: public StubCodeGenerator { BLOCK_COMMENT("arraycopy_range_checks done"); } + address generate_unsafecopy_common_error_exit() { + address start = __ pc(); + __ mv(x10, 0); + __ leave(); + __ ret(); + return start; + } + + // + // Generate 'unsafe' set memory stub + // Though just as safe as the other stubs, it takes an unscaled + // size_t (# bytes) argument instead of an element count. + // + // Input: + // c_rarg0 - destination array address + // c_rarg1 - byte count (size_t) + // c_rarg2 - byte value + // + address generate_unsafe_setmemory() { + __ align(CodeEntryAlignment); + StubGenStubId stub_id = StubGenStubId::unsafe_setmemory_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + + // bump this on entry, not on exit: + // inc_counter_np(SharedRuntime::_unsafe_set_memory_ctr); + + Label L_fill_elements; + + const Register dest = c_rarg0; + const Register count = c_rarg1; + const Register value = c_rarg2; + const Register cnt_words = x28; // temp register + const Register tmp_reg = x29; // temp register + + // Mark remaining code as such which performs Unsafe accesses. + UnsafeMemoryAccessMark umam(this, true, false); + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // if count < 8, jump to L_fill_elements + __ mv(tmp_reg, 8); // 8 bytes fill by element + __ bltu(count, tmp_reg, L_fill_elements); + + // Propagate byte to 64-bit width + // 8 bit -> 16 bit + __ zext(value, value, 8); + __ slli(tmp_reg, value, 8); + __ orr(value, value, tmp_reg); + // 16 bit -> 32 bit + __ slli(tmp_reg, value, 16); + __ orr(value, value, tmp_reg); + // 32 bit -> 64 bit + __ slli(tmp_reg, value, 32); + __ orr(value, value, tmp_reg); + + // Align source address at 8 bytes address boundary. + Label L_skip_align1, L_skip_align2, L_skip_align4; + // One byte misalignment happens. + __ test_bit(tmp_reg, dest, 0); + __ beqz(tmp_reg, L_skip_align1); + __ sb(value, Address(dest, 0)); + __ addi(dest, dest, 1); + __ subi(count, count, 1); + + __ bind(L_skip_align1); + // Two bytes misalignment happens. + __ test_bit(tmp_reg, dest, 1); + __ beqz(tmp_reg, L_skip_align2); + __ sh(value, Address(dest, 0)); + __ addi(dest, dest, 2); + __ subi(count, count, 2); + + __ bind(L_skip_align2); + // Four bytes misalignment happens. + __ test_bit(tmp_reg, dest, 2); + __ beqz(tmp_reg, L_skip_align4); + __ sw(value, Address(dest, 0)); + __ addi(dest, dest, 4); + __ subi(count, count, 4); + __ bind(L_skip_align4); + + // Fill large chunks + __ srli(cnt_words, count, 3); // number of words + __ slli(tmp_reg, cnt_words, 3); + __ sub(count, count, tmp_reg); + { + __ fill_words(dest, cnt_words, value); + } + + // Handle copies less than 8 bytes + __ bind(L_fill_elements); + Label L_fill_2, L_fill_1, L_exit; + __ test_bit(tmp_reg, count, 2); + __ beqz(tmp_reg, L_fill_2); + __ sb(value, Address(dest, 0)); + __ sb(value, Address(dest, 1)); + __ sb(value, Address(dest, 2)); + __ sb(value, Address(dest, 3)); + __ addi(dest, dest, 4); + + __ bind(L_fill_2); + __ test_bit(tmp_reg, count, 1); + __ beqz(tmp_reg, L_fill_1); + __ sb(value, Address(dest, 0)); + __ sb(value, Address(dest, 1)); + __ addi(dest, dest, 2); + + __ bind(L_fill_1); + __ test_bit(tmp_reg, count, 0); + __ beqz(tmp_reg, L_exit); + __ sb(value, Address(dest, 0)); + + __ bind(L_exit); + __ leave(); + __ ret(); + + return start; + } + // // Generate 'unsafe' array copy stub // Though just as safe as the other stubs, it takes an unscaled @@ -2029,44 +2149,40 @@ class StubGenerator: public StubCodeGenerator { __ enter(); - Label L_fill_elements, L_exit1; + Label L_fill_elements; int shift = -1; switch (t) { case T_BYTE: shift = 0; + // Short arrays (< 8 bytes) fill by element + __ mv(tmp_reg, 8 >> shift); + __ bltu(count, tmp_reg, L_fill_elements); // Zero extend value // 8 bit -> 16 bit __ zext(value, value, 8); - __ mv(tmp_reg, value); - __ slli(tmp_reg, tmp_reg, 8); + __ slli(tmp_reg, value, 8); __ orr(value, value, tmp_reg); // 16 bit -> 32 bit - __ mv(tmp_reg, value); - __ slli(tmp_reg, tmp_reg, 16); + __ slli(tmp_reg, value, 16); __ orr(value, value, tmp_reg); - - __ mv(tmp_reg, 8 >> shift); // Short arrays (< 8 bytes) fill by element - __ bltu(count, tmp_reg, L_fill_elements); break; case T_SHORT: shift = 1; + // Short arrays (< 8 bytes) fill by element + __ mv(tmp_reg, 8 >> shift); + __ bltu(count, tmp_reg, L_fill_elements); + // Zero extend value // 16 bit -> 32 bit __ zext(value, value, 16); - __ mv(tmp_reg, value); - __ slli(tmp_reg, tmp_reg, 16); + __ slli(tmp_reg, value, 16); __ orr(value, value, tmp_reg); - - // Short arrays (< 8 bytes) fill by element - __ mv(tmp_reg, 8 >> shift); - __ bltu(count, tmp_reg, L_fill_elements); break; case T_INT: shift = 2; - // Short arrays (< 8 bytes) fill by element __ mv(tmp_reg, 8 >> shift); __ bltu(count, tmp_reg, L_fill_elements); @@ -2080,8 +2196,8 @@ class StubGenerator: public StubCodeGenerator { switch (t) { case T_BYTE: // One byte misalignment happens only for byte arrays. - __ test_bit(t0, to, 0); - __ beqz(t0, L_skip_align1); + __ test_bit(tmp_reg, to, 0); + __ beqz(tmp_reg, L_skip_align1); __ sb(value, Address(to, 0)); __ addi(to, to, 1); __ subiw(count, count, 1); @@ -2089,8 +2205,8 @@ class StubGenerator: public StubCodeGenerator { // Fallthrough case T_SHORT: // Two bytes misalignment happens only for byte and short (char) arrays. - __ test_bit(t0, to, 1); - __ beqz(t0, L_skip_align2); + __ test_bit(tmp_reg, to, 1); + __ beqz(tmp_reg, L_skip_align2); __ sh(value, Address(to, 0)); __ addi(to, to, 2); __ subiw(count, count, 2 >> shift); @@ -2098,8 +2214,8 @@ class StubGenerator: public StubCodeGenerator { // Fallthrough case T_INT: // Align to 8 bytes, we know we are 4 byte aligned to start. - __ test_bit(t0, to, 2); - __ beqz(t0, L_skip_align4); + __ test_bit(tmp_reg, to, 2); + __ beqz(tmp_reg, L_skip_align4); __ sw(value, Address(to, 0)); __ addi(to, to, 4); __ subiw(count, count, 4 >> shift); @@ -2125,55 +2241,54 @@ class StubGenerator: public StubCodeGenerator { __ fill_words(to, cnt_words, value); } - // Remaining count is less than 8 bytes. Fill it by a single store. - // Note that the total length is no less than 8 bytes. - if (!AvoidUnalignedAccesses && (t == T_BYTE || t == T_SHORT)) { - __ beqz(count, L_exit1); - __ shadd(to, count, to, tmp_reg, shift); // points to the end - __ sd(value, Address(to, -8)); // overwrite some elements - __ bind(L_exit1); - __ leave(); - __ ret(); - } - // Handle copies less than 8 bytes. - Label L_fill_2, L_fill_4, L_exit2; + // Address may not be heapword aligned. + Label L_fill_1, L_fill_2, L_exit; __ bind(L_fill_elements); switch (t) { case T_BYTE: - __ test_bit(t0, count, 0); - __ beqz(t0, L_fill_2); + __ test_bit(tmp_reg, count, 2); + __ beqz(tmp_reg, L_fill_2); __ sb(value, Address(to, 0)); - __ addi(to, to, 1); + __ sb(value, Address(to, 1)); + __ sb(value, Address(to, 2)); + __ sb(value, Address(to, 3)); + __ addi(to, to, 4); + __ bind(L_fill_2); - __ test_bit(t0, count, 1); - __ beqz(t0, L_fill_4); - __ sh(value, Address(to, 0)); + __ test_bit(tmp_reg, count, 1); + __ beqz(tmp_reg, L_fill_1); + __ sb(value, Address(to, 0)); + __ sb(value, Address(to, 1)); __ addi(to, to, 2); - __ bind(L_fill_4); - __ test_bit(t0, count, 2); - __ beqz(t0, L_exit2); - __ sw(value, Address(to, 0)); + + __ bind(L_fill_1); + __ test_bit(tmp_reg, count, 0); + __ beqz(tmp_reg, L_exit); + __ sb(value, Address(to, 0)); break; case T_SHORT: - __ test_bit(t0, count, 0); - __ beqz(t0, L_fill_4); + __ test_bit(tmp_reg, count, 1); + __ beqz(tmp_reg, L_fill_2); + __ sh(value, Address(to, 0)); + __ sh(value, Address(to, 2)); + __ addi(to, to, 4); + + __ bind(L_fill_2); + __ test_bit(tmp_reg, count, 0); + __ beqz(tmp_reg, L_exit); __ sh(value, Address(to, 0)); - __ addi(to, to, 2); - __ bind(L_fill_4); - __ test_bit(t0, count, 1); - __ beqz(t0, L_exit2); - __ sw(value, Address(to, 0)); break; case T_INT: - __ beqz(count, L_exit2); + __ beqz(count, L_exit); __ sw(value, Address(to, 0)); break; default: ShouldNotReachHere(); } - __ bind(L_exit2); + __ bind(L_exit); __ leave(); __ ret(); + return start; } @@ -2189,6 +2304,9 @@ class StubGenerator: public StubCodeGenerator { generate_copy_longs(StubGenStubId::copy_byte_f_id, copy_f, c_rarg0, c_rarg1, t1); generate_copy_longs(StubGenStubId::copy_byte_b_id, copy_b, c_rarg0, c_rarg1, t1); + address ucm_common_error_exit = generate_unsafecopy_common_error_exit(); + UnsafeMemoryAccess::set_common_exit_stub_pc(ucm_common_error_exit); + StubRoutines::riscv::_zero_blocks = generate_zero_blocks(); //*** jbyte @@ -2259,6 +2377,8 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_arrayof_jbyte_fill = generate_fill(StubGenStubId::arrayof_jbyte_fill_id); StubRoutines::_arrayof_jshort_fill = generate_fill(StubGenStubId::arrayof_jshort_fill_id); StubRoutines::_arrayof_jint_fill = generate_fill(StubGenStubId::arrayof_jint_fill_id); + + StubRoutines::_unsafe_setmemory = generate_unsafe_setmemory(); } void generate_aes_loadkeys(const Register &key, VectorRegister *working_vregs, int rounds) { @@ -6458,58 +6578,6 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } - void generate_vector_math_stubs() { - if (!UseRVV) { - log_info(library)("vector is not supported, skip loading vector math (sleef) library!"); - return; - } - - // Get native vector math stub routine addresses - void* libsleef = nullptr; - char ebuf[1024]; - char dll_name[JVM_MAXPATHLEN]; - if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "sleef")) { - libsleef = os::dll_load(dll_name, ebuf, sizeof ebuf); - } - if (libsleef == nullptr) { - log_info(library)("Failed to load native vector math (sleef) library, %s!", ebuf); - return; - } - - // Method naming convention - // All the methods are named as _ - // - // Where: - // is the operation name, e.g. sin, cos - // is to indicate float/double - // "fx/dx" for vector float/double operation - // is the precision level - // "u10/u05" represents 1.0/0.5 ULP error bounds - // We use "u10" for all operations by default - // But for those functions do not have u10 support, we use "u05" instead - // rvv, indicates riscv vector extension - // - // e.g. sinfx_u10rvv is the method for computing vector float sin using rvv instructions - // - log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "sleef" JNI_LIB_SUFFIX, p2i(libsleef)); - - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - if (vop == VectorSupport::VECTOR_OP_TANH) { // skip tanh because of performance regression - continue; - } - - // The native library does not support u10 level of "hypot". - const char* ulf = (vop == VectorSupport::VECTOR_OP_HYPOT) ? "u05" : "u10"; - - snprintf(ebuf, sizeof(ebuf), "%sfx_%srvv", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); - - snprintf(ebuf, sizeof(ebuf), "%sdx_%srvv", VectorSupport::mathname[op], ulf); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_SCALABLE][op] = (address)os::dll_lookup(libsleef, ebuf); - } - } - #endif // COMPILER2 /** @@ -6741,8 +6809,6 @@ static const int64_t right_3_bits = right_n_bits(3); generate_string_indexof_stubs(); - generate_vector_math_stubs(); - #endif // COMPILER2 } diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 72e1180164b..b8de3547c83 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -765,6 +765,10 @@ void TemplateInterpreterGenerator::lock_method() { // xcpool: cp cache // stack_pointer: previous sp void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { + // Save ConstMethod* in x15_const_method for later use to avoid loading multiple times + Register x15_const_method = x15; + __ ld(x15_const_method, Address(xmethod, Method::const_offset())); + // initialize fixed part of activation frame if (native_call) { __ subi(esp, sp, 14 * wordSize); @@ -775,8 +779,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ sd(zr, Address(sp, 12 * wordSize)); } else { __ subi(esp, sp, 12 * wordSize); - __ ld(t0, Address(xmethod, Method::const_offset())); // get ConstMethod - __ add(xbcp, t0, in_bytes(ConstMethod::codes_offset())); // get codebase + __ add(xbcp, x15_const_method, in_bytes(ConstMethod::codes_offset())); // get codebase __ subi(sp, sp, 12 * wordSize); } __ sd(xbcp, Address(sp, wordSize)); @@ -798,9 +801,10 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ sd(fp, Address(sp, 10 * wordSize)); __ la(fp, Address(sp, 12 * wordSize)); // include ra & fp - __ ld(xcpool, Address(xmethod, Method::const_offset())); - __ ld(xcpool, Address(xcpool, ConstMethod::constants_offset())); - __ ld(xcpool, Address(xcpool, ConstantPool::cache_offset())); + // Save ConstantPool* in x28_constants for later use to avoid loading multiple times + Register x28_constants = x28; + __ ld(x28_constants, Address(x15_const_method, ConstMethod::constants_offset())); + __ ld(xcpool, Address(x28_constants, ConstantPool::cache_offset())); __ sd(xcpool, Address(sp, 3 * wordSize)); __ sub(t0, xlocals, fp); __ srai(t0, t0, Interpreter::logStackElementSize); // t0 = xlocals - fp(); @@ -812,13 +816,15 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ sd(x19_sender_sp, Address(sp, 9 * wordSize)); __ sd(zr, Address(sp, 8 * wordSize)); - // Get mirror and store it in the frame as GC root for this Method* - __ load_mirror(t2, xmethod, x15, t1); + // Get mirror, Resolve ConstantPool* -> InstanceKlass* -> Java mirror + // and store it in the frame as GC root for this Method* + __ ld(t2, Address(x28_constants, ConstantPool::pool_holder_offset())); + __ ld(t2, Address(t2, in_bytes(Klass::java_mirror_offset()))); + __ resolve_oop_handle(t2, t0, t1); __ sd(t2, Address(sp, 4 * wordSize)); if (!native_call) { - __ ld(t0, Address(xmethod, Method::const_offset())); - __ lhu(t0, Address(t0, ConstMethod::max_stack_offset())); + __ lhu(t0, Address(x15_const_method, ConstMethod::max_stack_offset())); __ add(t0, t0, MAX2(3, Method::extra_stack_entries())); __ slli(t0, t0, 3); __ sub(t0, sp, t0); @@ -1372,6 +1378,31 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ bind(L); } + #if INCLUDE_JFR + __ enter_jfr_critical_section(); + + // This poll test is to uphold the invariant that a JFR sampled frame + // must not return to its caller without a prior safepoint poll check. + // The earlier poll check in this routine is insufficient for this purpose + // because the thread has transitioned back to Java. + + Label slow_path; + Label fast_path; + __ safepoint_poll(slow_path, true /* at_return */, false /* acquire */, false /* in_nmethod */); + __ j(fast_path); + + __ bind(slow_path); + __ push(dtos); + __ push(ltos); + __ set_last_Java_frame(esp, fp, __ pc(), t0); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), xthread); + __ reset_last_Java_frame(true); + __ pop(ltos); + __ pop(dtos); + __ bind(fast_path); + +#endif // INCLUDE_JFR + // jvmti support // Note: This must happen _after_ handling/throwing any exceptions since // the exception handler code notifies the runtime of method exits @@ -1385,10 +1416,13 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ jalr(result_handler); // remove activation - __ ld(esp, Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp + // get sender sp + __ ld(esp, Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // remove frame anchor __ leave(); + JFR_ONLY(__ leave_jfr_critical_section();) + // restore sender sp __ mv(sp, esp); @@ -1612,6 +1646,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { Interpreter::_remove_activation_preserving_args_entry = __ pc(); __ empty_expression_stack(); + __ restore_bcp(); // We could have returned from deoptimizing this frame, so restore rbcp. // Set the popframe_processing bit in pending_popframe_condition // indicating that we are currently handling popframe, so that // call_VMs that may happen later do not trigger new popframe diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index a035326be01..f6bf1e79f92 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -125,24 +125,6 @@ static inline Address at_tos_p5() { return Address(esp, Interpreter::expr_offset_in_bytes(5)); } -// Miscellaneous helper routines -// Store an oop (or null) at the Address described by obj. -// If val == noreg this means store a null -static void do_oop_store(InterpreterMacroAssembler* _masm, - Address dst, - Register val, - DecoratorSet decorators) { - assert(val == noreg || val == x10, "parameter is just for looks"); - __ store_heap_oop(dst, val, x28, x29, x13, decorators); -} - -static void do_oop_load(InterpreterMacroAssembler* _masm, - Address src, - Register dst, - DecoratorSet decorators) { - __ load_heap_oop(dst, src, x28, x29, decorators); -} - Address TemplateTable::at_bcp(int offset) { assert(_desc->uses_bcp(), "inconsistent uses_bcp information"); return Address(xbcp, offset); @@ -787,7 +769,7 @@ void TemplateTable::aaload() { index_check(x10, x11); // leaves index in x11 __ addi(x11, x11, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop); __ shadd(x10, x11, x10, t0, LogBytesPerHeapOop); - do_oop_load(_masm, Address(x10), x10, IS_ARRAY); + __ load_heap_oop(x10, Address(x10), x28, x29, IS_ARRAY); } void TemplateTable::baload() { @@ -1099,7 +1081,7 @@ void TemplateTable::aastore() { // Get the value we will store __ ld(x10, at_tos()); // Now store using the appropriate barrier - do_oop_store(_masm, element_address, x10, IS_ARRAY); + __ store_heap_oop(element_address, x10, x28, x29, x13, IS_ARRAY); __ j(done); // Have a null in x10, x13=array, x12=index. Store null at ary[idx] @@ -1107,7 +1089,7 @@ void TemplateTable::aastore() { __ profile_null_seen(x12); // Store a null - do_oop_store(_masm, element_address, noreg, IS_ARRAY); + __ store_heap_oop(element_address, noreg, x28, x29, x13, IS_ARRAY); // Pop stack arguments __ bind(done); @@ -1757,6 +1739,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ mv(x9, x10); // save the nmethod + JFR_ONLY(__ enter_jfr_critical_section();) + call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin)); // x10 is OSR buffer, move it to expected parameter location @@ -1765,9 +1749,12 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // remove activation // get sender esp __ ld(esp, - Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); + Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // remove frame anchor __ leave(); + + JFR_ONLY(__ leave_jfr_critical_section();) + // Ensure compiled code always sees stack at proper alignment __ andi(sp, esp, -16); @@ -2560,7 +2547,7 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr __ subi(t0, tos_state, (u1)atos); __ bnez(t0, notObj); // atos - do_oop_load(_masm, field, x10, IN_HEAP); + __ load_heap_oop(x10, field, x28, x29, IN_HEAP); __ push(atos); if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_agetfield, bc, x11); @@ -2804,7 +2791,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr __ add(off, obj, off); // if static, obj from cache, else obj from stack. const Address field(off, 0); // Store into the field - do_oop_store(_masm, field, x10, IN_HEAP); + __ store_heap_oop(field, x10, x28, x29, x13, IN_HEAP); if (rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_aputfield, bc, x11, true, byte_no); } @@ -3046,10 +3033,10 @@ void TemplateTable::fast_storefield(TosState state) { __ add(x11, x12, x11); const Address field(x11, 0); - // access field + // access field, must not clobber x13 - flags switch (bytecode()) { case Bytecodes::_fast_aputfield: - do_oop_store(_masm, field, x10, IN_HEAP); + __ store_heap_oop(field, x10, x28, x29, x15, IN_HEAP); break; case Bytecodes::_fast_lputfield: __ access_store_at(T_LONG, IN_HEAP, field, x10, noreg, noreg, noreg); @@ -3128,7 +3115,7 @@ void TemplateTable::fast_accessfield(TosState state) { // access field switch (bytecode()) { case Bytecodes::_fast_agetfield: - do_oop_load(_masm, field, x10, IN_HEAP); + __ load_heap_oop(x10, field, x28, x29, IN_HEAP); __ verify_oop(x10); break; case Bytecodes::_fast_lgetfield: @@ -3186,7 +3173,7 @@ void TemplateTable::fast_xaccess(TosState state) { break; case atos: __ add(x10, x10, x11); - do_oop_load(_masm, Address(x10, 0), x10, IN_HEAP); + __ load_heap_oop(x10, Address(x10, 0), x28, x29, IN_HEAP); __ verify_oop(x10); break; case ftos: diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index a0de9d767bf..eca1bb83ab6 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -240,22 +240,20 @@ void VM_Version::common_initialize() { } // UseZvfh (depends on RVV) - if (UseZvfh && !UseRVV) { - warning("Cannot enable UseZvfh on cpu without RVV support."); - FLAG_SET_DEFAULT(UseZvfh, false); + if (UseZvfh) { + if (!UseRVV) { + warning("Cannot enable UseZvfh on cpu without RVV support."); + FLAG_SET_DEFAULT(UseZvfh, false); + } + if (!UseZfh) { + warning("Cannot enable UseZvfh on cpu without Zfh support."); + FLAG_SET_DEFAULT(UseZvfh, false); + } } } #ifdef COMPILER2 void VM_Version::c2_initialize() { - if (UseCMoveUnconditionally) { - FLAG_SET_DEFAULT(UseCMoveUnconditionally, false); - } - - if (ConditionalMoveLimit > 0) { - FLAG_SET_DEFAULT(ConditionalMoveLimit, 0); - } - if (!UseRVV) { FLAG_SET_DEFAULT(MaxVectorSize, 0); } else { @@ -476,7 +474,7 @@ void VM_Version::initialize_cpu_information(void) { _no_of_threads = _no_of_cores; _no_of_sockets = _no_of_cores; snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "RISCV64"); - snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", features_string()); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index 4214d6c53dc..a0a42fb5463 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -221,13 +221,13 @@ class VM_Version : public Abstract_VM_Version { FLAG_SET_DEFAULT(UseExtension, true); \ } \ - // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva20-profiles + // https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc#rva20-profiles #define RV_USE_RVA20U64 \ RV_ENABLE_EXTENSION(UseRVC) \ static void useRVA20U64Profile(); - // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva22-profiles + // https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc#rva22-profiles #define RV_USE_RVA22U64 \ RV_ENABLE_EXTENSION(UseRVC) \ RV_ENABLE_EXTENSION(UseZba) \ @@ -241,7 +241,7 @@ class VM_Version : public Abstract_VM_Version { static void useRVA22U64Profile(); - // https://github.com/riscv/riscv-profiles/blob/main/rva23-profile.adoc#rva23u64-profile + // https://github.com/riscv/riscv-profiles/blob/main/src/rva23-profile.adoc#rva23u64-profile #define RV_USE_RVA23U64 \ RV_ENABLE_EXTENSION(UseRVC) \ RV_ENABLE_EXTENSION(UseRVV) \ diff --git a/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp b/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp index e815542a51e..96990f0ce94 100644 --- a/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp +++ b/src/hotspot/cpu/s390/abstractInterpreter_s390.cpp @@ -176,7 +176,7 @@ void AbstractInterpreter::layout_activation(Method* method, intptr_t* monitor_base = (intptr_t*)((address)interpreter_frame->fp() - frame::z_ijava_state_size); intptr_t* monitor = monitor_base - (moncount * frame::interpreter_frame_monitor_size()); intptr_t* operand_stack_base = monitor; - intptr_t* tos = operand_stack_base - tempcount - popframe_extra_args; + intptr_t* esp = operand_stack_base - tempcount - popframe_extra_args - 1; intptr_t* top_frame_sp = operand_stack_base - method->max_stack() - frame::z_top_ijava_frame_abi_size / Interpreter::stackElementSize; intptr_t* sender_sp; @@ -206,7 +206,7 @@ void AbstractInterpreter::layout_activation(Method* method, interpreter_frame->interpreter_frame_set_locals(locals_base); interpreter_frame->interpreter_frame_set_monitor_end((BasicObjectLock *)monitor); *interpreter_frame->interpreter_frame_cache_addr() = method->constants()->cache(); - interpreter_frame->interpreter_frame_set_tos_address(tos); + interpreter_frame->interpreter_frame_set_esp(esp); if (!is_bottom_frame) { interpreter_frame->interpreter_frame_set_sender_sp(sender_sp); } diff --git a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp index c858a4b8cb1..430928a66ed 100644 --- a/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp +++ b/src/hotspot/cpu/s390/c1_CodeStubs_s390.cpp @@ -52,7 +52,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { CHECK_BAILOUT(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } @@ -74,7 +74,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { CHECK_BAILOUT(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { @@ -88,7 +88,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { CHECK_BAILOUT(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void CounterOverflowStub::emit_code(LIR_Assembler* ce) { @@ -116,7 +116,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) { ce->emit_call_c(Runtime1::entry_for (C1StubId::throw_div0_exception_id)); CHECK_BAILOUT(); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { @@ -134,7 +134,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { CHECK_BAILOUT(); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } // Note: pass object in Z_R1_scratch @@ -147,7 +147,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { ce->emit_call_c(a); CHECK_BAILOUT(); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, C1StubId stub_id) { diff --git a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp index 9fa6da8341f..ddba445154a 100644 --- a/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp +++ b/src/hotspot/cpu/s390/c1_FrameMap_s390.cpp @@ -144,13 +144,13 @@ LIR_Opr FrameMap::_caller_save_fpu_regs[] = {}; // c1 rnr -> FloatRegister FloatRegister FrameMap::nr2floatreg (int rnr) { assert(_init_done, "tables not initialized"); - debug_only(fpu_range_check(rnr);) + DEBUG_ONLY(fpu_range_check(rnr);) return _fpu_rnr2reg[rnr]; } void FrameMap::map_float_register(int rnr, FloatRegister reg) { - debug_only(fpu_range_check(rnr);) - debug_only(fpu_range_check(reg->encoding());) + DEBUG_ONLY(fpu_range_check(rnr);) + DEBUG_ONLY(fpu_range_check(reg->encoding());) _fpu_rnr2reg[rnr] = reg; // mapping c1 regnr. -> FloatRegister _fpu_reg2rnr[reg->encoding()] = rnr; // mapping assembler encoding -> c1 regnr. } diff --git a/src/hotspot/cpu/s390/c1_FrameMap_s390.hpp b/src/hotspot/cpu/s390/c1_FrameMap_s390.hpp index 66ccc8de876..721995f41fe 100644 --- a/src/hotspot/cpu/s390/c1_FrameMap_s390.hpp +++ b/src/hotspot/cpu/s390/c1_FrameMap_s390.hpp @@ -107,7 +107,7 @@ static int fpu_reg2rnr (FloatRegister reg) { assert(_init_done, "tables not initialized"); int c1rnr = _fpu_reg2rnr[reg->encoding()]; - debug_only(fpu_range_check(c1rnr);) + DEBUG_ONLY(fpu_range_check(c1rnr);) return c1rnr; } diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index 5691a2055b3..0e873250dca 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -69,17 +69,18 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox // Save object being locked into the BasicObjectLock... z_stg(Roop, Address(Rbox, BasicObjectLock::obj_offset())); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, Roop); - z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - branch_optimized(Assembler::bcondAllOne, slow_case); - } - assert(LockingMode != LM_MONITOR, "LM_MONITOR is already handled, by emit_lock()"); if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(Rbox, Roop, Rmark, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, Roop); + z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + branch_optimized(Assembler::bcondAllOne, slow_case); + } + NearLabel done; // Load object header. diff --git a/src/hotspot/cpu/s390/frame_s390.cpp b/src/hotspot/cpu/s390/frame_s390.cpp index 01ed22c7d86..b602d0adce5 100644 --- a/src/hotspot/cpu/s390/frame_s390.cpp +++ b/src/hotspot/cpu/s390/frame_s390.cpp @@ -185,7 +185,8 @@ bool frame::is_interpreted_frame() const { void frame::interpreter_frame_set_locals(intptr_t* locs) { assert(is_interpreted_frame(), "interpreted frame expected"); - ijava_state_unchecked()->locals = (uint64_t)locs; + // set relativized locals + *addr_at(_z_ijava_idx(locals)) = (intptr_t) (locs - fp()); } // sender_sp @@ -340,7 +341,7 @@ bool frame::is_interpreted_frame_valid(JavaThread* thread) const { if (MetaspaceObj::is_valid(cp) == false) return false; // validate locals - address locals = (address)(ijava_state_unchecked()->locals); + address locals = (address)interpreter_frame_locals(); return thread->is_in_stack_range_incl(locals, (address)fp()); } diff --git a/src/hotspot/cpu/s390/frame_s390.hpp b/src/hotspot/cpu/s390/frame_s390.hpp index 3a6b3f33a55..ad754706367 100644 --- a/src/hotspot/cpu/s390/frame_s390.hpp +++ b/src/hotspot/cpu/s390/frame_s390.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -330,6 +330,10 @@ #define _z_ijava_state_neg(_component) \ (int) (-frame::z_ijava_state_size + offset_of(frame::z_ijava_state, _component)) +// Frame slot index relative to fp +#define _z_ijava_idx(_component) \ + (_z_ijava_state_neg(_component) >> LogBytesPerWord) + // ENTRY_FRAME struct z_entry_frame_locals { @@ -406,7 +410,7 @@ // C2I adapter frames: // - // STACK (interpreted called from compiled, on entry to frame manager): + // STACK (interpreted called from compiled, on entry to template interpreter): // // [TOP_C2I_FRAME] // [JIT_FRAME] @@ -471,6 +475,7 @@ public: // To be used, if sp was not extended to match callee's calling convention. inline frame(intptr_t* sp, address pc, intptr_t* unextended_sp = nullptr, intptr_t* fp = nullptr, CodeBlob* cb = nullptr); + inline frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map = nullptr); // Access frame via stack pointer. inline intptr_t* sp_addr_at(int index) const { return &sp()[index]; } @@ -494,14 +499,12 @@ inline z_ijava_state* ijava_state() const; - // Where z_ijava_state.monitors is saved. - inline BasicObjectLock** interpreter_frame_monitors_addr() const; - // Where z_ijava_state.esp is saved. - inline intptr_t** interpreter_frame_esp_addr() const; - public: + + inline intptr_t* interpreter_frame_esp() const; + // Where z_ijava_state.esp is saved. + inline void interpreter_frame_set_esp(intptr_t* esp); inline intptr_t* interpreter_frame_top_frame_sp(); - inline void interpreter_frame_set_tos_address(intptr_t* x); inline void interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp); inline void interpreter_frame_set_sender_sp(intptr_t* sender_sp); #ifdef ASSERT @@ -513,6 +516,8 @@ // Next two functions read and write z_ijava_state.monitors. private: inline BasicObjectLock* interpreter_frame_monitors() const; + + // Where z_ijava_state.monitors is saved. inline void interpreter_frame_set_monitors(BasicObjectLock* monitors); public: diff --git a/src/hotspot/cpu/s390/frame_s390.inline.hpp b/src/hotspot/cpu/s390/frame_s390.inline.hpp index d29106cfc40..dea0e72581f 100644 --- a/src/hotspot/cpu/s390/frame_s390.inline.hpp +++ b/src/hotspot/cpu/s390/frame_s390.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -87,6 +87,11 @@ inline frame::frame(intptr_t* sp, address pc, intptr_t* unextended_sp, intptr_t* inline frame::frame(intptr_t* sp) : frame(sp, nullptr) {} +inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc, CodeBlob* cb, const ImmutableOopMap* oop_map) + :_sp(sp), _pc(pc), _cb(cb), _oop_map(oop_map), _on_heap(false), DEBUG_ONLY(_frame_index(-1) COMMA) _unextended_sp(unextended_sp), _fp(fp) { + setup(); +} + // Generic constructor. Used by pns() in debug.cpp only #ifndef PRODUCT inline frame::frame(void* sp, void* pc, void* unextended_sp) @@ -109,16 +114,19 @@ inline frame::z_ijava_state* frame::ijava_state() const { return state; } -inline BasicObjectLock** frame::interpreter_frame_monitors_addr() const { - return (BasicObjectLock**) &(ijava_state()->monitors); -} - // The next two functions read and write z_ijava_state.monitors. inline BasicObjectLock* frame::interpreter_frame_monitors() const { - return *interpreter_frame_monitors_addr(); + BasicObjectLock* result = (BasicObjectLock*) at_relative(_z_ijava_idx(monitors)); + // make sure the pointer points inside the frame + assert(sp() <= (intptr_t*) result, "monitor end should be above the stack pointer"); + assert((intptr_t*) result < fp(), "monitor end should be strictly below the frame pointer: result: " INTPTR_FORMAT " fp: " INTPTR_FORMAT, p2i(result), p2i(fp())); + return result; } + inline void frame::interpreter_frame_set_monitors(BasicObjectLock* monitors) { - *interpreter_frame_monitors_addr() = monitors; + assert(is_interpreted_frame(), "interpreted frame expected"); + // set relativized monitors + ijava_state()->monitors = (intptr_t) ((intptr_t*)monitors - fp()); } // Accessors @@ -180,7 +188,8 @@ inline intptr_t* frame::link_or_null() const { } inline intptr_t* frame::interpreter_frame_locals() const { - return (intptr_t*) (ijava_state()->locals); + intptr_t n = *addr_at(_z_ijava_idx(locals)); + return &fp()[n]; // return relativized locals } inline intptr_t* frame::interpreter_frame_bcp_addr() const { @@ -202,11 +211,14 @@ inline intptr_t* frame::interpreter_frame_expression_stack() const { // Also begin is one past last monitor. inline intptr_t* frame::interpreter_frame_top_frame_sp() { - return (intptr_t*)ijava_state()->top_frame_sp; + intptr_t n = *addr_at(_z_ijava_idx(top_frame_sp)); + return &fp()[n]; // return relativized locals } inline void frame::interpreter_frame_set_top_frame_sp(intptr_t* top_frame_sp) { - ijava_state()->top_frame_sp = (intptr_t) top_frame_sp; + assert(is_interpreted_frame(), "interpreted frame expected"); + // set relativized top_frame_sp + ijava_state()->top_frame_sp = (intptr_t) (top_frame_sp - fp()); } inline void frame::interpreter_frame_set_sender_sp(intptr_t* sender_sp) { @@ -219,18 +231,20 @@ inline void frame::interpreter_frame_set_magic() { } #endif +inline intptr_t* frame::interpreter_frame_esp() const { + return (intptr_t*) at_relative(_z_ijava_idx(esp)); +} + // Where z_ijava_state.esp is saved. -inline intptr_t** frame::interpreter_frame_esp_addr() const { - return (intptr_t**) &(ijava_state()->esp); +inline void frame::interpreter_frame_set_esp(intptr_t* esp) { + assert(is_interpreted_frame(), "interpreted frame expected"); + // set relativized esp + ijava_state()->esp = (intptr_t) (esp - fp()); } // top of expression stack (lowest address) inline intptr_t* frame::interpreter_frame_tos_address() const { - return *interpreter_frame_esp_addr() + 1; -} - -inline void frame::interpreter_frame_set_tos_address(intptr_t* x) { - *interpreter_frame_esp_addr() = x - 1; + return interpreter_frame_esp() + Interpreter::stackElementWords; } // Stack slot needed for native calls and GC. @@ -362,4 +376,42 @@ void frame::update_map_with_saved_link(RegisterMapT* map, intptr_t** link_addr) Unimplemented(); } +#if INCLUDE_JFR + +// Static helper routines +inline intptr_t* frame::sender_sp(intptr_t* fp) { return fp; } + +// Extract common_abi parts. +inline intptr_t* frame::fp(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast(((z_common_abi*)sp)->callers_sp); +} + +inline intptr_t* frame::link(const intptr_t* fp) { return frame::fp(fp); } + +inline address frame::return_address(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast
          (((z_common_abi*)sp)->return_pc); +} + +inline address frame::interpreter_return_address(const intptr_t* fp) { return frame::return_address(fp); } + +inline address frame::interpreter_bcp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (*(fp + _z_ijava_idx(bcp))); +} + +inline intptr_t* frame::interpreter_sender_sp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(*(fp + _z_ijava_idx(sender_sp))); +} + +inline bool frame::is_interpreter_frame_setup_at(const intptr_t* fp, const void* sp) { + assert(fp != nullptr, "invariant"); + assert(sp != nullptr, "invariant"); + return sp <= fp - ((frame::z_ijava_state_size + frame::z_top_ijava_frame_abi_size) >> LogBytesPerWord); +} + +#endif // INCLUDE_JFR + #endif // CPU_S390_FRAME_S390_INLINE_HPP diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp index 2054c3db36c..dea3317270e 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp @@ -24,16 +24,16 @@ */ #include "asm/macroAssembler.inline.hpp" -#include "registerSaver_s390.hpp" -#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1BarrierSetAssembler.hpp" #include "gc/g1/g1BarrierSetRuntime.hpp" +#include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1DirtyCardQueue.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1SATBMarkQueueSet.hpp" #include "gc/g1/g1ThreadLocalData.hpp" #include "interpreter/interp_masm.hpp" +#include "registerSaver_s390.hpp" #include "runtime/jniHandles.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/macros.hpp" diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp index 85dcc0a4e73..88b3199e4e1 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp @@ -40,7 +40,7 @@ class NativeMethodBarrier: public NativeInstruction { address get_patchable_data_address() const { address inst_addr = get_barrier_start_address() + PATCHABLE_INSTRUCTION_OFFSET; - debug_only(Assembler::is_z_cfi(*((long*)inst_addr))); + DEBUG_ONLY(Assembler::is_z_cfi(*((long*)inst_addr))); return inst_addr + 2; } @@ -91,7 +91,7 @@ static NativeMethodBarrier* get_nmethod_barrier(nmethod* nm) { address barrier_address = nm->code_begin() + nm->frame_complete_offset() - NativeMethodBarrier::BARRIER_TOTAL_LENGTH; auto barrier = reinterpret_cast(barrier_address); - debug_only(barrier->verify()); + DEBUG_ONLY(barrier->verify()); return barrier; } diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index 48f4c7293a2..b384b24d49b 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -104,7 +104,15 @@ void InterpreterMacroAssembler::dispatch_base(TosState state, address* table, bo } { Label OK; // check if the locals pointer in Z_locals is correct - z_cg(Z_locals, _z_ijava_state_neg(locals), Z_fp); + + // _z_ijava_state_neg(locals)) is fp relativized, so we need to + // extract the pointer. + + z_lg(Z_R1_scratch, Address(Z_fp, _z_ijava_state_neg(locals))); + z_sllg(Z_R1_scratch, Z_R1_scratch, Interpreter::logStackElementSize); + z_agr(Z_R1_scratch, Z_fp); + + z_cgr(Z_locals, Z_R1_scratch); z_bre(OK); reentry = stop_chain_static(reentry, "invalid locals pointer Z_locals: " FILE_AND_LINE); bind(OK); @@ -444,7 +452,7 @@ void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, // Useful if consumed previously by access via stackTop(). void InterpreterMacroAssembler::popx(int len) { add2reg(Z_esp, len*Interpreter::stackElementSize); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } // Get Address object of stack top. No checks. No pop. @@ -458,38 +466,38 @@ void InterpreterMacroAssembler::pop_i(Register r) { z_l(r, Interpreter::expr_offset_in_bytes(0), Z_esp); add2reg(Z_esp, Interpreter::stackElementSize); assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::pop_ptr(Register r) { z_lg(r, Interpreter::expr_offset_in_bytes(0), Z_esp); add2reg(Z_esp, Interpreter::stackElementSize); assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::pop_l(Register r) { z_lg(r, Interpreter::expr_offset_in_bytes(0), Z_esp); add2reg(Z_esp, 2*Interpreter::stackElementSize); assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::pop_f(FloatRegister f) { mem2freg_opt(f, Address(Z_esp, Interpreter::expr_offset_in_bytes(0)), false); add2reg(Z_esp, Interpreter::stackElementSize); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::pop_d(FloatRegister f) { mem2freg_opt(f, Address(Z_esp, Interpreter::expr_offset_in_bytes(0)), true); add2reg(Z_esp, 2*Interpreter::stackElementSize); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); } void InterpreterMacroAssembler::push_i(Register r) { assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); z_st(r, Address(Z_esp)); add2reg(Z_esp, -Interpreter::stackElementSize); } @@ -501,7 +509,7 @@ void InterpreterMacroAssembler::push_ptr(Register r) { void InterpreterMacroAssembler::push_l(Register r) { assert_different_registers(r, Z_R1_scratch); - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); int offset = -Interpreter::stackElementSize; z_stg(r, Address(Z_esp, offset)); clear_mem(Address(Z_esp), Interpreter::stackElementSize); @@ -509,13 +517,13 @@ void InterpreterMacroAssembler::push_l(Register r) { } void InterpreterMacroAssembler::push_f(FloatRegister f) { - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); freg2mem_opt(f, Address(Z_esp), false); add2reg(Z_esp, -Interpreter::stackElementSize); } void InterpreterMacroAssembler::push_d(FloatRegister d) { - debug_only(verify_esp(Z_esp, Z_R1_scratch)); + DEBUG_ONLY(verify_esp(Z_esp, Z_R1_scratch)); int offset = -Interpreter::stackElementSize; freg2mem_opt(d, Address(Z_esp, offset)); add2reg(Z_esp, 2 * offset); @@ -568,7 +576,10 @@ void InterpreterMacroAssembler::prepare_to_jump_from_interpreted(Register method // Satisfy interpreter calling convention (see generate_normal_entry()). z_lgr(Z_R10, Z_SP); // Set sender sp (aka initial caller sp, aka unextended sp). // Record top_frame_sp, because the callee might modify it, if it's compiled. - z_stg(Z_SP, _z_ijava_state_neg(top_frame_sp), Z_fp); + assert_different_registers(Z_R1, method); + z_sgrk(Z_R1, Z_SP, Z_fp); + z_srag(Z_R1, Z_R1, Interpreter::logStackElementSize); + z_stg(Z_R1, _z_ijava_state_neg(top_frame_sp), Z_fp); save_bcp(); save_esp(); z_lgr(Z_method, method); // Set Z_method (kills Z_fp!). @@ -616,7 +627,7 @@ void InterpreterMacroAssembler::verify_esp(Register Resp, Register Rtemp) { // i.e. IJAVA_STATE.monitors > Resp. NearLabel OK; Register Rmonitors = Rtemp; - z_lg(Rmonitors, _z_ijava_state_neg(monitors), Z_fp); + get_monitors(Rmonitors); compareU64_and_branch(Rmonitors, Resp, bcondHigh, OK); reentry = stop_chain_static(reentry, "too many pops: Z_esp points into monitor area"); bind(OK); @@ -654,21 +665,46 @@ void InterpreterMacroAssembler::restore_bcp() { z_lg(Z_bcp, Address(Z_fp, _z_ijava_state_neg(bcp))); } -void InterpreterMacroAssembler::save_esp() { - z_stg(Z_esp, Address(Z_fp, _z_ijava_state_neg(esp))); +void InterpreterMacroAssembler::save_esp(Register fp) { + if (fp == noreg) { + fp = Z_fp; + } + z_sgrk(Z_R0, Z_esp, fp); + z_srag(Z_R0, Z_R0, Interpreter::logStackElementSize); + z_stg(Z_R0, Address(fp, _z_ijava_state_neg(esp))); } void InterpreterMacroAssembler::restore_esp() { asm_assert_ijava_state_magic(Z_esp); z_lg(Z_esp, Address(Z_fp, _z_ijava_state_neg(esp))); + z_slag(Z_esp, Z_esp, Interpreter::logStackElementSize); + z_agr(Z_esp, Z_fp); } void InterpreterMacroAssembler::get_monitors(Register reg) { asm_assert_ijava_state_magic(reg); +#ifdef ASSERT + NearLabel ok; + z_cg(Z_fp, 0, Z_SP); + z_bre(ok); + stop("Z_fp is corrupted"); + bind(ok); +#endif // ASSERT mem2reg_opt(reg, Address(Z_fp, _z_ijava_state_neg(monitors))); + z_slag(reg, reg, Interpreter::logStackElementSize); + z_agr(reg, Z_fp); } void InterpreterMacroAssembler::save_monitors(Register reg) { +#ifdef ASSERT + NearLabel ok; + z_cg(Z_fp, 0, Z_SP); + z_bre(ok); + stop("Z_fp is corrupted"); + bind(ok); +#endif // ASSERT + z_sgr(reg, Z_fp); + z_srag(reg, reg, Interpreter::logStackElementSize); reg2mem_opt(reg, Address(Z_fp, _z_ijava_state_neg(monitors))); } @@ -684,6 +720,8 @@ void InterpreterMacroAssembler::save_mdp(Register mdp) { void InterpreterMacroAssembler::restore_locals() { asm_assert_ijava_state_magic(Z_locals); z_lg(Z_locals, Address(Z_fp, _z_ijava_state_neg(locals))); + z_sllg(Z_locals, Z_locals, Interpreter::logStackElementSize); + z_agr(Z_locals, Z_fp); } void InterpreterMacroAssembler::get_method(Register reg) { @@ -827,12 +865,11 @@ void InterpreterMacroAssembler::unlock_if_synchronized_method(TosState state, // register for unlock_object to pass to VM directly. Register R_current_monitor = Z_ARG2; Register R_monitor_block_bot = Z_ARG1; - const Address monitor_block_top(Z_fp, _z_ijava_state_neg(monitors)); const Address monitor_block_bot(Z_fp, -frame::z_ijava_state_size); bind(restart); // Starting with top-most entry. - z_lg(R_current_monitor, monitor_block_top); + get_monitors(R_current_monitor); // Points to word before bottom of monitor block. load_address(R_monitor_block_bot, monitor_block_bot); z_bru(entry); @@ -1002,16 +1039,16 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { // markWord header = obj->mark().set_unlocked(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp, object); - z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - z_btrue(slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(monitor, object, header, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, object); + z_tm(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + z_btrue(slow_case); + } + // Load markWord from object into header. z_lg(header, hdr_offset, object); diff --git a/src/hotspot/cpu/s390/interp_masm_s390.hpp b/src/hotspot/cpu/s390/interp_masm_s390.hpp index 2473463219c..94ad63b16c6 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.hpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.hpp @@ -169,7 +169,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void restore_bcp(); - void save_esp(); + void save_esp(Register fp = noreg); void restore_esp(); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 88aedd1b5c0..0129e604978 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -6363,11 +6363,17 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe z_lg(mark, Address(obj, mark_offset)); if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. const Address om_cache_addr = Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))); z_mvghi(om_cache_addr, 0); } + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(temp1, obj); + z_tm(Address(temp1, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + z_brne(slow); + } + // First we need to check if the lock-stack has room for pushing the object reference. z_lgf(top, Address(Z_thread, ls_top_offset)); @@ -6501,7 +6507,7 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe NearLabel slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. z_mvghi(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0); } diff --git a/src/hotspot/cpu/s390/register_s390.hpp b/src/hotspot/cpu/s390/register_s390.hpp index e7fdaa58d1a..a33145db02c 100644 --- a/src/hotspot/cpu/s390/register_s390.hpp +++ b/src/hotspot/cpu/s390/register_s390.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -414,7 +414,7 @@ constexpr FloatRegister Z_FARG2 = Z_F2; constexpr FloatRegister Z_FARG3 = Z_F4; constexpr FloatRegister Z_FARG4 = Z_F6; -// Register declarations to be used in frame manager assembly code. +// Register declarations to be used in template interpreter assembly code. // Use only non-volatile registers in order to keep values across C-calls. // Register to cache the integer value on top of the operand stack. @@ -439,7 +439,7 @@ constexpr Register Z_bcp = Z_R13; // Bytecode which is dispatched (short lived!). constexpr Register Z_bytecode = Z_R14; -// Temporary registers to be used within frame manager. We can use +// Temporary registers to be used within template interpreter. We can use // the nonvolatile ones because the call stub has saved them. // Use only non-volatile registers in order to keep values across C-calls. constexpr Register Z_tmp_1 = Z_R10; diff --git a/src/hotspot/cpu/s390/runtime_s390.cpp b/src/hotspot/cpu/s390/runtime_s390.cpp index 4eedb3877d2..99a33716b8b 100644 --- a/src/hotspot/cpu/s390/runtime_s390.cpp +++ b/src/hotspot/cpu/s390/runtime_s390.cpp @@ -72,6 +72,9 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); Register handle_exception = Z_ARG5; @@ -115,7 +118,7 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { __ z_lgr(Z_SP, saved_sp); // [Z_RET] isn't null was possible in hotspot5 but not in sapjvm6. - // C2I adapter extensions are now removed by a resize in the frame manager + // C2I adapter extensions are now removed by a resize in the template interpreter // (unwind_initial_activation_pending_exception). #ifdef ASSERT __ z_ltgr(handle_exception, handle_exception); diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index f4487ccabec..cb1f12504fd 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -2139,7 +2139,7 @@ static address gen_c2i_adapter(MacroAssembler *masm, Register value = Z_R12; // Remember the senderSP so we can pop the interpreter arguments off of the stack. - // In addition, frame manager expects initial_caller_sp in Z_R10. + // In addition, template interpreter expects initial_caller_sp in Z_R10. __ z_lgr(sender_SP, Z_SP); // This should always fit in 14 bit immediate. @@ -2352,12 +2352,12 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, __ z_br(Z_R1_scratch); } -AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs, - AdapterFingerPrint* fingerprint) { +void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + AdapterHandlerEntry* handler) { __ align(CodeEntryAlignment); address i2c_entry = __ pc(); gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); @@ -2411,7 +2411,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); - return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); + handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); + return; } // This function returns the adjust size (in number of words) to a c2i adapter @@ -2768,6 +2769,9 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Setup code generation tools const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } InterpreterMacroAssembler* masm = new InterpreterMacroAssembler(&buffer); Register unroll_block_reg = Z_tmp_1; diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index b46393f543e..d3f6540a3ea 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -115,7 +115,7 @@ class StubGenerator: public StubCodeGenerator { // [SP+176] - thread : Thread* // address generate_call_stub(address& return_address) { - // Set up a new C frame, copy Java arguments, call frame manager + // Set up a new C frame, copy Java arguments, call template interpreter // or native_entry, and process result. StubGenStubId stub_id = StubGenStubId::call_stub_id; @@ -272,10 +272,10 @@ class StubGenerator: public StubCodeGenerator { BLOCK_COMMENT("call {"); { - // Call frame manager or native entry. + // Call template interpreter or native entry. // - // Register state on entry to frame manager / native entry: + // Register state on entry to template interpreter / native entry: // // Z_ARG1 = r_top_of_arguments_addr - intptr_t *sender tos (prepushed) // Lesp = (SP) + copied_arguments_offset - 8 @@ -290,7 +290,7 @@ class StubGenerator: public StubCodeGenerator { __ z_lgr(Z_esp, r_top_of_arguments_addr); // - // Stack on entry to frame manager / native entry: + // Stack on entry to template interpreter / native entry: // // F0 [TOP_IJAVA_FRAME_ABI] // [outgoing Java arguments] @@ -300,7 +300,7 @@ class StubGenerator: public StubCodeGenerator { // // Do a light-weight C-call here, r_new_arg_entry holds the address - // of the interpreter entry point (frame manager or native entry) + // of the interpreter entry point (template interpreter or native entry) // and save runtime-value of return_pc in return_address // (call by reference argument). return_address = __ call_stub(r_new_arg_entry); @@ -309,11 +309,11 @@ class StubGenerator: public StubCodeGenerator { { BLOCK_COMMENT("restore registers {"); - // Returned from frame manager or native entry. + // Returned from template interpreter or native entry. // Now pop frame, process result, and return to caller. // - // Stack on exit from frame manager / native entry: + // Stack on exit from template interpreter / native entry: // // F0 [ABI] // ... @@ -330,7 +330,7 @@ class StubGenerator: public StubCodeGenerator { __ pop_frame(); // Reload some volatile registers which we've spilled before the call - // to frame manager / native entry. + // to template interpreter / native entry. // Access all locals via frame pointer, because we know nothing about // the topmost frame's size. __ z_lg(r_arg_result_addr, result_address_offset, r_entryframe_fp); @@ -1468,11 +1468,120 @@ class StubGenerator: public StubCodeGenerator { return __ addr_at(start_off); } + // + // Generate 'unsafe' set memory stub + // Though just as safe as the other stubs, it takes an unscaled + // size_t (# bytes) argument instead of an element count. + // + // Input: + // Z_ARG1 - destination array address + // Z_ARG2 - byte count (size_t) + // Z_ARG3 - byte value + // + address generate_unsafe_setmemory(address unsafe_byte_fill) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, StubGenStubId::unsafe_setmemory_id); + unsigned int start_off = __ offset(); + + // bump this on entry, not on exit: + // inc_counter_np(SharedRuntime::_unsafe_set_memory_ctr); + + const Register dest = Z_ARG1; + const Register size = Z_ARG2; + const Register byteVal = Z_ARG3; + NearLabel tail, finished; + // fill_to_memory_atomic(unsigned char*, unsigned long, unsigned char) + + // Mark remaining code as such which performs Unsafe accesses. + UnsafeMemoryAccessMark umam(this, true, false); + + __ z_vlvgb(Z_V0, byteVal, 0); + __ z_vrepb(Z_V0, Z_V0, 0); + + __ z_aghi(size, -32); + __ z_brl(tail); + + { + NearLabel again; + __ bind(again); + __ z_vst(Z_V0, Address(dest, 0)); + __ z_vst(Z_V0, Address(dest, 16)); + __ z_aghi(dest, 32); + __ z_aghi(size, -32); + __ z_brnl(again); + } + + __ bind(tail); + + { + NearLabel dont; + __ testbit(size, 4); + __ z_brz(dont); + __ z_vst(Z_V0, Address(dest, 0)); + __ z_aghi(dest, 16); + __ bind(dont); + } + + { + NearLabel dont; + __ testbit(size, 3); + __ z_brz(dont); + __ z_vsteg(Z_V0, 0, Z_R0, dest, 0); + __ z_aghi(dest, 8); + __ bind(dont); + } + + __ z_tmll(size, 7); + __ z_brc(Assembler::bcondAllZero, finished); + + { + NearLabel dont; + __ testbit(size, 2); + __ z_brz(dont); + __ z_vstef(Z_V0, 0, Z_R0, dest, 0); + __ z_aghi(dest, 4); + __ bind(dont); + } + + { + NearLabel dont; + __ testbit(size, 1); + __ z_brz(dont); + __ z_vsteh(Z_V0, 0, Z_R0, dest, 0); + __ z_aghi(dest, 2); + __ bind(dont); + } + + { + NearLabel dont; + __ testbit(size, 0); + __ z_brz(dont); + __ z_vsteb(Z_V0, 0, Z_R0, dest, 0); + __ bind(dont); + } + + __ bind(finished); + __ z_br(Z_R14); + + return __ addr_at(start_off); + } + + // This is common errorexit stub for UnsafeMemoryAccess. + address generate_unsafecopy_common_error_exit() { + unsigned int start_off = __ offset(); + __ z_lghi(Z_RET, 0); // return 0 + __ z_br(Z_R14); + return __ addr_at(start_off); + } void generate_arraycopy_stubs() { // Note: the disjoint stubs must be generated first, some of // the conjoint stubs use them. + + address ucm_common_error_exit = generate_unsafecopy_common_error_exit(); + UnsafeMemoryAccess::set_common_exit_stub_pc(ucm_common_error_exit); + StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_nonoop_copy (StubGenStubId::jbyte_disjoint_arraycopy_id); StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_nonoop_copy(StubGenStubId::jshort_disjoint_arraycopy_id); StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_nonoop_copy (StubGenStubId::jint_disjoint_arraycopy_id); @@ -1500,6 +1609,12 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_nonoop_copy(StubGenStubId::arrayof_jlong_arraycopy_id); StubRoutines::_arrayof_oop_arraycopy = generate_conjoint_oop_copy(StubGenStubId::arrayof_oop_arraycopy_id); StubRoutines::_arrayof_oop_arraycopy_uninit = generate_conjoint_oop_copy(StubGenStubId::arrayof_oop_arraycopy_uninit_id); + +#ifdef COMPILER2 + StubRoutines::_unsafe_setmemory = + VM_Version::has_VectorFacility() ? generate_unsafe_setmemory(StubRoutines::_jbyte_fill) : nullptr; + +#endif // COMPILER2 } // Call interface for AES_encryptBlock, AES_decryptBlock stubs. @@ -3184,6 +3299,10 @@ class StubGenerator: public StubCodeGenerator { //---------------------------------------------------------------------- // Entry points that are platform specific. + if (UnsafeMemoryAccess::_table == nullptr) { + UnsafeMemoryAccess::create_table(4); // 4 for setMemory + } + if (UseCRC32Intrinsics) { StubRoutines::_crc_table_adr = (address)StubRoutines::zarch::_crc_table; StubRoutines::_updateBytesCRC32 = generate_CRC32_updateBytes(); diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp index a52d20e32a3..e03d891496a 100644 --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -637,6 +637,8 @@ address TemplateInterpreterGenerator::generate_return_entry_for (TosState state, Register sp_before_i2c_extension = Z_bcp; __ z_lg(Z_fp, _z_abi(callers_sp), Z_SP); // Restore frame pointer. __ z_lg(sp_before_i2c_extension, Address(Z_fp, _z_ijava_state_neg(top_frame_sp))); + __ z_slag(sp_before_i2c_extension, sp_before_i2c_extension, Interpreter::logStackElementSize); + __ z_agr(sp_before_i2c_extension, Z_fp); __ resize_frame_absolute(sp_before_i2c_extension, Z_locals/*tmp*/, true/*load_fp*/); // TODO(ZASM): necessary?? @@ -1134,7 +1136,11 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ z_agr(Z_locals, Z_esp); // z_ijava_state->locals - i*BytesPerWord points to i-th Java local (i starts at 0) // z_ijava_state->locals = Z_esp + parameter_count bytes - __ z_stg(Z_locals, _z_ijava_state_neg(locals), fp); + + __ z_sgrk(Z_R0, Z_locals, fp); // Z_R0 = Z_locals - fp(); + __ z_srlg(Z_R0, Z_R0, Interpreter::logStackElementSize); + // Store relativized Z_locals, see frame::interpreter_frame_locals(). + __ z_stg(Z_R0, _z_ijava_state_neg(locals), fp); // z_ijava_state->oop_temp = nullptr; __ store_const(Address(fp, oop_tmp_offset), 0); @@ -1168,9 +1174,14 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // z_ijava_state->monitors = fp - frame::z_ijava_state_size - Interpreter::stackElementSize; // z_ijava_state->esp = Z_esp = z_ijava_state->monitors; __ add2reg(Z_esp, -frame::z_ijava_state_size, fp); - __ z_stg(Z_esp, _z_ijava_state_neg(monitors), fp); + + __ z_sgrk(Z_R0, Z_esp, fp); + __ z_srag(Z_R0, Z_R0, Interpreter::logStackElementSize); + __ z_stg(Z_R0, _z_ijava_state_neg(monitors), fp); + __ add2reg(Z_esp, -Interpreter::stackElementSize); - __ z_stg(Z_esp, _z_ijava_state_neg(esp), fp); + + __ save_esp(fp); // z_ijava_state->cpoolCache = Z_R1_scratch (see load above); __ z_stg(Z_R1_scratch, _z_ijava_state_neg(cpoolCache), fp); @@ -1206,7 +1217,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { // Various method entries -// Math function, frame manager must set up an interpreter state, etc. +// Math function, template interpreter must set up an interpreter state, etc. address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { // Decide what to do: Use same platform specific instructions and runtime calls as compilers. @@ -1229,6 +1240,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M case Interpreter::java_lang_math_cos : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); break; case Interpreter::java_lang_math_tan : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); break; case Interpreter::java_lang_math_tanh : /* run interpreted */ break; + case Interpreter::java_lang_math_cbrt : /* run interpreted */ break; case Interpreter::java_lang_math_abs : /* run interpreted */ break; case Interpreter::java_lang_math_sqrt : /* runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); not available */ break; case Interpreter::java_lang_math_log : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); break; @@ -1627,7 +1639,7 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ add2reg(Rfirst_monitor, -(frame::z_ijava_state_size + (int)sizeof(BasicObjectLock)), Z_fp); #ifdef ASSERT NearLabel ok; - __ z_lg(Z_R1, _z_ijava_state_neg(monitors), Z_fp); + __ get_monitors(Z_R1); __ compareU64_and_branch(Rfirst_monitor, Z_R1, Assembler::bcondEqual, ok); reentry = __ stop_chain_static(reentry, "native_entry:unlock: inconsistent z_ijava_state.monitors"); __ bind(ok); diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp index 4262c77ecd7..2b39cc8318c 100644 --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -65,7 +65,8 @@ // The actual size of each block heavily depends on the CPU capabilities and, // of course, on the logic implemented in each block. #ifdef ASSERT - #define BTB_MINSIZE 256 +// With introduced assert in get_monitor() & set_monitor(), required block size is now 322. + #define BTB_MINSIZE 512 #else #define BTB_MINSIZE 64 #endif @@ -91,7 +92,8 @@ if (len > alignment) { \ tty->print_cr("%4d of %4d @ " INTPTR_FORMAT ": Block len for %s", \ len, alignment, e_addr-len, name); \ - guarantee(len <= alignment, "block too large"); \ + guarantee(len <= alignment, "block too large, len = %d, alignment = %d", \ + len, alignment); \ } \ guarantee(len == e_addr-b_addr, "block len mismatch"); \ } @@ -112,7 +114,8 @@ if (len > alignment) { \ tty->print_cr("%4d of %4d @ " INTPTR_FORMAT ": Block len for %s", \ len, alignment, e_addr-len, name); \ - guarantee(len <= alignment, "block too large"); \ + guarantee(len <= alignment, "block too large, len = %d, alignment = %d", \ + len, alignment); \ } \ guarantee(len == e_addr-b_addr, "block len mismatch"); \ } diff --git a/src/hotspot/cpu/s390/vm_version_s390.cpp b/src/hotspot/cpu/s390/vm_version_s390.cpp index 157b945e6e1..8261fbd083a 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.cpp +++ b/src/hotspot/cpu/s390/vm_version_s390.cpp @@ -90,7 +90,7 @@ static const char* z_features[] = {" ", void VM_Version::initialize() { determine_features(); // Get processor capabilities. - set_features_string(); // Set a descriptive feature indication. + set_cpu_info_string(); // Set a descriptive feature indication. if (Verbose || PrintAssembly || PrintStubCode) { print_features_internal("CPU Version as detected internally:", PrintAssembly || PrintStubCode); @@ -388,9 +388,9 @@ int VM_Version::get_model_index() { } -void VM_Version::set_features_string() { - // A note on the _features_string format: - // There are jtreg tests checking the _features_string for various properties. +void VM_Version::set_cpu_info_string() { + // A note on the _cpu_info_string format: + // There are jtreg tests checking the _cpu_info_string for various properties. // For some strange reason, these tests require the string to contain // only _lowercase_ characters. Keep that in mind when being surprised // about the unusual notation of features - and when adding new ones. @@ -412,29 +412,29 @@ void VM_Version::set_features_string() { _model_string = "unknown model"; strcpy(buf, "z/Architecture (ambiguous detection)"); } - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); if (has_Crypto_AES()) { - assert(strlen(_features_string) + 3*8 < sizeof(buf), "increase buffer size"); + assert(strlen(_cpu_info_string) + 3*8 < sizeof(buf), "increase buffer size"); jio_snprintf(buf, sizeof(buf), "%s%s%s%s", - _features_string, + _cpu_info_string, has_Crypto_AES128() ? ", aes128" : "", has_Crypto_AES192() ? ", aes192" : "", has_Crypto_AES256() ? ", aes256" : ""); - os::free((void *)_features_string); - _features_string = os::strdup(buf); + os::free((void *)_cpu_info_string); + _cpu_info_string = os::strdup(buf); } if (has_Crypto_SHA()) { - assert(strlen(_features_string) + 6 + 2*8 + 7 < sizeof(buf), "increase buffer size"); + assert(strlen(_cpu_info_string) + 6 + 2*8 + 7 < sizeof(buf), "increase buffer size"); jio_snprintf(buf, sizeof(buf), "%s%s%s%s%s", - _features_string, + _cpu_info_string, has_Crypto_SHA1() ? ", sha1" : "", has_Crypto_SHA256() ? ", sha256" : "", has_Crypto_SHA512() ? ", sha512" : "", has_Crypto_GHASH() ? ", ghash" : ""); - os::free((void *)_features_string); - _features_string = os::strdup(buf); + os::free((void *)_cpu_info_string); + _cpu_info_string = os::strdup(buf); } } @@ -464,7 +464,7 @@ bool VM_Version::test_feature_bit(unsigned long* featureBuffer, int featureNum, } void VM_Version::print_features_internal(const char* text, bool print_anyway) { - tty->print_cr("%s %s", text, features_string()); + tty->print_cr("%s %s", text, cpu_info_string()); tty->cr(); if (Verbose || print_anyway) { @@ -906,7 +906,7 @@ void VM_Version::set_features_from(const char* march) { err = true; } if (!err) { - set_features_string(); + set_cpu_info_string(); if (prt || PrintAssembly) { print_features_internal("CPU Version as set by cmdline option:", prt); } @@ -1542,6 +1542,6 @@ void VM_Version::initialize_cpu_information(void) { _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()); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "s390 %s", cpu_info_string()); _initialized = true; } diff --git a/src/hotspot/cpu/s390/vm_version_s390.hpp b/src/hotspot/cpu/s390/vm_version_s390.hpp index 49e6f5686f6..6c6eb76bf7b 100644 --- a/src/hotspot/cpu/s390/vm_version_s390.hpp +++ b/src/hotspot/cpu/s390/vm_version_s390.hpp @@ -148,7 +148,7 @@ class VM_Version: public Abstract_VM_Version { static bool test_feature_bit(unsigned long* featureBuffer, int featureNum, unsigned int bufLen); static int get_model_index(); - static void set_features_string(); + static void set_cpu_info_string(); static void print_features_internal(const char* text, bool print_anyway=false); static void determine_features(); static long call_getFeatures(unsigned long* buffer, int buflen, int functionCode); diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 6853af9e746..897b06e94df 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -280,15 +280,14 @@ void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) { emit_int24(op1, (op2 | encode(dst)), imm8); } - -void Assembler::emit_arith(int op1, int op2, Register dst, int32_t imm32) { +void Assembler::emit_arith(int op1, int op2, Register dst, int32_t imm32, bool optimize_rax_dst) { assert(isByte(op1) && isByte(op2), "wrong opcode"); assert(op1 == 0x81, "Unexpected opcode"); if (is8bit(imm32)) { emit_int24(op1 | 0x02, // set sign bit op2 | encode(dst), imm32 & 0xFF); - } else if (dst == rax) { + } else if (optimize_rax_dst && dst == rax) { switch (op2) { case 0xD0: emit_int8(0x15); break; // adc case 0xC0: emit_int8(0x05); break; // add @@ -307,21 +306,6 @@ void Assembler::emit_arith(int op1, int op2, Register dst, int32_t imm32) { } } -void Assembler::emit_arith_ndd(int op1, int op2, Register dst, int32_t imm32) { - assert(isByte(op1) && isByte(op2), "wrong opcode"); - assert(op1 == 0x81, "Unexpected opcode"); - // This code cache friendly optimization saves 3 bytes per encoding, which offsets the EVEX encoding penalty. - if (is8bit(imm32)) { - emit_int24(op1 | 0x02, // set sign bit - op2 | encode(dst), - imm32 & 0xFF); - } - else { - emit_int16(op1, (op2 | encode(dst))); - emit_int32(imm32); - } -} - // Force generation of a 4 byte immediate value even if it fits into 8bit void Assembler::emit_arith_imm32(int op1, int op2, Register dst, int32_t imm32) { assert(isByte(op1) && isByte(op2), "wrong opcode"); @@ -801,7 +785,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { address ip = inst; bool is_64bit = false; - debug_only(bool has_disp32 = false); + DEBUG_ONLY(bool has_disp32 = false); int tail_size = 0; // other random bytes (#32, #16, etc.) at end of insn again_after_prefix: @@ -859,7 +843,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x8A: // movb r, a case 0x8B: // movl r, a case 0x8F: // popl a - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; case 0x68: // pushq #32 @@ -898,10 +882,10 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x8B: // movw r, a case 0x89: // movw a, r - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; case 0xC7: // movw a, #16 - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); tail_size = 2; // the imm16 break; case 0x0F: // several SSE/SSE2 variants @@ -923,7 +907,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x69: // imul r, a, #32 case 0xC7: // movl a, #32(oop?) tail_size = 4; - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0x0F: // movx..., etc. @@ -932,11 +916,11 @@ address Assembler::locate_operand(address inst, WhichOperand which) { tail_size = 1; case 0x38: // ptest, pmovzxbw ip++; // skip opcode - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0x70: // pshufd r, r/a, #8 - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! case 0x73: // psrldq r, #8 tail_size = 1; break; @@ -961,7 +945,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0xAE: // ldmxcsr, stmxcsr, fxrstor, fxsave, clflush case 0xD6: // movq case 0xFE: // paddd - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; case 0xAD: // shrd r, a, %cl @@ -976,18 +960,18 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0xC1: // xaddl case 0xC7: // cmpxchg8 case REP16(0x90): // setcc a - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); // fall out of the switch to decode the address break; case 0xC4: // pinsrw r, a, #8 - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); case 0xC5: // pextrw r, r, #8 tail_size = 1; // the imm8 break; case 0xAC: // shrd r, a, #8 - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); tail_size = 1; // the imm8 break; @@ -1004,12 +988,12 @@ address Assembler::locate_operand(address inst, WhichOperand which) { // also: orl, adcl, sbbl, andl, subl, xorl, cmpl // on 32bit in the case of cmpl, the imm might be an oop tail_size = 4; - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0x83: // addl a, #8; addl r, #8 // also: orl, adcl, sbbl, andl, subl, xorl, cmpl - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! tail_size = 1; break; @@ -1026,7 +1010,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x9B: switch (0xFF & *ip++) { case 0xD9: // fnstcw a - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; default: ShouldNotReachHere(); @@ -1045,7 +1029,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0x87: // xchg r, a case REP4(0x38): // cmp... case 0x85: // test r, a - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0xA8: // testb rax, #8 @@ -1057,7 +1041,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0xC6: // movb a, #8 case 0x80: // cmpb a, #8 case 0x6B: // imul r, a, #8 - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! tail_size = 1; // the imm8 break; @@ -1109,7 +1093,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { break; } ip++; // skip opcode - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0x62: // EVEX_4bytes @@ -1135,7 +1119,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { break; } ip++; // skip opcode - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; case 0xD1: // sal a, 1; sar a, 1; shl a, 1; shr a, 1 @@ -1147,7 +1131,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case 0xD8: // fadd_s a; fsubr_s a; fmul_s a; fdivr_s a; fcomp_s a case 0xDC: // fadd_d a; fsubr_d a; fmul_d a; fdivr_d a; fcomp_d a case 0xDE: // faddp_d a; fsubrp_d a; fmulp_d a; fdivrp_d a; fcompp_d a - debug_only(has_disp32 = true); + DEBUG_ONLY(has_disp32 = true); break; case 0xE8: // call rdisp32 @@ -1184,7 +1168,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { default: ip++; } - debug_only(has_disp32 = true); // has both kinds of operands! + DEBUG_ONLY(has_disp32 = true); // has both kinds of operands! break; default: @@ -1364,7 +1348,7 @@ void Assembler::eaddl(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, rax, src, imm32); } @@ -1416,7 +1400,7 @@ void Assembler::eaddl(Register dst, Address src1, Register src2, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x01); emit_operand(src2, src1, 0); } @@ -1427,9 +1411,7 @@ void Assembler::addl(Register dst, int32_t imm32) { } void Assembler::eaddl(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xC0, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x81, 0xC0, no_flags); } void Assembler::addl(Register dst, Address src) { @@ -1441,11 +1423,7 @@ void Assembler::addl(Register dst, Address src) { void Assembler::eaddl(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x03); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x03, no_flags); } void Assembler::addl(Register dst, Register src) { @@ -1457,7 +1435,7 @@ void Assembler::eaddl(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void)evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void)emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith(0x03, 0xC0, src1, src2); } @@ -1647,7 +1625,7 @@ void Assembler::eandl(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, rsp, src, imm32); } @@ -1657,9 +1635,7 @@ void Assembler::andl(Register dst, int32_t imm32) { } void Assembler::eandl(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xE0, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x81, 0xE0, no_flags); } void Assembler::andl(Address dst, Register src) { @@ -1678,11 +1654,7 @@ void Assembler::andl(Register dst, Address src) { void Assembler::eandl(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x23); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x23, no_flags); } void Assembler::andl(Register dst, Register src) { @@ -1694,7 +1666,7 @@ void Assembler::eandl(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith(0x23, 0xC0, src1, src2); } @@ -1841,9 +1813,7 @@ void Assembler::cmovl(Condition cc, Register dst, Register src) { } void Assembler::ecmovl(Condition cc, Register dst, Register src1, Register src2) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); - emit_int16((0x40 | cc), (0xC0 | encode)); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x40 | cc, false /* no_flags */, true /* is_map1 */, true /* swap */); } void Assembler::cmovl(Condition cc, Register dst, Address src) { @@ -1855,11 +1825,7 @@ void Assembler::cmovl(Condition cc, Register dst, Address src) { void Assembler::ecmovl(Condition cc, Register dst, Register src1, Address src2) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); - emit_int8((0x40 | cc)); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, (0x40 | cc) , false /* no_flags */, true /* is_map1 */); } void Assembler::cmpb(Address dst, Register reg) { @@ -2010,6 +1976,11 @@ void Assembler::cpuid() { emit_int16(0x0F, (unsigned char)0xA2); } +void Assembler::serialize() { + assert(VM_Version::supports_serialize(), ""); + emit_int24(0x0F, 0x01, 0xE8); +} + // Opcode / Instruction Op / En 64 - Bit Mode Compat / Leg Mode Description Implemented // F2 0F 38 F0 / r CRC32 r32, r / m8 RM Valid Valid Accumulate CRC32 on r / m8. v // F2 REX 0F 38 F0 / r CRC32 r32, r / m8* RM Valid N.E. Accumulate CRC32 on r / m8. - @@ -2024,7 +1995,7 @@ void Assembler::crc32(Register crc, Register v, int8_t sizeInBytes) { assert(VM_Version::supports_sse4_2(), ""); if (needs_eevex(crc, v)) { InstructionAttr attributes(AVX_128bit, /* rex_w */ sizeInBytes == 8, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(crc->encoding(), 0, v->encoding(), sizeInBytes == 2 ? VEX_SIMD_66 : VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, true); + int encode = vex_prefix_and_encode(crc->encoding(), 0, v->encoding(), sizeInBytes == 2 ? VEX_SIMD_66 : VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, true); emit_int16(sizeInBytes == 1 ? (unsigned char)0xF0 : (unsigned char)0xF1, (0xC0 | encode)); } else { int8_t w = 0x01; @@ -2071,7 +2042,7 @@ void Assembler::crc32(Register crc, Address adr, int8_t sizeInBytes) { if (needs_eevex(crc, adr.base(), adr.index())) { InstructionAttr attributes(AVX_128bit, /* vex_w */ sizeInBytes == 8, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - vex_prefix(adr, 0, crc->encoding(), sizeInBytes == 2 ? VEX_SIMD_66 : VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); + vex_prefix(adr, 0, crc->encoding(), sizeInBytes == 2 ? VEX_SIMD_66 : VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes); emit_int8(sizeInBytes == 1 ? (unsigned char)0xF0 : (unsigned char)0xF1); emit_operand(crc, adr, 0); } else { @@ -2468,7 +2439,7 @@ void Assembler::edecl(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xFF); emit_operand(rcx, src, 0); } @@ -2516,7 +2487,7 @@ void Assembler::idivl(Register src) { void Assembler::eidivl(Register src, bool no_flags) { // Signed InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF7, (0xF8 | encode)); } @@ -2527,7 +2498,7 @@ void Assembler::divl(Register src) { // Unsigned void Assembler::edivl(Register src, bool no_flags) { // Unsigned InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF7, (0xF0 | encode)); } @@ -2538,7 +2509,7 @@ void Assembler::imull(Register src) { void Assembler::eimull(Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF7, (0xE8 | encode)); } @@ -2548,9 +2519,7 @@ void Assembler::imull(Register dst, Register src) { } void Assembler::eimull(Register dst, Register src1, Register src2, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int16((unsigned char)0xAF, (0xC0 | encode)); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0xAF, no_flags, true /* is_map1 */, true /* swap */); } void Assembler::imull(Register dst, Address src, int32_t value) { @@ -2571,7 +2540,7 @@ void Assembler::eimull(Register dst, Address src, int32_t value, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (is8bit(value)) { emit_int8((unsigned char)0x6B); emit_operand(dst, src, 1); @@ -2595,7 +2564,7 @@ void Assembler::imull(Register dst, Register src, int value) { void Assembler::eimull(Register dst, Register src, int value, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (is8bit(value)) { emit_int24(0x6B, (0xC0 | encode), value & 0xFF); } else { @@ -2613,11 +2582,7 @@ void Assembler::imull(Register dst, Address src) { void Assembler::eimull(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8((unsigned char)0xAF); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, (unsigned char)0xAF, no_flags, true /* is_map1 */); } void Assembler::incl(Address dst) { @@ -2633,7 +2598,7 @@ void Assembler::eincl(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xFF); emit_operand(rax, src, 0); } @@ -2825,7 +2790,7 @@ void Assembler::lzcntl(Register dst, Register src) { void Assembler::elzcntl(Register dst, Register src, bool no_flags) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } @@ -2843,7 +2808,7 @@ void Assembler::elzcntl(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xF5); emit_operand(dst, src, 0); } @@ -2862,6 +2827,17 @@ void Assembler::mov(Register dst, Register src) { movq(dst, src); } +void Assembler::movapd(XMMRegister dst, Address src) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionMark im(this); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + attributes.set_rex_vex_w_reverted(); + simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int8(0x28); + emit_operand(dst, src, 0); +} + void Assembler::movapd(XMMRegister dst, XMMRegister src) { int vector_len = VM_Version::supports_avx512novl() ? AVX_512bit : AVX_128bit; InstructionAttr attributes(vector_len, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); @@ -4050,7 +4026,7 @@ void Assembler::emull(Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_nf(src, 0, 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xF7); emit_operand(rsp, src, 0); } @@ -4062,7 +4038,7 @@ void Assembler::mull(Register src) { void Assembler::emull(Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF7, (0xE0 | encode)); } @@ -4105,7 +4081,7 @@ void Assembler::negl(Register dst) { void Assembler::enegl(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF7, (0xD8 | encode)); } @@ -4120,7 +4096,7 @@ void Assembler::enegl(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xF7); emit_operand(as_Register(3), src, 0); } @@ -4438,7 +4414,7 @@ void Assembler::notl(Register dst) { void Assembler::enotl(Register dst, Register src) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes); emit_int16((unsigned char)0xF7, (0xD0 | encode)); } @@ -4446,7 +4422,7 @@ void Assembler::eorw(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_66, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith(0x0B, 0xC0, src1, src2); } @@ -4460,7 +4436,7 @@ void Assembler::eorl(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, rcx, src, imm32); } @@ -4470,9 +4446,7 @@ void Assembler::orl(Register dst, int32_t imm32) { } void Assembler::eorl(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xC8, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x81, 0xC8, no_flags); } void Assembler::orl(Register dst, Address src) { @@ -4484,11 +4458,7 @@ void Assembler::orl(Register dst, Address src) { void Assembler::eorl(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x0B); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x0B, no_flags); } void Assembler::orl(Register dst, Register src) { @@ -4500,7 +4470,7 @@ void Assembler::eorl(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith(0x0B, 0xC0, src1, src2); } @@ -4515,7 +4485,7 @@ void Assembler::eorl(Register dst, Address src1, Register src2, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x09); emit_operand(src2, src1, 0); } @@ -4532,7 +4502,7 @@ void Assembler::eorb(Register dst, Address src, int imm8, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0x80); emit_operand(rcx, src, 1); emit_int8(imm8); @@ -4549,7 +4519,7 @@ void Assembler::eorb(Register dst, Address src1, Register src2, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x08); emit_operand(src2, src1, 0); } @@ -4584,7 +4554,7 @@ void Assembler::packuswb(XMMRegister dst, Address src) { assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8(0x67); emit_operand(dst, src, 0); @@ -4648,6 +4618,7 @@ void Assembler::vpermb(XMMRegister dst, XMMRegister nds, Address src, int vector InstructionMark im(this); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0x8D); emit_operand(dst, src, 0); @@ -4678,6 +4649,7 @@ void Assembler::vpermd(XMMRegister dst, XMMRegister nds, Address src, int vector // VEX.NDS.256.66.0F38.W0 36 /r InstructionMark im(this); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8(0x36); emit_operand(dst, src, 0); @@ -5387,7 +5359,7 @@ void Assembler::evpmovzxbd(XMMRegister dst, KRegister mask, Address src, int vec assert(dst != xnoreg, "sanity"); InstructionMark im(this); InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ false, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_HVM, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_QVM, /* input_size_in_bits */ EVEX_NObit); attributes.set_embedded_opmask_register_specifier(mask); attributes.set_is_evex_instruction(); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); @@ -5675,7 +5647,7 @@ void Assembler::epopcntl(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0x88); emit_operand(dst, src, 0); } @@ -5690,7 +5662,7 @@ void Assembler::popcntl(Register dst, Register src) { void Assembler::epopcntl(Register dst, Register src, bool no_flags) { assert(VM_Version::supports_popcnt(), "must support"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0x88, (0xC0 | encode)); } @@ -6241,7 +6213,7 @@ void Assembler::rcll(Register dst, int imm8) { void Assembler::ercll(Register dst, Register src, int imm8) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xD0 | encode)); } else { @@ -6324,7 +6296,7 @@ void Assembler::roll(Register dst, int imm8) { void Assembler::eroll(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xC0 | encode)); } else { @@ -6339,7 +6311,7 @@ void Assembler::roll(Register dst) { void Assembler::eroll(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xD3, (0xC0 | encode)); } @@ -6356,7 +6328,7 @@ void Assembler::rorl(Register dst, int imm8) { void Assembler::erorl(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xC8 | encode)); } else { @@ -6371,7 +6343,7 @@ void Assembler::rorl(Register dst) { void Assembler::erorl(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xD3, (0xC8 | encode)); } @@ -6382,7 +6354,7 @@ void Assembler::rorq(Register dst) { void Assembler::erorq(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_int16((unsigned char)0xD3, (0xC8 | encode)); } @@ -6399,7 +6371,7 @@ void Assembler::rorq(Register dst, int imm8) { void Assembler::erorq(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xC8 | encode)); } else { @@ -6414,7 +6386,7 @@ void Assembler::rolq(Register dst) { void Assembler::erolq(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_int16((unsigned char)0xD3, (0xC0 | encode)); } @@ -6431,7 +6403,7 @@ void Assembler::rolq(Register dst, int imm8) { void Assembler::erolq(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xC0 | encode)); } else { @@ -6459,7 +6431,7 @@ void Assembler::esall(Register dst, Address src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int8((unsigned char)0xD1); emit_operand(as_Register(4), src, 0); @@ -6482,7 +6454,7 @@ void Assembler::esall(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xD3); emit_operand(as_Register(4), src, 0); } @@ -6500,7 +6472,7 @@ void Assembler::sall(Register dst, int imm8) { void Assembler::esall(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xE0 | encode)); } else { @@ -6515,7 +6487,7 @@ void Assembler::sall(Register dst) { void Assembler::esall(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xD3, (0xE0 | encode)); } @@ -6539,7 +6511,7 @@ void Assembler::esarl(Register dst, Address src, int imm8, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int8((unsigned char)0xD1); emit_operand(as_Register(7), src, 0); @@ -6562,7 +6534,7 @@ void Assembler::esarl(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xD3); emit_operand(as_Register(7), src, 0); } @@ -6580,7 +6552,7 @@ void Assembler::sarl(Register dst, int imm8) { void Assembler::esarl(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xF8 | encode)); } else { @@ -6595,7 +6567,7 @@ void Assembler::sarl(Register dst) { void Assembler::esarl(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xD3, (0xF8 | encode)); } @@ -6736,7 +6708,7 @@ void Assembler::shll(Register dst, int imm8) { void Assembler::eshll(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1 ) { emit_int16((unsigned char)0xD1, (0xE0 | encode)); } else { @@ -6751,7 +6723,7 @@ void Assembler::shll(Register dst) { void Assembler::eshll(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xD3, (0xE0 | encode)); } @@ -6769,7 +6741,7 @@ void Assembler::shrl(Register dst, int imm8) { void Assembler::eshrl(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xE8 | encode)); } @@ -6785,7 +6757,7 @@ void Assembler::shrl(Register dst) { void Assembler::eshrl(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xD3, (0xE8 | encode)); } @@ -6800,7 +6772,7 @@ void Assembler::eshrl(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xD3); emit_operand(as_Register(5), src, 0); } @@ -6825,7 +6797,7 @@ void Assembler::eshrl(Register dst, Address src, int imm8, bool no_flags) { assert(isShiftCount(imm8), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int8((unsigned char)0xD1); emit_operand(as_Register(5), src, 0); @@ -6843,11 +6815,7 @@ void Assembler::shldl(Register dst, Register src) { } void Assembler::eshldl(Register dst, Register src1, Register src2, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - // NDD shares its encoding bits with NDS bits for regular EVEX instruction. - // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - int encode = evex_prefix_and_encode_ndd(src2->encoding(), dst->encoding(), src1->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int16(0xA5, (0xC0 | encode)); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0xA5, no_flags, true /* is_map1 */); } void Assembler::shldl(Register dst, Register src, int8_t imm8) { @@ -6856,11 +6824,7 @@ void Assembler::shldl(Register dst, Register src, int8_t imm8) { } void Assembler::eshldl(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - // NDD shares its encoding bits with NDS bits for regular EVEX instruction. - // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - int encode = evex_prefix_and_encode_ndd(src2->encoding(), dst->encoding(), src1->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int24(0x24, (0xC0 | encode), imm8); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), imm8, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x24, no_flags, true /* is_map1 */); } void Assembler::shrdl(Register dst, Register src) { @@ -6869,11 +6833,7 @@ void Assembler::shrdl(Register dst, Register src) { } void Assembler::eshrdl(Register dst, Register src1, Register src2, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - // NDD shares its encoding bits with NDS bits for regular EVEX instruction. - // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - int encode = evex_prefix_and_encode_ndd(src2->encoding(), dst->encoding(), src1->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int16(0xAD, (0xC0 | encode)); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0xAD, no_flags, true /* is_map1 */); } void Assembler::shrdl(Register dst, Register src, int8_t imm8) { @@ -6882,11 +6842,7 @@ void Assembler::shrdl(Register dst, Register src, int8_t imm8) { } void Assembler::eshrdl(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - // NDD shares its encoding bits with NDS bits for regular EVEX instruction. - // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - int encode = evex_prefix_and_encode_ndd(src2->encoding(), dst->encoding(), src1->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int24(0x2C, (0xC0 | encode), imm8); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), imm8, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x2C, no_flags, true /* is_map1 */); } void Assembler::shldq(Register dst, Register src, int8_t imm8) { @@ -6895,11 +6851,7 @@ void Assembler::shldq(Register dst, Register src, int8_t imm8) { } void Assembler::eshldq(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - // NDD shares its encoding bits with NDS bits for regular EVEX instruction. - // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - int encode = evex_prefix_and_encode_ndd(src2->encoding(), dst->encoding(), src1->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int24(0x24, (0xC0 | encode), imm8); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), imm8, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x24, no_flags, true /* is_map1 */); } void Assembler::shrdq(Register dst, Register src, int8_t imm8) { @@ -6908,11 +6860,7 @@ void Assembler::shrdq(Register dst, Register src, int8_t imm8) { } void Assembler::eshrdq(Register dst, Register src1, Register src2, int8_t imm8, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - // NDD shares its encoding bits with NDS bits for regular EVEX instruction. - // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - int encode = evex_prefix_and_encode_ndd(src2->encoding(), dst->encoding(), src1->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int24(0x2C, (0xC0 | encode), imm8); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), imm8, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x2C, no_flags, true /* is_map1 */); } // copies a single word from [esi] to [edi] @@ -7002,7 +6950,7 @@ void Assembler::esubl(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, rbp, src, imm32); } @@ -7017,7 +6965,7 @@ void Assembler::esubl(Register dst, Address src1, Register src2, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x29); emit_operand(src2, src1, 0); } @@ -7028,9 +6976,7 @@ void Assembler::subl(Register dst, int32_t imm32) { } void Assembler::esubl(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xE8, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x81, 0xE8, no_flags); } // Force generation of a 4 byte immediate value even if it fits into 8bit @@ -7041,7 +6987,7 @@ void Assembler::subl_imm32(Register dst, int32_t imm32) { void Assembler::esubl_imm32(Register dst, Register src, int32_t imm32, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_imm32(0x81, 0xE8, src, imm32); } @@ -7054,11 +7000,7 @@ void Assembler::subl(Register dst, Address src) { void Assembler::esubl(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x2B); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x2B, no_flags); } void Assembler::subl(Register dst, Register src) { @@ -7070,7 +7012,7 @@ void Assembler::esubl(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith(0x2B, 0xC0, src1, src2); } @@ -7175,7 +7117,7 @@ void Assembler::tzcntl(Register dst, Register src) { void Assembler::etzcntl(Register dst, Register src, bool no_flags) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF4, (0xC0 | encode)); } @@ -7193,7 +7135,7 @@ void Assembler::etzcntl(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xF4); emit_operand(dst, src, 0); } @@ -7208,7 +7150,7 @@ void Assembler::tzcntq(Register dst, Register src) { void Assembler::etzcntq(Register dst, Register src, bool no_flags) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF4, (0xC0 | encode)); } @@ -7226,7 +7168,7 @@ void Assembler::etzcntq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xF4); emit_operand(dst, src, 0); } @@ -7350,7 +7292,7 @@ void Assembler::exorl(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, as_Register(6), src, imm32); } @@ -7360,9 +7302,7 @@ void Assembler::xorl(Register dst, int32_t imm32) { } void Assembler::exorl(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xF0, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x81, 0xF0, no_flags); } void Assembler::xorl(Register dst, Address src) { @@ -7374,11 +7314,7 @@ void Assembler::xorl(Register dst, Address src) { void Assembler::exorl(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x33); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_32bit, 0x33, no_flags); } void Assembler::xorl(Register dst, Register src) { @@ -7390,7 +7326,7 @@ void Assembler::exorl(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith(0x33, 0xC0, src1, src2); } @@ -7405,7 +7341,7 @@ void Assembler::exorl(Register dst, Address src1, Register src2, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x31); emit_operand(src2, src1, 0); } @@ -7419,11 +7355,7 @@ void Assembler::xorb(Register dst, Address src) { void Assembler::exorb(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x32); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_8bit, 0x32, no_flags); } void Assembler::xorb(Address dst, Register src) { @@ -7437,7 +7369,7 @@ void Assembler::exorb(Register dst, Address src1, Register src2, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_8bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x30); emit_operand(src2, src1, 0); } @@ -7452,13 +7384,7 @@ void Assembler::xorw(Register dst, Address src) { void Assembler::exorw(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_16bit); - // NDD shares its encoding bits with NDS bits for regular EVEX instruction. - // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_66, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x33); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_66, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_16bit, 0x33, no_flags); } // AVX 3-operands scalar float-point arithmetic instructions @@ -8065,6 +7991,14 @@ void Assembler::vandps(XMMRegister dst, XMMRegister nds, Address src, int vector emit_operand(dst, src, 0); } +void Assembler::orpd(XMMRegister dst, XMMRegister src) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_rex_vex_w_reverted(); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16(0x56, (0xC0 | encode)); +} + void Assembler::unpckhpd(XMMRegister dst, XMMRegister src) { InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_rex_vex_w_reverted(); @@ -8186,6 +8120,7 @@ void Assembler::paddd(XMMRegister dst, XMMRegister src) { void Assembler::paddd(XMMRegister dst, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xFE); emit_operand(dst, src, 0); @@ -8359,7 +8294,7 @@ void Assembler::vpaddsb(XMMRegister dst, XMMRegister nds, Address src, int vecto assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xEC); emit_operand(dst, src, 0); @@ -8378,7 +8313,7 @@ void Assembler::vpaddsw(XMMRegister dst, XMMRegister nds, Address src, int vecto assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xED); emit_operand(dst, src, 0); @@ -8397,7 +8332,7 @@ void Assembler::vpaddusb(XMMRegister dst, XMMRegister nds, Address src, int vect assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xDC); emit_operand(dst, src, 0); @@ -8417,7 +8352,7 @@ void Assembler::vpaddusw(XMMRegister dst, XMMRegister nds, Address src, int vect assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xDD); emit_operand(dst, src, 0); @@ -8437,7 +8372,7 @@ void Assembler::vpsubsb(XMMRegister dst, XMMRegister nds, Address src, int vecto assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xE8); emit_operand(dst, src, 0); @@ -8456,7 +8391,7 @@ void Assembler::vpsubsw(XMMRegister dst, XMMRegister nds, Address src, int vecto assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xE9); emit_operand(dst, src, 0); @@ -8475,7 +8410,7 @@ void Assembler::vpsubusb(XMMRegister dst, XMMRegister nds, Address src, int vect assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD8); emit_operand(dst, src, 0); @@ -8494,7 +8429,7 @@ void Assembler::vpsubusw(XMMRegister dst, XMMRegister nds, Address src, int vect assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xD9); emit_operand(dst, src, 0); @@ -8862,7 +8797,7 @@ void Assembler::vpminub(XMMRegister dst, XMMRegister nds, Address src, int vecto assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xDA); emit_operand(dst, src, 0); @@ -8885,7 +8820,7 @@ void Assembler::evpminub(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { attributes.reset_is_clear_context(); @@ -8908,7 +8843,7 @@ void Assembler::vpminuw(XMMRegister dst, XMMRegister nds, Address src, int vecto assert(!needs_evex(dst, nds) || VM_Version::supports_avx512bw(), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0x3A); emit_operand(dst, src, 0); @@ -8931,7 +8866,7 @@ void Assembler::evpminuw(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { attributes.reset_is_clear_context(); @@ -9031,7 +8966,7 @@ void Assembler::vpmaxub(XMMRegister dst, XMMRegister nds, Address src, int vecto assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0xDE); emit_operand(dst, src, 0); @@ -9054,7 +8989,7 @@ void Assembler::evpmaxub(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { attributes.reset_is_clear_context(); @@ -9079,7 +9014,7 @@ void Assembler::vpmaxuw(XMMRegister dst, XMMRegister nds, Address src, int vecto assert(UseAVX > 0 && (vector_len == Assembler::AVX_512bit || (!needs_evex(dst, nds) || VM_Version::supports_avx512vl())), ""); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0x3E); emit_operand(dst, src, 0); @@ -9102,7 +9037,7 @@ void Assembler::evpmaxuw(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { attributes.reset_is_clear_context(); @@ -9205,7 +9140,8 @@ void Assembler::pslld(XMMRegister dst, int shift) { } void Assembler::psllq(XMMRegister dst, int shift) { - InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_rex_vex_w_reverted(); // XMM6 is for /6 encoding: 66 0F 73 /6 ib int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int24(0x73, (0xC0 | encode), shift & 0xFF); @@ -10547,7 +10483,7 @@ void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, Addres InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -10574,7 +10510,7 @@ void Assembler::evpaddw(XMMRegister dst, KRegister mask, XMMRegister nds, Addres InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -10717,7 +10653,7 @@ void Assembler::evpsubb(XMMRegister dst, KRegister mask, XMMRegister nds, Addres InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -10744,7 +10680,7 @@ void Assembler::evpsubw(XMMRegister dst, KRegister mask, XMMRegister nds, Addres InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -10887,7 +10823,7 @@ void Assembler::evpaddsb(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -10914,7 +10850,7 @@ void Assembler::evpaddsw(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -10941,7 +10877,7 @@ void Assembler::evpaddusb(XMMRegister dst, KRegister mask, XMMRegister nds, Addr InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -10968,7 +10904,7 @@ void Assembler::evpaddusw(XMMRegister dst, KRegister mask, XMMRegister nds, Addr InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -10995,7 +10931,7 @@ void Assembler::evpsubsb(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11022,7 +10958,7 @@ void Assembler::evpsubsw(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11049,7 +10985,7 @@ void Assembler::evpsubusb(XMMRegister dst, KRegister mask, XMMRegister nds, Addr InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11077,7 +11013,7 @@ void Assembler::evpsubusw(XMMRegister dst, KRegister mask, XMMRegister nds, Addr InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11104,7 +11040,7 @@ void Assembler::evpmullw(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11370,7 +11306,6 @@ void Assembler::evdivsd(XMMRegister dst, XMMRegister nds, XMMRegister src, EvexR void Assembler::evpabsb(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11385,7 +11320,7 @@ void Assembler::evpabsb(XMMRegister dst, KRegister mask, Address src, bool merge InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11399,7 +11334,6 @@ void Assembler::evpabsb(XMMRegister dst, KRegister mask, Address src, bool merge void Assembler::evpabsw(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11414,7 +11348,7 @@ void Assembler::evpabsw(XMMRegister dst, KRegister mask, Address src, bool merge InstructionMark im(this); assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11534,7 +11468,7 @@ void Assembler::evpfma213pd(XMMRegister dst, KRegister mask, XMMRegister nds, Ad assert(VM_Version::supports_evex(), ""); assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); InstructionAttr attributes(vector_len, /* vex_w */ true,/* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_32bit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV,/* input_size_in_bits */ EVEX_NObit); attributes.set_is_evex_instruction(); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { @@ -11563,6 +11497,7 @@ void Assembler::evpermb(XMMRegister dst, KRegister mask, XMMRegister nds, Addres 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_FVM, /* input_size_in_bits */ EVEX_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -11589,6 +11524,7 @@ void Assembler::evpermw(XMMRegister dst, KRegister mask, XMMRegister nds, Addres 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_FVM, /* input_size_in_bits */ EVEX_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -11615,6 +11551,7 @@ void Assembler::evpermd(XMMRegister dst, KRegister mask, XMMRegister nds, Addres 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_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -11641,6 +11578,7 @@ void Assembler::evpermq(XMMRegister dst, KRegister mask, XMMRegister nds, Addres 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_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -12009,6 +11947,7 @@ void Assembler::evpminsb(XMMRegister dst, KRegister mask, XMMRegister nds, Addre 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_FVM, /* input_size_in_bits */ EVEX_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -12034,6 +11973,7 @@ void Assembler::evpminsw(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { attributes.reset_is_clear_context(); @@ -12063,6 +12003,7 @@ void Assembler::evpminsd(XMMRegister dst, KRegister mask, XMMRegister nds, Addre 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_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -12091,6 +12032,7 @@ void Assembler::evpminsq(XMMRegister dst, KRegister mask, XMMRegister nds, Addre 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_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -12118,6 +12060,7 @@ void Assembler::evpmaxsb(XMMRegister dst, KRegister mask, XMMRegister nds, Addre 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_FVM, /* input_size_in_bits */ EVEX_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -12144,6 +12087,7 @@ void Assembler::evpmaxsw(XMMRegister dst, KRegister mask, XMMRegister nds, Addre 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_FVM, /* input_size_in_bits */ EVEX_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -12172,6 +12116,7 @@ void Assembler::evpmaxsd(XMMRegister dst, KRegister mask, XMMRegister nds, Addre 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_NObit); if (merge) { attributes.reset_is_clear_context(); } @@ -12199,6 +12144,7 @@ void Assembler::evpmaxsq(XMMRegister dst, KRegister mask, XMMRegister nds, Addre InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); attributes.set_is_evex_instruction(); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); attributes.set_embedded_opmask_register_specifier(mask); if (merge) { attributes.reset_is_clear_context(); @@ -12569,7 +12515,7 @@ void Assembler::evpgatherdq(XMMRegister dst, KRegister mask, Address src, int ve assert(mask != k0, "instruction will #UD if mask is in k0"); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); attributes.reset_is_clear_context(); attributes.set_embedded_opmask_register_specifier(mask); attributes.set_is_evex_instruction(); @@ -12587,7 +12533,7 @@ void Assembler::evgatherdpd(XMMRegister dst, KRegister mask, Address src, int ve assert(mask != k0, "instruction will #UD if mask is in k0"); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); attributes.reset_is_clear_context(); attributes.set_embedded_opmask_register_specifier(mask); attributes.set_is_evex_instruction(); @@ -12634,7 +12580,7 @@ void Assembler::evpscatterdq(Address dst, KRegister mask, XMMRegister src, int v assert(mask != k0, "instruction will #UD if mask is in k0"); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); attributes.reset_is_clear_context(); attributes.set_embedded_opmask_register_specifier(mask); attributes.set_is_evex_instruction(); @@ -12662,7 +12608,7 @@ void Assembler::evscatterdpd(Address dst, KRegister mask, XMMRegister src, int v assert(mask != k0, "instruction will #UD if mask is in k0"); InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true); - attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); attributes.reset_is_clear_context(); attributes.set_embedded_opmask_register_specifier(mask); attributes.set_is_evex_instruction(); @@ -12940,12 +12886,35 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix } } -void Assembler::evex_prefix_ndd(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool no_flags) { +void Assembler::eevex_prefix_ndd(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool no_flags) { attributes->set_is_evex_instruction(); vex_prefix(adr, ndd_enc, xreg_enc, pre, opc, attributes, /* nds_is_ndd */ true, no_flags); } -void Assembler::evex_prefix_nf(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool no_flags) { +void Assembler::emit_eevex_or_demote(Register dst, Register src1, Address src2, VexSimdPrefix pre, VexOpcode opc, + int size, int opcode_byte, bool no_flags, bool is_map1) { + if (is_demotable(no_flags, dst->encoding(), src1->encoding())) { + if (size == EVEX_64bit) { + emit_prefix_and_int8(get_prefixq(src2, dst, is_map1), opcode_byte); + } else { + // For 32-bit, 16-bit and 8-bit + if (size == EVEX_16bit) { + emit_int8(0x66); + } + prefix(src2, dst, false, is_map1); + emit_int8(opcode_byte); + } + } else { + bool vex_w = (size == EVEX_64bit) ? true : false; + InstructionAttr attributes(AVX_128bit, vex_w, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, size); + eevex_prefix_ndd(src2, dst->encoding(), src1->encoding(), pre, opc, &attributes, no_flags); + emit_int8(opcode_byte); + } + emit_operand(src1, src2, 0); +} + +void Assembler::eevex_prefix_nf(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool no_flags) { attributes->set_is_evex_instruction(); vex_prefix(adr, ndd_enc, xreg_enc, pre, opc, attributes, /* nds_is_ndd */ false, no_flags); } @@ -13007,18 +12976,98 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS return (((dst_enc & 7) << 3) | (src_enc & 7)); } -int Assembler::evex_prefix_and_encode_ndd(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, - InstructionAttr *attributes, bool no_flags) { +void Assembler::emit_eevex_or_demote(int dst_enc, int nds_enc, int src_enc, int8_t imm8, VexSimdPrefix pre, VexOpcode opc, + int size, int opcode_byte, bool no_flags, bool is_map1) { + bool is_prefixq = (size == EVEX_64bit) ? true : false; + if (is_demotable(no_flags, dst_enc, nds_enc)) { + int encode = is_prefixq ? prefixq_and_encode(src_enc, dst_enc, is_map1) : prefix_and_encode(src_enc, dst_enc, is_map1); + emit_opcode_prefix_and_encoding((unsigned char)(opcode_byte | 0x80), 0xC0, encode, imm8); + } else { + InstructionAttr attributes(AVX_128bit, is_prefixq, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, size); + int encode = emit_eevex_prefix_or_demote_ndd(src_enc, dst_enc, nds_enc, pre, opc, &attributes, no_flags); + emit_int24(opcode_byte, (0xC0 | encode), imm8); + } +} + +void Assembler::emit_eevex_or_demote(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, + int size, int opcode_byte, bool no_flags, bool is_map1, bool swap) { + int encode; + bool is_prefixq = (size == EVEX_64bit) ? true : false; + if (is_demotable(no_flags, dst_enc, nds_enc)) { + if (size == EVEX_16bit) { + emit_int8(0x66); + } + + if (swap) { + encode = is_prefixq ? prefixq_and_encode(dst_enc, src_enc, is_map1) : prefix_and_encode(dst_enc, src_enc, is_map1); + } else { + encode = is_prefixq ? prefixq_and_encode(src_enc, dst_enc, is_map1) : prefix_and_encode(src_enc, dst_enc, is_map1); + } + emit_opcode_prefix_and_encoding((unsigned char)opcode_byte, 0xC0, encode); + } else { + InstructionAttr attributes(AVX_128bit, is_prefixq, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_is_evex_instruction(); + if (swap) { + encode = vex_prefix_and_encode(nds_enc, dst_enc, src_enc, pre, opc, &attributes, /* src_is_gpr */ true, /* nds_is_ndd */ true, no_flags); + } else { + encode = vex_prefix_and_encode(src_enc, dst_enc, nds_enc, pre, opc, &attributes, /* src_is_gpr */ true, /* nds_is_ndd */ true, no_flags); + } + emit_int16(opcode_byte, (0xC0 | encode)); + } +} + +int Assembler::emit_eevex_prefix_or_demote_ndd(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, + InstructionAttr *attributes, bool no_flags, bool use_prefixq) { + if (is_demotable(no_flags, dst_enc, nds_enc)) { + if (pre == VEX_SIMD_66) { + emit_int8(0x66); + } + return use_prefixq ? prefixq_and_encode(dst_enc, src_enc) : prefix_and_encode(dst_enc, src_enc); + } attributes->set_is_evex_instruction(); return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes, /* src_is_gpr */ true, /* nds_is_ndd */ true, no_flags); } -int Assembler::evex_prefix_and_encode_nf(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, - InstructionAttr *attributes, bool no_flags) { +int Assembler::emit_eevex_prefix_or_demote_ndd(int dst_enc, int nds_enc, VexSimdPrefix pre, VexOpcode opc, + InstructionAttr *attributes, bool no_flags, bool use_prefixq) { + //Demote RegReg and RegRegImm instructions + if (is_demotable(no_flags, dst_enc, nds_enc)) { + return use_prefixq ? prefixq_and_encode(dst_enc) : prefix_and_encode(dst_enc); + } + attributes->set_is_evex_instruction(); + return vex_prefix_and_encode(0, dst_enc, nds_enc, pre, opc, attributes, /* src_is_gpr */ true, /* nds_is_ndd */ true, no_flags); +} + +int Assembler::emit_eevex_prefix_ndd(int dst_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool no_flags) { + attributes->set_is_evex_instruction(); + return vex_prefix_and_encode(0, 0, dst_enc, pre, opc, attributes, /* src_is_gpr */ true, /* nds_is_ndd */ true, no_flags); +} + +int Assembler::eevex_prefix_and_encode_nf(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, + InstructionAttr *attributes, bool no_flags) { attributes->set_is_evex_instruction(); return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes, /* src_is_gpr */ true, /* nds_is_ndd */ false, no_flags); } +void Assembler::emit_eevex_prefix_or_demote_arith_ndd(Register dst, Register nds, int32_t imm32, VexSimdPrefix pre, VexOpcode opc, + int size, int op1, int op2, bool no_flags) { + int dst_enc = dst->encoding(); + int nds_enc = nds->encoding(); + bool demote = is_demotable(no_flags, dst_enc, nds_enc); + if (demote) { + (size == EVEX_64bit) ? (void) prefixq_and_encode(dst_enc) : (void) prefix_and_encode(dst_enc); + } else { + bool vex_w = (size == EVEX_64bit) ? true : false; + InstructionAttr attributes(AVX_128bit, vex_w, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + //attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, size); + attributes.set_is_evex_instruction(); + vex_prefix_and_encode(0, dst_enc, nds_enc, pre, opc, &attributes, /* src_is_gpr */ true, /* nds_is_ndd */ true, no_flags); + + } + emit_arith(op1, op2, nds, imm32, demote); +} + void Assembler::simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) { if (UseAVX > 0) { @@ -13044,6 +13093,10 @@ int Assembler::simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegis } } +bool Assembler::is_demotable(bool no_flags, int dst_enc, int nds_enc) { + return (!no_flags && dst_enc == nds_enc); +} + void Assembler::vmaxss(XMMRegister dst, XMMRegister nds, XMMRegister src) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); @@ -14478,7 +14531,7 @@ void Assembler::eaddq(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, rax, src, imm32); } @@ -14492,7 +14545,7 @@ void Assembler::eaddq(Register dst, Address src1, Register src2, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x01); emit_operand(src2, src1, 0); } @@ -14503,9 +14556,7 @@ void Assembler::addq(Register dst, int32_t imm32) { } void Assembler::eaddq(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xC0, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x81, 0xC0, no_flags); } void Assembler::addq(Register dst, Address src) { @@ -14516,11 +14567,7 @@ void Assembler::addq(Register dst, Address src) { void Assembler::eaddq(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x03); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x03, no_flags); } void Assembler::addq(Register dst, Register src) { @@ -14532,7 +14579,7 @@ void Assembler::eaddq(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_arith(0x03, 0xC0, src1, src2); } @@ -14540,7 +14587,7 @@ void Assembler::adcxq(Register dst, Register src) { //assert(VM_Version::supports_adx(), "adx instructions not supported"); if (needs_rex2(dst, src)) { InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C, &attributes, true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, true); emit_int16((unsigned char)0x66, (0xC0 | encode)); } else { emit_int8(0x66); @@ -14553,16 +14600,19 @@ void Assembler::adcxq(Register dst, Register src) { } void Assembler::eadcxq(Register dst, Register src1, Register src2) { - InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C, &attributes); - emit_int16((unsigned char)0x66, (0xC0 | encode)); + if (is_demotable(false, dst->encoding(), src1->encoding())) { + return adcxq(dst, src2); + } + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, false /* no_flags */, true /* use_prefixq */); + emit_int16((unsigned char)0x66, (0xC0 | encode)); } void Assembler::adoxq(Register dst, Register src) { //assert(VM_Version::supports_adx(), "adx instructions not supported"); if (needs_rex2(dst, src)) { InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_3C, &attributes, true); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, true); emit_int16((unsigned char)0x66, (0xC0 | encode)); } else { emit_int8((unsigned char)0xF3); @@ -14575,9 +14625,12 @@ void Assembler::adoxq(Register dst, Register src) { } void Assembler::eadoxq(Register dst, Register src1, Register src2) { - InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_3C, &attributes); - emit_int16((unsigned char)0x66, (0xC0 | encode)); + if (is_demotable(false, dst->encoding(), src1->encoding())) { + return adoxq(dst, src2); + } + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, false /* no_flags */, true /* use_prefixq */); + emit_int16((unsigned char)0x66, (0xC0 | encode)); } void Assembler::andq(Address dst, int32_t imm32) { @@ -14590,7 +14643,7 @@ void Assembler::eandq(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, as_Register(4), src, imm32); } @@ -14600,9 +14653,7 @@ void Assembler::andq(Register dst, int32_t imm32) { } void Assembler::eandq(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xE0, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x81, 0xE0, no_flags); } void Assembler::andq(Register dst, Address src) { @@ -14613,11 +14664,7 @@ void Assembler::andq(Register dst, Address src) { void Assembler::eandq(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x23); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x23, no_flags); } void Assembler::andq(Register dst, Register src) { @@ -14629,7 +14676,7 @@ void Assembler::eandq(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_arith(0x23, 0xC0, src1, src2); } @@ -14643,7 +14690,7 @@ void Assembler::eandq(Register dst, Address src1, Register src2, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x21); emit_operand(src2, src1, 0); } @@ -14782,9 +14829,7 @@ void Assembler::cmovq(Condition cc, Register dst, Register src) { } void Assembler::ecmovq(Condition cc, Register dst, Register src1, Register src2) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); - emit_int16((0x40 | cc), (0xC0 | encode)); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x40 | cc, false /* no_flags */, true /* is_map1 */, true /* swap */); } void Assembler::cmovq(Condition cc, Register dst, Address src) { @@ -14796,11 +14841,7 @@ void Assembler::cmovq(Condition cc, Register dst, Address src) { void Assembler::ecmovq(Condition cc, Register dst, Register src1, Address src2) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); - emit_int8((0x40 | cc)); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, (0x40 | cc) , false /* no_flags */, true /* is_map1 */); } void Assembler::cmpq(Address dst, int32_t imm32) { @@ -14847,7 +14888,7 @@ void Assembler::cvtsi2sdq(XMMRegister dst, Register src) { void Assembler::cvtsi2sdq(XMMRegister dst, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); simd_prefix(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int8(0x2A); emit_operand(dst, src, 0); @@ -14856,7 +14897,7 @@ void Assembler::cvtsi2sdq(XMMRegister dst, Address src) { void Assembler::cvtsi2ssq(XMMRegister dst, Address src) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_64bit); + attributes.set_address_attributes(/* tuple_type */ EVEX_T1S, /* input_size_in_bits */ EVEX_32bit); simd_prefix(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int8(0x2A); emit_operand(dst, src, 0); @@ -14899,7 +14940,7 @@ void Assembler::decl(Register dst) { void Assembler::edecl(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xFF, (0xC8 | encode)); } @@ -14912,7 +14953,7 @@ void Assembler::decq(Register dst) { void Assembler::edecq(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_int16((unsigned char)0xFF, (0xC8 | encode)); } @@ -14927,7 +14968,7 @@ void Assembler::edecq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xFF); emit_operand(rcx, src, 0); } @@ -14967,7 +15008,7 @@ void Assembler::idivq(Register src) { void Assembler::eidivq(Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF7, (0xF8 | encode)); } @@ -14978,7 +15019,7 @@ void Assembler::divq(Register src) { void Assembler::edivq(Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF7, (0xF0 | encode)); } @@ -14988,15 +15029,16 @@ void Assembler::imulq(Register dst, Register src) { } void Assembler::eimulq(Register dst, Register src, bool no_flags) { + if (is_demotable(no_flags, dst->encoding(), src->encoding())) { + return imulq(dst); + } InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xAF, (0xC0 | encode)); } void Assembler::eimulq(Register dst, Register src1, Register src2, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int16((unsigned char)0xAF, (0xC0 | encode)); + emit_eevex_or_demote(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0xAF, no_flags, true /* is_map1 */, true /* swap */); } void Assembler::imulq(Register src) { @@ -15006,7 +15048,7 @@ void Assembler::imulq(Register src) { void Assembler::eimulq(Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF7, (0xE8 | encode)); } @@ -15028,7 +15070,7 @@ void Assembler::eimulq(Register dst, Address src, int32_t value, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (is8bit(value)) { emit_int8((unsigned char)0x6B); emit_operand(dst, src, 1); @@ -15052,7 +15094,7 @@ void Assembler::imulq(Register dst, Register src, int value) { void Assembler::eimulq(Register dst, Register src, int value, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (is8bit(value)) { emit_int24(0x6B, (0xC0 | encode), (value & 0xFF)); } else { @@ -15072,7 +15114,7 @@ void Assembler::eimulq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xAF); emit_operand(dst, src, 0); @@ -15080,11 +15122,7 @@ void Assembler::eimulq(Register dst, Address src, bool no_flags) { void Assembler::eimulq(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8((unsigned char)0xAF); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, (unsigned char)0xAF, no_flags, true /* is_map1 */); } void Assembler::incl(Register dst) { @@ -15098,8 +15136,7 @@ void Assembler::eincl(Register dst, Register src, bool no_flags) { // Don't use it directly. Use MacroAssembler::incrementl() instead. // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - // int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xFF, (0xC0 | encode)); } @@ -15114,7 +15151,7 @@ void Assembler::eincq(Register dst, Register src, bool no_flags) { // Don't use it directly. Use MacroAssembler::incrementq() instead. // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_int16((unsigned char)0xFF, (0xC0 | encode)); } @@ -15130,7 +15167,7 @@ void Assembler::eincq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char) 0xFF); emit_operand(rax, src, 0); } @@ -15206,7 +15243,7 @@ void Assembler::lzcntq(Register dst, Register src) { void Assembler::elzcntq(Register dst, Register src, bool no_flags) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } @@ -15224,7 +15261,7 @@ void Assembler::elzcntq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xF5); emit_operand(dst, src, 0); } @@ -15351,7 +15388,7 @@ void Assembler::emulq(Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_nf(src, 0, 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0xF7); emit_operand(rsp, src, 0); } @@ -15363,7 +15400,7 @@ void Assembler::mulq(Register src) { void Assembler::emulq(Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(0, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF7, (0xE0 | encode)); } @@ -15381,7 +15418,7 @@ void Assembler::negq(Register dst) { void Assembler::enegq(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_int16((unsigned char)0xF7, (0xD8 | encode)); } @@ -15395,7 +15432,7 @@ void Assembler::enegq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xF7); emit_operand(as_Register(3), src, 0); } @@ -15407,7 +15444,7 @@ void Assembler::notq(Register dst) { void Assembler::enotq(Register dst, Register src) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, false /* no_flags */, true /* use_prefixq */); emit_int16((unsigned char)0xF7, (0xD0 | encode)); } @@ -15451,7 +15488,7 @@ void Assembler::eorq(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, as_Register(1), src, imm32); } @@ -15465,7 +15502,7 @@ void Assembler::eorq(Register dst, Address src1, Register src2, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x09); emit_operand(src2, src1, 0); } @@ -15476,9 +15513,7 @@ void Assembler::orq(Register dst, int32_t imm32) { } void Assembler::eorq(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xC8, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x81, 0xC8, no_flags); } void Assembler::orq_imm32(Register dst, int32_t imm32) { @@ -15488,7 +15523,7 @@ void Assembler::orq_imm32(Register dst, int32_t imm32) { void Assembler::eorq_imm32(Register dst, Register src, int32_t imm32, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_arith_imm32(0x81, 0xC8, src, imm32); } @@ -15500,11 +15535,7 @@ void Assembler::orq(Register dst, Address src) { void Assembler::eorq(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x0B); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x0B, no_flags); } void Assembler::orq(Register dst, Register src) { @@ -15516,7 +15547,7 @@ void Assembler::eorq(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_arith(0x0B, 0xC0, src1, src2); } @@ -15533,7 +15564,7 @@ void Assembler::epopcntq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_nf(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char) 0x88); emit_operand(dst, src, 0); } @@ -15548,7 +15579,7 @@ void Assembler::popcntq(Register dst, Register src) { void Assembler::epopcntq(Register dst, Register src, bool no_flags) { assert(VM_Version::supports_popcnt(), "must support"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0x88, (0xC0 | encode)); } @@ -15773,7 +15804,7 @@ void Assembler::rclq(Register dst, int imm8) { void Assembler::erclq(Register dst, Register src, int imm8) { assert(isShiftCount(imm8 >> 1), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, false /* no_flags */, true /* use_prefixq */); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xD0 | encode)); } else { @@ -15794,7 +15825,7 @@ void Assembler::rcrq(Register dst, int imm8) { void Assembler::ercrq(Register dst, Register src, int imm8) { assert(isShiftCount(imm8 >> 1), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, false /* no_flags */, true /* use_prefixq */); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xD8 | encode)); } else { @@ -15857,7 +15888,7 @@ void Assembler::esalq(Register dst, Address src, int imm8, bool no_flags) { assert(isShiftCount(imm8 >> 1), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int8((unsigned char)0xD1); emit_operand(as_Register(4), src, 0); @@ -15879,7 +15910,7 @@ void Assembler::esalq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xD3); emit_operand(as_Register(4), src, 0); } @@ -15897,7 +15928,7 @@ void Assembler::salq(Register dst, int imm8) { void Assembler::esalq(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8 >> 1), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xE0 | encode)); } else { @@ -15912,7 +15943,7 @@ void Assembler::salq(Register dst) { void Assembler::esalq(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_int16((unsigned char)0xD3, (0xE0 | encode)); } @@ -15935,7 +15966,7 @@ void Assembler::esarq(Register dst, Address src, int imm8, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int8((unsigned char)0xD1); emit_operand(as_Register(7), src, 0); @@ -15957,7 +15988,7 @@ void Assembler::esarq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xD3); emit_operand(as_Register(7), src, 0); } @@ -15974,7 +16005,7 @@ void Assembler::sarq(Register dst, int imm8) { void Assembler::esarq(Register dst, Register src, int imm8, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xF8 | encode)); } else { @@ -15989,7 +16020,7 @@ void Assembler::sarq(Register dst) { void Assembler::esarq(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_int16((unsigned char)0xD3, (0xF8 | encode)); } @@ -16028,7 +16059,7 @@ void Assembler::shlq(Register dst, int imm8) { void Assembler::eshlq(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8 >> 1), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); if (imm8 == 1 ) { emit_int16((unsigned char)0xD1, (0xE0 | encode)); } else { @@ -16043,7 +16074,7 @@ void Assembler::shlq(Register dst) { void Assembler::eshlq(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_int16((unsigned char)0xD3, (0xE0 | encode)); } @@ -16061,7 +16092,7 @@ void Assembler::shrq(Register dst, int imm8) { void Assembler::eshrq(Register dst, Register src, int imm8, bool no_flags) { assert(isShiftCount(imm8 >> 1), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); if (imm8 == 1) { emit_int16((unsigned char)0xD1, (0xE8 | encode)); } @@ -16077,7 +16108,7 @@ void Assembler::shrq(Register dst) { void Assembler::eshrq(Register dst, Register src, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + int encode = emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_int16((unsigned char)0xD3, (0xE8 | encode)); } @@ -16091,7 +16122,7 @@ void Assembler::eshrq(Register dst, Address src, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8((unsigned char)0xD3); emit_operand(as_Register(5), src, 0); } @@ -16115,7 +16146,7 @@ void Assembler::eshrq(Register dst, Address src, int imm8, bool no_flags) { assert(isShiftCount(imm8 >> 1), "illegal shift count"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); if (imm8 == 1) { emit_int8((unsigned char)0xD1); emit_operand(as_Register(5), src, 0); @@ -16137,7 +16168,7 @@ void Assembler::esubq(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, rbp, src, imm32); } @@ -16151,7 +16182,7 @@ void Assembler::esubq(Register dst, Address src1, Register src2, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x29); emit_operand(src2, src1, 0); } @@ -16162,9 +16193,7 @@ void Assembler::subq(Register dst, int32_t imm32) { } void Assembler::esubq(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xE8, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x81, 0xE8, no_flags); } // Force generation of a 4 byte immediate value even if it fits into 8bit @@ -16175,7 +16204,7 @@ void Assembler::subq_imm32(Register dst, int32_t imm32) { void Assembler::esubq_imm32(Register dst, Register src, int32_t imm32, bool no_flags) { InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - (void) evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_arith_imm32(0x81, 0xE8, src, imm32); } @@ -16187,11 +16216,7 @@ void Assembler::subq(Register dst, Address src) { void Assembler::esubq(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x2B); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x2B, no_flags); } void Assembler::subq(Register dst, Register src) { @@ -16203,7 +16228,7 @@ void Assembler::esubq(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_arith(0x2B, 0xC0, src1, src2); } @@ -16268,7 +16293,7 @@ void Assembler::exorq(Register dst, Register src1, Register src2, bool no_flags) InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // NDD shares its encoding bits with NDS bits for regular EVEX instruction. // Therefore, DST is passed as the second argument to minimize changes in the leaf level routine. - (void) evex_prefix_and_encode_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, /* MAP4 */VEX_OPCODE_0F_3C, &attributes, no_flags); + (void) emit_eevex_prefix_or_demote_ndd(src1->encoding(), dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags, true /* use_prefixq */); emit_arith(0x33, 0xC0, src1, src2); } @@ -16280,11 +16305,7 @@ void Assembler::xorq(Register dst, Address src) { void Assembler::exorq(Register dst, Register src1, Address src2, bool no_flags) { InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src2, dst->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_int8(0x33); - emit_operand(src1, src2, 0); + emit_eevex_or_demote(dst, src1, src2, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x33, no_flags); } void Assembler::xorq(Register dst, int32_t imm32) { @@ -16293,9 +16314,7 @@ void Assembler::xorq(Register dst, int32_t imm32) { } void Assembler::exorq(Register dst, Register src, int32_t imm32, bool no_flags) { - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - evex_prefix_and_encode_ndd(0, dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); - emit_arith_ndd(0x81, 0xF0, src, imm32); + emit_eevex_prefix_or_demote_arith_ndd(dst, src, imm32, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, EVEX_64bit, 0x81, 0xF0, no_flags); } void Assembler::xorq(Address dst, int32_t imm32) { @@ -16308,7 +16327,7 @@ void Assembler::exorq(Register dst, Address src, int32_t imm32, bool no_flags) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src, dst->encoding(), 0, VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_arith_operand(0x81, as_Register(6), src, imm32); } @@ -16323,7 +16342,7 @@ void Assembler::esetzucc(Condition cc, Register dst) { assert(0 <= cc && cc < 16, "illegal cc"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // Encoding Format : eevex_prefix (4 bytes) | opcode_cc | modrm - int encode = evex_prefix_and_encode_ndd(0, 0, dst->encoding(), VEX_SIMD_F2, /* MAP4 */VEX_OPCODE_0F_3C, &attributes); + int encode = emit_eevex_prefix_ndd(dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3C /* MAP4 */, &attributes); // demotion disabled emit_opcode_prefix_and_encoding((0x40 | cc), 0xC0, encode); } @@ -16331,7 +16350,7 @@ void Assembler::exorq(Register dst, Address src1, Register src2, bool no_flags) InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); - evex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, no_flags); + eevex_prefix_ndd(src1, dst->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int8(0x31); emit_operand(src2, src1, 0); } @@ -16438,7 +16457,7 @@ void Assembler::evaddph(XMMRegister dst, XMMRegister nds, Address src, int vecto InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); emit_int8(0x58); emit_operand(dst, src, 0); @@ -16459,7 +16478,7 @@ void Assembler::evsubph(XMMRegister dst, XMMRegister nds, Address src, int vecto InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); emit_int8(0x5C); emit_operand(dst, src, 0); @@ -16480,7 +16499,7 @@ void Assembler::evmulph(XMMRegister dst, XMMRegister nds, Address src, int vecto InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); emit_int8(0x59); emit_operand(dst, src, 0); @@ -16501,7 +16520,7 @@ void Assembler::evminph(XMMRegister dst, XMMRegister nds, Address src, int vecto InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); emit_int8(0x5D); emit_operand(dst, src, 0); @@ -16522,7 +16541,7 @@ void Assembler::evmaxph(XMMRegister dst, XMMRegister nds, Address src, int vecto InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); emit_int8(0x5F); emit_operand(dst, src, 0); @@ -16543,7 +16562,7 @@ void Assembler::evdivph(XMMRegister dst, XMMRegister nds, Address src, int vecto InstructionMark im(this); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + attributes.set_address_attributes(/* tuple_type */ EVEX_FV, /* input_size_in_bits */ EVEX_NObit); vex_prefix(src, nds->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_MAP5, &attributes); emit_int8(0x5E); emit_operand(dst, src, 0); diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 6395be02f27..b1959e23722 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -772,25 +772,42 @@ class Assembler : public AbstractAssembler { void evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_v, bool evex_r, bool evex_b, bool eevex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc, bool no_flags = false); - void evex_prefix_ndd(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, - InstructionAttr *attributes, bool no_flags = false); + void eevex_prefix_ndd(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, + InstructionAttr *attributes, bool no_flags = false); - void evex_prefix_nf(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, - InstructionAttr *attributes, bool no_flags = false); + void eevex_prefix_nf(Address adr, int ndd_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, + InstructionAttr *attributes, bool no_flags = false); void vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool nds_is_ndd = false, bool no_flags = false); - int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, + int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr = false, bool nds_is_ndd = false, bool no_flags = false); - int evex_prefix_and_encode_ndd(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, - InstructionAttr *attributes, bool no_flags = false); - - int evex_prefix_and_encode_nf(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, + int eevex_prefix_and_encode_nf(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool no_flags = false); + int emit_eevex_prefix_ndd(int dst_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool no_flags = false); + + int emit_eevex_prefix_or_demote_ndd(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, + InstructionAttr *attributes, bool no_flags = false, bool use_prefixq = false); + + int emit_eevex_prefix_or_demote_ndd(int dst_enc, int nds_enc, VexSimdPrefix pre, VexOpcode opc, + InstructionAttr *attributes, bool no_flags = false, bool use_prefixq = false); + + void emit_eevex_prefix_or_demote_arith_ndd(Register dst, Register nds, int32_t imm32, VexSimdPrefix pre, VexOpcode opc, + int size, int op1, int op2, bool no_flags); + + void emit_eevex_or_demote(Register dst, Register src1, Address src2, VexSimdPrefix pre, VexOpcode opc, + int size, int opcode_byte, bool no_flags = false, bool is_map1 = false); + + void emit_eevex_or_demote(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, + int size, int opcode_byte, bool no_flags, bool is_map1 = false, bool swap = false); + + void emit_eevex_or_demote(int dst_enc, int nds_enc, int src_enc, int8_t imm8, VexSimdPrefix pre, VexOpcode opc, + int size, int opcode_byte, bool no_flags, bool is_map1 = false); + void simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes); @@ -798,10 +815,10 @@ class Assembler : public AbstractAssembler { VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr = false); // Helper functions for groups of instructions + bool is_demotable(bool no_flags, int dst_enc, int nds_enc); void emit_arith_b(int op1, int op2, Register dst, int imm8); - void emit_arith(int op1, int op2, Register dst, int32_t imm32); - void emit_arith_ndd(int op1, int op2, Register dst, int32_t imm32); + void emit_arith(int op1, int op2, Register dst, int32_t imm32, bool optimize_rax_dst = true); // Force generation of a 4 byte immediate value even if it fits into 8bit void emit_arith_imm32(int op1, int op2, Register dst, int32_t imm32); void emit_arith(int op1, int op2, Register dst, Register src); @@ -950,6 +967,7 @@ class Assembler : public AbstractAssembler { // New cpus require use of movaps and movapd to avoid partial register stall // when moving between registers. void movaps(XMMRegister dst, XMMRegister src); + void movapd(XMMRegister dst, Address src); void movapd(XMMRegister dst, XMMRegister src); // End avoid using directly @@ -1232,6 +1250,9 @@ class Assembler : public AbstractAssembler { // Identify processor type and features void cpuid(); + // Serialize instruction stream + void serialize(); + // CRC32C void crc32(Register crc, Register v, int8_t sizeInBytes); void crc32(Register crc, Address adr, int8_t sizeInBytes); @@ -2447,6 +2468,9 @@ class Assembler : public AbstractAssembler { void vandpd(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void vandps(XMMRegister dst, XMMRegister nds, Address src, int vector_len); + // Bitwise Logical OR of Packed Floating-Point Values + void orpd(XMMRegister dst, XMMRegister src); + void unpckhpd(XMMRegister dst, XMMRegister src); void unpcklpd(XMMRegister dst, XMMRegister src); diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp index 73262b21365..7c0d3ff624d 100644 --- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp @@ -68,7 +68,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); return; } @@ -88,7 +88,7 @@ void RangeCheckStub::emit_code(LIR_Assembler* ce) { __ call(RuntimeAddress(Runtime1::entry_for(stub_id))); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { @@ -101,7 +101,7 @@ void PredicateFailedStub::emit_code(LIR_Assembler* ce) { __ call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } void DivByZeroStub::emit_code(LIR_Assembler* ce) { @@ -111,7 +111,7 @@ void DivByZeroStub::emit_code(LIR_Assembler* ce) { __ bind(_entry); __ call(RuntimeAddress(Runtime1::entry_for(C1StubId::throw_div0_exception_id))); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } @@ -399,7 +399,7 @@ void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { __ call(RuntimeAddress(a)); ce->add_call_info_here(_info); ce->verify_oop_map(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } @@ -413,7 +413,7 @@ void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { } __ call(RuntimeAddress(Runtime1::entry_for(_stub))); ce->add_call_info_here(_info); - debug_only(__ should_not_reach_here()); + DEBUG_ONLY(__ should_not_reach_here()); } diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 60ce3419dfb..3ea2e99fe57 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -720,7 +720,8 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { if (x->id() == vmIntrinsics::_dexp || x->id() == vmIntrinsics::_dlog || x->id() == vmIntrinsics::_dpow || x->id() == vmIntrinsics::_dcos || x->id() == vmIntrinsics::_dsin || x->id() == vmIntrinsics::_dtan || - x->id() == vmIntrinsics::_dlog10 || x->id() == vmIntrinsics::_dtanh + x->id() == vmIntrinsics::_dlog10 || x->id() == vmIntrinsics::_dtanh || + x->id() == vmIntrinsics::_dcbrt ) { do_LibmIntrinsic(x); return; @@ -807,7 +808,7 @@ void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { } break; case vmIntrinsics::_dpow: - if (StubRoutines::dpow() != nullptr) { + if (StubRoutines::dpow() != nullptr) { __ call_runtime_leaf(StubRoutines::dpow(), getThreadTemp(), result_reg, cc->args()); } else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dpow), getThreadTemp(), result_reg, cc->args()); @@ -828,18 +829,24 @@ void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { } break; case vmIntrinsics::_dtan: - if (StubRoutines::dtan() != nullptr) { + if (StubRoutines::dtan() != nullptr) { __ call_runtime_leaf(StubRoutines::dtan(), getThreadTemp(), result_reg, cc->args()); } else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtan), getThreadTemp(), result_reg, cc->args()); } break; case vmIntrinsics::_dtanh: - assert(StubRoutines::dtanh() != nullptr, "tanh intrinsic not found"); - if (StubRoutines::dtanh() != nullptr) { + assert(StubRoutines::dtanh() != nullptr, "tanh intrinsic not found"); + if (StubRoutines::dtanh() != nullptr) { __ call_runtime_leaf(StubRoutines::dtanh(), getThreadTemp(), result_reg, cc->args()); } break; + case vmIntrinsics::_dcbrt: + assert(StubRoutines::dcbrt() != nullptr, "cbrt intrinsic not found"); + if (StubRoutines::dcbrt() != nullptr) { + __ call_runtime_leaf(StubRoutines::dcbrt(), getThreadTemp(), result_reg, cc->args()); + } + break; default: ShouldNotReachHere(); } diff --git a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp index b8873758b61..684347e35fa 100644 --- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp @@ -55,16 +55,17 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr null_check_offset = offset(); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(hdr, obj, rscratch1); - testb(Address(hdr, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(disp_hdr, obj, hdr, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { Label done; + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(hdr, obj, rscratch1); + testb(Address(hdr, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + jcc(Assembler::notZero, slow_case); + } + // Load object header movptr(hdr, Address(obj, hdr_offset)); // and mark it as unlocked diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index a7967d83a4e..177be6e59f7 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -476,7 +476,7 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist Label slow_path; if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. movptr(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0); } @@ -787,6 +787,119 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, // C2 uses the value of ZF to determine the continuation. } +static void abort_verify_int_in_range(uint idx, jint val, jint lo, jint hi) { + fatal("Invalid CastII, idx: %u, val: %d, lo: %d, hi: %d", idx, val, lo, hi); +} + +static void reconstruct_frame_pointer_helper(MacroAssembler* masm, Register dst) { + const int framesize = Compile::current()->output()->frame_size_in_bytes(); + masm->movptr(dst, rsp); + if (framesize > 2 * wordSize) { + masm->addptr(dst, framesize - 2 * wordSize); + } +} + +void C2_MacroAssembler::reconstruct_frame_pointer(Register rtmp) { + if (PreserveFramePointer) { + // frame pointer is valid +#ifdef ASSERT + // Verify frame pointer value in rbp. + reconstruct_frame_pointer_helper(this, rtmp); + Label L_success; + cmpq(rbp, rtmp); + jccb(Assembler::equal, L_success); + STOP("frame pointer mismatch"); + bind(L_success); +#endif // ASSERT + } else { + reconstruct_frame_pointer_helper(this, rbp); + } +} + +void C2_MacroAssembler::verify_int_in_range(uint idx, const TypeInt* t, Register val) { + jint lo = t->_lo; + jint hi = t->_hi; + assert(lo < hi, "type should not be empty or constant, idx: %u, lo: %d, hi: %d", idx, lo, hi); + if (t == TypeInt::INT) { + return; + } + + BLOCK_COMMENT("CastII {"); + Label fail; + Label succeed; + if (hi == max_jint) { + cmpl(val, lo); + jccb(Assembler::greaterEqual, succeed); + } else { + if (lo != min_jint) { + cmpl(val, lo); + jccb(Assembler::less, fail); + } + cmpl(val, hi); + jccb(Assembler::lessEqual, succeed); + } + + bind(fail); + movl(c_rarg0, idx); + movl(c_rarg1, val); + movl(c_rarg2, lo); + movl(c_rarg3, hi); + reconstruct_frame_pointer(rscratch1); + call(RuntimeAddress(CAST_FROM_FN_PTR(address, abort_verify_int_in_range))); + hlt(); + bind(succeed); + BLOCK_COMMENT("} // CastII"); +} + +static void abort_verify_long_in_range(uint idx, jlong val, jlong lo, jlong hi) { + fatal("Invalid CastLL, idx: %u, val: " JLONG_FORMAT ", lo: " JLONG_FORMAT ", hi: " JLONG_FORMAT, idx, val, lo, hi); +} + +void C2_MacroAssembler::verify_long_in_range(uint idx, const TypeLong* t, Register val, Register tmp) { + jlong lo = t->_lo; + jlong hi = t->_hi; + assert(lo < hi, "type should not be empty or constant, idx: %u, lo: " JLONG_FORMAT ", hi: " JLONG_FORMAT, idx, lo, hi); + if (t == TypeLong::LONG) { + return; + } + + BLOCK_COMMENT("CastLL {"); + Label fail; + Label succeed; + + auto cmp_val = [&](jlong bound) { + if (is_simm32(bound)) { + cmpq(val, checked_cast(bound)); + } else { + mov64(tmp, bound); + cmpq(val, tmp); + } + }; + + if (hi == max_jlong) { + cmp_val(lo); + jccb(Assembler::greaterEqual, succeed); + } else { + if (lo != min_jlong) { + cmp_val(lo); + jccb(Assembler::less, fail); + } + cmp_val(hi); + jccb(Assembler::lessEqual, succeed); + } + + bind(fail); + movl(c_rarg0, idx); + movq(c_rarg1, val); + mov64(c_rarg2, lo); + mov64(c_rarg3, hi); + reconstruct_frame_pointer(rscratch1); + call(RuntimeAddress(CAST_FROM_FN_PTR(address, abort_verify_long_in_range))); + hlt(); + bind(succeed); + BLOCK_COMMENT("} // CastLL"); +} + //------------------------------------------------------------------------------------------- // Generic instructions support for use in .ad files C2 code generation @@ -5618,7 +5731,7 @@ void C2_MacroAssembler::vector_compress_expand_avx2(int opcode, XMMRegister dst, // in a permute table row contains either a valid permute index or a -1 (default) // value, this can potentially be used as a blending mask after // compressing/expanding the source vector lanes. - vblendvps(dst, dst, xtmp, permv, vec_enc, false, permv); + vblendvps(dst, dst, xtmp, permv, vec_enc, true, permv); } void C2_MacroAssembler::vector_compress_expand(int opcode, XMMRegister dst, XMMRegister src, KRegister mask, diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index dd2880d88c3..713eb73d68f 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -44,6 +44,9 @@ Register t, Register thread); void fast_unlock_lightweight(Register obj, Register reg_rax, Register t, Register thread); + void verify_int_in_range(uint idx, const TypeInt* t, Register val); + void verify_long_in_range(uint idx, const TypeLong* t, Register val, Register tmp); + // Generic instructions support for use in .ad files C2 code generation void vabsnegd(int opcode, XMMRegister dst, XMMRegister src); void vabsnegd(int opcode, XMMRegister dst, XMMRegister src, int vector_len); @@ -574,4 +577,7 @@ void scalar_max_min_fp16(int opcode, XMMRegister dst, XMMRegister src1, XMMRegister src2, KRegister ktmp, XMMRegister xtmp1, XMMRegister xtmp2); + + void reconstruct_frame_pointer(Register rtmp); + #endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/compressedKlass_x86.cpp b/src/hotspot/cpu/x86/compressedKlass_x86.cpp index 8a06a7ba3d5..e88b7a3d4e1 100644 --- a/src/hotspot/cpu/x86/compressedKlass_x86.cpp +++ b/src/hotspot/cpu/x86/compressedKlass_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * Copyright (c) 2023, 2025, Red Hat, Inc. All rights reserved. * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,6 +25,7 @@ #ifdef _LP64 +#include "memory/metaspace.hpp" #include "oops/compressedKlass.hpp" #include "utilities/globalDefinitions.hpp" @@ -32,15 +33,25 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size char* result = nullptr; - // Optimize for unscaled encoding; failing that, for zero-based encoding: - if (optimize_for_zero_base) { - result = reserve_address_space_for_unscaled_encoding(size, aslr); - if (result == nullptr) { - result = reserve_address_space_for_zerobased_encoding(size, aslr); - } - } // end: low-address reservation + assert(CompressedKlassPointers::narrow_klass_pointer_bits() == 32 || + CompressedKlassPointers::narrow_klass_pointer_bits() == 22, "Rethink if we ever use different nKlass bit sizes"); + + // Unconditionally attempting to reserve in lower 4G first makes always sense: + // -CDS -COH: Try to get unscaled mode (zero base, zero shift) + // +CDS -COH: No zero base possible (CDS prevents it); but we still benefit from small base pointers (imm32 movabs) + // -CDS +COH: No zero base possible (22bit nKlass + zero base zero shift = 4MB encoding range, way too small); + // but we still benefit from small base pointers (imm32 movabs) + // +CDS +COH: No zero base possible for multiple reasons (CDS prevents it and encoding range too small); + // but we still benefit from small base pointers (imm32 movabs) + + result = reserve_address_space_below_4G(size, aslr); + + if (result == nullptr && optimize_for_zero_base) { + // Failing that, if we are running without CDS, attempt to allocate below 32G. + // This allows us to use zero-based encoding with a non-zero shift. + result = reserve_address_space_for_zerobased_encoding(size, aslr); + } - // Nothing more to optimize for on x64. If base != 0, we will always emit the full 64-bit immediate. return result; } diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index a5700134f60..b9a2ef35f10 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -701,7 +701,6 @@ void JavaFrameAnchor::make_walkable() { if (last_Java_sp() == nullptr) return; // already walkable? if (walkable()) return; - vmassert(last_Java_pc() == nullptr, "already walkable"); _last_Java_pc = (address)_last_Java_sp[-1]; vmassert(walkable(), "something went wrong"); } diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp index c74731d0410..afc4ab8767b 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,53 @@ // Inline functions for Intel frames: +#if INCLUDE_JFR + +// Static helper routines + +inline address frame::interpreter_bcp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (fp[frame::interpreter_frame_bcp_offset]); +} + +inline address frame::interpreter_return_address(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast
          (fp[frame::return_addr_offset]); +} + +inline intptr_t* frame::interpreter_sender_sp(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(fp[frame::interpreter_frame_sender_sp_offset]); +} + +inline bool frame::is_interpreter_frame_setup_at(const intptr_t* fp, const void* sp) { + assert(fp != nullptr, "invariant"); + assert(sp != nullptr, "invariant"); + return sp <= fp + frame::interpreter_frame_initial_sp_offset; +} + +inline intptr_t* frame::sender_sp(intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return fp + frame::sender_sp_offset; +} + +inline intptr_t* frame::link(const intptr_t* fp) { + assert(fp != nullptr, "invariant"); + return reinterpret_cast(fp[frame::link_offset]); +} + +inline address frame::return_address(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast
          (sp[-1]); +} + +inline intptr_t* frame::fp(const intptr_t* sp) { + assert(sp != nullptr, "invariant"); + return reinterpret_cast(sp[-2]); +} + +#endif // INCLUDE_JFR + // Constructors: inline frame::frame() { diff --git a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp index 298e5640b27..66fb4cbb8c7 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp @@ -26,9 +26,9 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" -#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" #define __ masm->masm()-> diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 45e4c46161f..deb8111adad 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -23,6 +23,8 @@ * */ +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" #include "gc/shenandoah/shenandoahForwarding.hpp" @@ -30,8 +32,6 @@ #include "gc/shenandoah/shenandoahHeapRegion.hpp" #include "gc/shenandoah/shenandoahRuntime.hpp" #include "gc/shenandoah/shenandoahThreadLocalData.hpp" -#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" -#include "gc/shenandoah/mode/shenandoahMode.hpp" #include "interpreter/interpreter.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" diff --git a/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp b/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp index 6b5b64d3036..db35a4efe08 100644 --- a/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zAddress_x86.cpp @@ -30,11 +30,15 @@ size_t ZPointerLoadShift; size_t ZPlatformAddressOffsetBits() { +#ifdef ADDRESS_SANITIZER + return 44; +#else const size_t min_address_offset_bits = 42; // 4TB const size_t max_address_offset_bits = 44; // 16TB const size_t address_offset = ZGlobalsPointers::min_address_offset_request(); const size_t address_offset_bits = log2i_exact(address_offset); return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); +#endif } size_t ZPlatformAddressHeapBaseShift() { diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index 9cdf0b229c0..fe7f19e1260 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -78,15 +78,48 @@ class ZRuntimeCallSpill { void save() { MacroAssembler* masm = _masm; - __ push(rax); - __ push(rcx); - __ push(rdx); - __ push(rdi); - __ push(rsi); - __ push(r8); - __ push(r9); - __ push(r10); - __ push(r11); + if (VM_Version::supports_apx_f()) { + if (_result != rax) { + __ pushp(rax); + } + __ pushp(rcx); + // Save current stack pointer into rcx + __ movptr(rcx, rsp); + // Align stack pointer to 16 byte boundary. This is hard constraint + // for push2/pop2 with PPX hints. + __ andptr(rsp, -StackAlignmentInBytes); + // Push original stack pointer. + __ push(rcx); + // Restore the original contents of RCX register. + __ movptr(rcx, Address(rcx)); + // Now push remaining caller save GPRs and EGPRs on 16B aligned stack. + // Note: For PPX to work properly, a PPX-marked PUSH2 (respectively, POP2) should always + // be matched with a PPX-marked POP2 (PUSH2), not with two PPX-marked POPs (PUSHs). + __ pushp(rdx); + __ push2p(rdi, rsi); + __ push2p(r8, r9); + __ push2p(r10, r11); + __ push2p(r16, r17); + __ push2p(r18, r19); + __ push2p(r20, r21); + __ push2p(r22, r23); + __ push2p(r24, r25); + __ push2p(r26, r27); + __ push2p(r28, r29); + __ push2p(r30, r31); + } else { + if (_result != rax) { + __ push(rax); + } + __ push(rcx); + __ push(rdx); + __ push(rdi); + __ push(rsi); + __ push(r8); + __ push(r9); + __ push(r10); + __ push(r11); + } if (_xmm_spill_size != 0) { __ subptr(rsp, _xmm_spill_size); @@ -139,21 +172,43 @@ class ZRuntimeCallSpill { __ addptr(rsp, _xmm_spill_size); } - __ pop(r11); - __ pop(r10); - __ pop(r9); - __ pop(r8); - __ pop(rsi); - __ pop(rdi); - __ pop(rdx); - __ pop(rcx); - if (_result == noreg) { - __ pop(rax); - } else if (_result == rax) { - __ addptr(rsp, wordSize); + if (VM_Version::supports_apx_f()) { + __ pop2p(r31, r30); + __ pop2p(r29, r28); + __ pop2p(r27, r26); + __ pop2p(r25, r24); + __ pop2p(r23, r22); + __ pop2p(r21, r20); + __ pop2p(r19, r18); + __ pop2p(r17, r16); + __ pop2p(r11, r10); + __ pop2p(r9, r8); + __ pop2p(rsi, rdi); + __ popp(rdx); + // Re-instantiate original stack pointer. + __ movptr(rsp, Address(rsp)); + __ popp(rcx); + if (_result != rax) { + if (_result != noreg) { + __ movptr(_result, rax); + } + __ popp(rax); + } } else { - __ movptr(_result, rax); - __ pop(rax); + __ pop(r11); + __ pop(r10); + __ pop(r9); + __ pop(r8); + __ pop(rsi); + __ pop(rdi); + __ pop(rdx); + __ pop(rcx); + if (_result != rax) { + if (_result != noreg) { + __ movptr(_result, rax); + } + __ pop(rax); + } } } @@ -1328,7 +1383,13 @@ void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) { const uint16_t value = patch_barrier_relocation_value(format); uint8_t* const patch_addr = (uint8_t*)addr + offset; if (format == ZBarrierRelocationFormatLoadGoodBeforeShl) { - *patch_addr = (uint8_t)value; + if (VM_Version::supports_apx_f()) { + NativeInstruction* instruction = nativeInstruction_at(addr); + uint8_t* const rex2_patch_addr = patch_addr + (instruction->has_rex2_prefix() ? 1 : 0); + *rex2_patch_addr = (uint8_t)value; + } else { + *patch_addr = (uint8_t)value; + } } else { *(uint16_t*)patch_addr = value; } diff --git a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp index 873cfbdcea0..3c1474ae861 100644 --- a/src/hotspot/cpu/x86/globalDefinitions_x86.hpp +++ b/src/hotspot/cpu/x86/globalDefinitions_x86.hpp @@ -34,9 +34,7 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define SUPPORTS_NATIVE_CX8 -#ifdef _LP64 #define SUPPORT_MONITOR_COUNT -#endif #define CPU_MULTI_COPY_ATOMIC @@ -44,15 +42,11 @@ const bool CCallingConventionRequiresIntsAsLongs = false; #define DEFAULT_CACHE_LINE_SIZE 64 // The default padding size for data structures to avoid false sharing. -#ifdef _LP64 // The common wisdom is that adjacent cache line prefetchers on some hardware // may pull two cache lines on access, so we have to pessimistically assume twice // the cache line size for padding. TODO: Check if this is still true for modern // hardware. If not, DEFAULT_CACHE_LINE_SIZE might as well suffice. #define DEFAULT_PADDING_SIZE (DEFAULT_CACHE_LINE_SIZE*2) -#else -#define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE -#endif #if defined(LINUX) || defined(__APPLE__) #define SUPPORT_RESERVED_STACK_AREA diff --git a/src/hotspot/cpu/x86/globals_x86.hpp b/src/hotspot/cpu/x86/globals_x86.hpp index 54888a9f849..a1d4a71874f 100644 --- a/src/hotspot/cpu/x86/globals_x86.hpp +++ b/src/hotspot/cpu/x86/globals_x86.hpp @@ -61,29 +61,19 @@ define_pd_global(intx, InlineSmallCode, 1000); #define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES #define MIN_STACK_RESERVED_PAGES (0) -#ifdef _LP64 // Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the -// stack if compiled for unix and LP64. To pass stack overflow tests we need -// 20 shadow pages. +// stack if compiled for unix. To pass stack overflow tests we need 20 shadow pages. #define DEFAULT_STACK_SHADOW_PAGES (NOT_WIN64(20) WIN64_ONLY(8) DEBUG_ONLY(+4)) // For those clients that do not use write socket, we allow // the min range value to be below that of the default #define MIN_STACK_SHADOW_PAGES (NOT_WIN64(10) WIN64_ONLY(8) DEBUG_ONLY(+4)) -#else -#define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5)) -#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES -#endif // _LP64 define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); -#ifdef _LP64 define_pd_global(bool, VMContinuations, true); -#else -define_pd_global(bool, VMContinuations, false); -#endif define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); @@ -191,6 +181,15 @@ define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong); product(bool, IntelJccErratumMitigation, true, DIAGNOSTIC, \ "Turn off JVM mitigations related to Intel micro code " \ "mitigations for the Intel JCC erratum") \ + \ + product(int, X86ICacheSync, -1, DIAGNOSTIC, \ + "Select the X86 ICache sync mechanism: -1 = auto-select; " \ + "0 = none (dangerous); 1 = CLFLUSH loop; 2 = CLFLUSHOPT loop; "\ + "3 = CLWB loop; 4 = single CPUID; 5 = single SERIALIZE. " \ + "Explicitly selected mechanism will fail at startup if " \ + "hardware does not support it.") \ + range(-1, 5) \ + \ // end of ARCH_FLAGS #endif // CPU_X86_GLOBALS_X86_HPP diff --git a/src/hotspot/cpu/x86/icache_x86.cpp b/src/hotspot/cpu/x86/icache_x86.cpp index 45679332eca..889cfb32931 100644 --- a/src/hotspot/cpu/x86/icache_x86.cpp +++ b/src/hotspot/cpu/x86/icache_x86.cpp @@ -23,15 +23,63 @@ */ #include "asm/macroAssembler.hpp" +#include "runtime/flags/flagSetting.hpp" +#include "runtime/globals_extension.hpp" #include "runtime/icache.hpp" #define __ _masm-> +void x86_generate_icache_fence(MacroAssembler* _masm) { + switch (X86ICacheSync) { + case 0: + break; + case 1: + __ mfence(); + break; + case 2: + case 3: + __ sfence(); + break; + case 4: + __ push(rax); + __ push(rbx); + __ push(rcx); + __ push(rdx); + __ xorptr(rax, rax); + __ cpuid(); + __ pop(rdx); + __ pop(rcx); + __ pop(rbx); + __ pop(rax); + break; + case 5: + __ serialize(); + break; + default: + ShouldNotReachHere(); + } +} + +void x86_generate_icache_flush_insn(MacroAssembler* _masm, Register addr) { + switch (X86ICacheSync) { + case 1: + __ clflush(Address(addr, 0)); + break; + case 2: + __ clflushopt(Address(addr, 0)); + break; + case 3: + __ clwb(Address(addr, 0)); + break; + default: + ShouldNotReachHere(); + } +} + void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub) { - StubCodeMark mark(this, "ICache", "flush_icache_stub"); + StubCodeMark mark(this, "ICache", _stub_name); address start = __ pc(); -#ifdef AMD64 const Register addr = c_rarg0; const Register lines = c_rarg1; @@ -40,26 +88,22 @@ void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flu Label flush_line, done; __ testl(lines, lines); - __ jcc(Assembler::zero, done); + __ jccb(Assembler::zero, done); - // Force ordering wrt cflush. - // Other fence and sync instructions won't do the job. - __ mfence(); + x86_generate_icache_fence(_masm); - __ bind(flush_line); - __ clflush(Address(addr, 0)); - __ addptr(addr, ICache::line_size); - __ decrementl(lines); - __ jcc(Assembler::notZero, flush_line); + if (1 <= X86ICacheSync && X86ICacheSync <= 3) { + __ bind(flush_line); + x86_generate_icache_flush_insn(_masm, addr); + __ addptr(addr, ICache::line_size); + __ decrementl(lines); + __ jccb(Assembler::notZero, flush_line); - __ mfence(); + x86_generate_icache_fence(_masm); + } __ bind(done); -#else - const Address magic(rsp, 3*wordSize); - __ lock(); __ addl(Address(rsp, 0), 0); -#endif // AMD64 __ movptr(rax, magic); // Handshake with caller to make sure it happened! __ ret(0); @@ -67,4 +111,22 @@ void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flu *flush_icache_stub = (ICache::flush_icache_stub_t)start; } +void ICache::initialize(int phase) { + switch (phase) { + case 1: { + // Initial phase, we assume only CLFLUSH is available. + IntFlagSetting fs(X86ICacheSync, 1); + AbstractICache::initialize(phase); + break; + } + case 2: { + // Final phase, generate the stub again. + AbstractICache::initialize(phase); + break; + } + default: + ShouldNotReachHere(); + } +} + #undef __ diff --git a/src/hotspot/cpu/x86/icache_x86.hpp b/src/hotspot/cpu/x86/icache_x86.hpp index 48286a7e3b3..805022fbb32 100644 --- a/src/hotspot/cpu/x86/icache_x86.hpp +++ b/src/hotspot/cpu/x86/icache_x86.hpp @@ -40,21 +40,13 @@ class ICache : public AbstractICache { public: -#ifdef AMD64 enum { stub_size = 64, // Size of the icache flush stub in bytes line_size = 64, // Icache line size in bytes log2_line_size = 6 // log2(line_size) }; - // Use default implementation -#else - enum { - stub_size = 16, // Size of the icache flush stub in bytes - line_size = BytesPerWord, // conservative - log2_line_size = LogBytesPerWord // log2(line_size) - }; -#endif // AMD64 + static void initialize(int phase); }; #endif // CPU_X86_ICACHE_X86_HPP diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index bd029f2e4ac..92233ee0d07 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -778,9 +778,10 @@ void InterpreterMacroAssembler::narrow(Register result) { // remove activation // -// Apply stack watermark barrier. // Unlock the receiver if this is a synchronized method. // Unlock any Java monitors from synchronized blocks. +// Apply stack watermark barrier. +// Notify JVMTI. // Remove the activation from the stack. // // If there are locked Java monitors @@ -790,12 +791,11 @@ void InterpreterMacroAssembler::narrow(Register result) { // installs IllegalMonitorStateException // Else // no error processing -void InterpreterMacroAssembler::remove_activation( - TosState state, - Register ret_addr, - bool throw_monitor_exception, - bool install_monitor_exception, - bool notify_jvmdi) { +void InterpreterMacroAssembler::remove_activation(TosState state, + Register ret_addr, + bool throw_monitor_exception, + bool install_monitor_exception, + bool notify_jvmdi) { // Note: Registers rdx xmm0 may be in use for the // result check if synchronized method Label unlocked, unlock, no_unlock; @@ -804,21 +804,6 @@ void InterpreterMacroAssembler::remove_activation( const Register robj = c_rarg1; const Register rmon = c_rarg1; - // The below poll is for the stack watermark barrier. It allows fixing up frames lazily, - // that would normally not be safe to use. Such bad returns into unsafe territory of - // the stack, will call InterpreterRuntime::at_unwind. - Label slow_path; - Label fast_path; - safepoint_poll(slow_path, true /* at_return */, false /* in_nmethod */); - jmp(fast_path); - bind(slow_path); - push(state); - set_last_Java_frame(noreg, rbp, (address)pc(), rscratch1); - super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), rthread); - reset_last_Java_frame(true); - pop(state); - bind(fast_path); - // get the value of _do_not_unlock_if_synchronized into rdx const Address do_not_unlock_if_synchronized(rthread, in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); @@ -940,7 +925,24 @@ void InterpreterMacroAssembler::remove_activation( bind(no_unlock); - // jvmti support + JFR_ONLY(enter_jfr_critical_section();) + + // The below poll is for the stack watermark barrier. It allows fixing up frames lazily, + // that would normally not be safe to use. Such bad returns into unsafe territory of + // the stack, will call InterpreterRuntime::at_unwind. + Label slow_path; + Label fast_path; + safepoint_poll(slow_path, true /* at_return */, false /* in_nmethod */); + jmp(fast_path); + bind(slow_path); + push(state); + set_last_Java_frame(noreg, rbp, (address)pc(), rscratch1); + super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), r15_thread); + reset_last_Java_frame(true); + pop(state); + bind(fast_path); + + // JVMTI support. Make sure the safepoint poll test is issued prior. if (notify_jvmdi) { notify_method_exit(state, NotifyJVMTI); // preserve TOSCA } else { @@ -964,6 +966,8 @@ void InterpreterMacroAssembler::remove_activation( cmpptr(rbx, Address(rthread, JavaThread::reserved_stack_activation_offset())); jcc(Assembler::lessEqual, no_reserved_zone_enabling); + JFR_ONLY(leave_jfr_critical_section();) + call_VM_leaf( CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), rthread); call_VM(noreg, CAST_FROM_FN_PTR(address, @@ -972,12 +976,29 @@ void InterpreterMacroAssembler::remove_activation( bind(no_reserved_zone_enabling); } + leave(); // remove frame anchor + + JFR_ONLY(leave_jfr_critical_section();) + pop(ret_addr); // get return address mov(rsp, rbx); // set sp to sender sp pop_cont_fastpath(); + } +#if INCLUDE_JFR +void InterpreterMacroAssembler::enter_jfr_critical_section() { + const Address sampling_critical_section(r15_thread, in_bytes(SAMPLING_CRITICAL_SECTION_OFFSET_JFR)); + movbool(sampling_critical_section, true); +} + +void InterpreterMacroAssembler::leave_jfr_critical_section() { + const Address sampling_critical_section(r15_thread, in_bytes(SAMPLING_CRITICAL_SECTION_OFFSET_JFR)); + movbool(sampling_critical_section, false); +} +#endif // INCLUDE_JFR + void InterpreterMacroAssembler::get_method_counters(Register method, Register mcs, Label& skip) { Label has_counters; @@ -1023,15 +1044,15 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) { // Load object pointer into obj_reg movptr(obj_reg, Address(lock_reg, obj_offset)); - if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(tmp_reg, obj_reg, rklass_decode_tmp); - testb(Address(tmp_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); - jcc(Assembler::notZero, slow_case); - } - if (LockingMode == LM_LIGHTWEIGHT) { lightweight_lock(lock_reg, obj_reg, swap_reg, tmp_reg, slow_case); } else if (LockingMode == LM_LEGACY) { + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp_reg, obj_reg, rklass_decode_tmp); + testb(Address(tmp_reg, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + jcc(Assembler::notZero, slow_case); + } + // Load immediate 1 into swap_reg %rax movl(swap_reg, 1); @@ -1254,46 +1275,19 @@ void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - int constant, - bool decrement) { - // Counter address - Address data(mdp_in, constant); - - increment_mdp_data_at(data, decrement); -} - -void InterpreterMacroAssembler::increment_mdp_data_at(Address data, - bool decrement) { + int constant) { assert(ProfileInterpreter, "must be profiling interpreter"); - // %%% this does 64bit counters at best it is wasting space - // at worst it is a rare bug when counters overflow - - if (decrement) { - // Decrement the register. Set condition codes. - addptr(data, -DataLayout::counter_increment); - // If the decrement causes the counter to overflow, stay negative - Label L; - jcc(Assembler::negative, L); - addptr(data, DataLayout::counter_increment); - bind(L); - } else { - assert(DataLayout::counter_increment == 1, - "flow-free idiom only works with 1"); - // Increment the register. Set carry flag. - addptr(data, DataLayout::counter_increment); - // If the increment causes the counter to overflow, pull back by 1. - sbbptr(data, 0); - } + Address data(mdp_in, constant); + addptr(data, DataLayout::counter_increment); } void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, - Register reg, - int constant, - bool decrement) { - Address data(mdp_in, reg, Address::times_1, constant); - - increment_mdp_data_at(data, decrement); + Register index, + int constant) { + assert(ProfileInterpreter, "must be profiling interpreter"); + Address data(mdp_in, index, Address::times_1, constant); + addptr(data, DataLayout::counter_increment); } void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, @@ -1361,25 +1355,15 @@ void InterpreterMacroAssembler::update_mdp_for_ret(Register return_bci) { } -void InterpreterMacroAssembler::profile_taken_branch(Register mdp, - Register bumped_count) { +void InterpreterMacroAssembler::profile_taken_branch(Register mdp) { if (ProfileInterpreter) { Label profile_continue; // If no method data exists, go to profile_continue. - // Otherwise, assign to mdp test_method_data_pointer(mdp, profile_continue); // We are taking a branch. Increment the taken count. - // We inline increment_mdp_data_at to return bumped_count in a register - //increment_mdp_data_at(mdp, in_bytes(JumpData::taken_offset())); - Address data(mdp, in_bytes(JumpData::taken_offset())); - movptr(bumped_count, data); - assert(DataLayout::counter_increment == 1, - "flow-free idiom only works with 1"); - addptr(bumped_count, DataLayout::counter_increment); - sbbptr(bumped_count, 0); - movptr(data, bumped_count); // Store back out + increment_mdp_data_at(mdp, in_bytes(JumpData::taken_offset())); // The method data pointer needs to be updated to reflect the new target. update_mdp_by_offset(mdp, in_bytes(JumpData::displacement_offset())); @@ -1395,7 +1379,7 @@ void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { // If no method data exists, go to profile_continue. test_method_data_pointer(mdp, profile_continue); - // We are taking a branch. Increment the not taken count. + // We are not taking a branch. Increment the not taken count. increment_mdp_data_at(mdp, in_bytes(BranchData::not_taken_offset())); // The method data pointer needs to be updated to correspond to diff --git a/src/hotspot/cpu/x86/interp_masm_x86.hpp b/src/hotspot/cpu/x86/interp_masm_x86.hpp index 308d700ff4f..a36a697eebf 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.hpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -212,11 +212,8 @@ class InterpreterMacroAssembler: public MacroAssembler { void verify_method_data_pointer(); void set_mdp_data_at(Register mdp_in, int constant, Register value); - void increment_mdp_data_at(Address data, bool decrement = false); - void increment_mdp_data_at(Register mdp_in, int constant, - bool decrement = false); - void increment_mdp_data_at(Register mdp_in, Register reg, int constant, - bool decrement = false); + void increment_mdp_data_at(Register mdp_in, int constant); + void increment_mdp_data_at(Register mdp_in, Register index, int constant); 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); @@ -239,7 +236,7 @@ class InterpreterMacroAssembler: public MacroAssembler { void update_mdp_by_constant(Register mdp_in, int constant); void update_mdp_for_ret(Register return_bci); - void profile_taken_branch(Register mdp, Register bumped_count); + void profile_taken_branch(Register mdp); void profile_not_taken_branch(Register mdp); void profile_call(Register mdp); void profile_final_call(Register mdp); @@ -265,6 +262,9 @@ class InterpreterMacroAssembler: public MacroAssembler { void notify_method_entry(); void notify_method_exit(TosState state, NotifyMethodExitMode mode); + JFR_ONLY(void enter_jfr_critical_section();) + JFR_ONLY(void leave_jfr_critical_section();) + private: Register _locals_register; // register that contains the pointer to the locals diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 25de76a7e40..803bce48945 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -24,6 +24,7 @@ #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" +#include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "compiler/compiler_globals.hpp" #include "compiler/disassembler.hpp" @@ -366,7 +367,9 @@ void MacroAssembler::stop(const char* msg) { lea(c_rarg1, InternalAddress(rip)); movq(c_rarg2, rsp); // pass pointer to regs array } - lea(c_rarg0, ExternalAddress((address) msg)); + // Skip AOT caching C strings in scratch buffer. + const char* str = (code_section()->scratch_emit()) ? msg : AOTCodeCache::add_C_string(msg); + lea(c_rarg0, ExternalAddress((address) str)); andq(rsp, -16); // align stack as required by ABI call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64))); hlt(); @@ -2247,6 +2250,16 @@ void MacroAssembler::evmovdqaq(XMMRegister dst, AddressLiteral src, int vector_l } } +void MacroAssembler::movapd(XMMRegister dst, AddressLiteral src, Register rscratch) { + assert(rscratch != noreg || always_reachable(src), "missing"); + + if (reachable(src)) { + Assembler::movapd(dst, as_Address(src)); + } else { + lea(rscratch, src); + Assembler::movapd(dst, Address(rscratch, 0)); + } +} void MacroAssembler::movdqa(XMMRegister dst, AddressLiteral src, Register rscratch) { assert(rscratch != noreg || always_reachable(src), "missing"); @@ -5399,20 +5412,27 @@ void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) { } void MacroAssembler::encode_klass_not_null(Register r, Register tmp) { + BLOCK_COMMENT("encode_klass_not_null {"); assert_different_registers(r, tmp); if (CompressedKlassPointers::base() != nullptr) { - mov64(tmp, (int64_t)CompressedKlassPointers::base()); + if (AOTCodeCache::is_on_for_dump()) { + movptr(tmp, ExternalAddress(CompressedKlassPointers::base_addr())); + } else { + movptr(tmp, (intptr_t)CompressedKlassPointers::base()); + } subq(r, tmp); } if (CompressedKlassPointers::shift() != 0) { shrq(r, CompressedKlassPointers::shift()); } + BLOCK_COMMENT("} encode_klass_not_null"); } void MacroAssembler::encode_and_move_klass_not_null(Register dst, Register src) { + BLOCK_COMMENT("encode_and_move_klass_not_null {"); assert_different_registers(src, dst); if (CompressedKlassPointers::base() != nullptr) { - mov64(dst, -(int64_t)CompressedKlassPointers::base()); + movptr(dst, -(intptr_t)CompressedKlassPointers::base()); addq(dst, src); } else { movptr(dst, src); @@ -5420,9 +5440,11 @@ void MacroAssembler::encode_and_move_klass_not_null(Register dst, Register src) if (CompressedKlassPointers::shift() != 0) { shrq(dst, CompressedKlassPointers::shift()); } + BLOCK_COMMENT("} encode_and_move_klass_not_null"); } void MacroAssembler::decode_klass_not_null(Register r, Register tmp) { + BLOCK_COMMENT("decode_klass_not_null {"); assert_different_registers(r, tmp); // Note: it will change flags assert(UseCompressedClassPointers, "should only be used for compressed headers"); @@ -5433,12 +5455,18 @@ void MacroAssembler::decode_klass_not_null(Register r, Register tmp) { shlq(r, CompressedKlassPointers::shift()); } if (CompressedKlassPointers::base() != nullptr) { - mov64(tmp, (int64_t)CompressedKlassPointers::base()); + if (AOTCodeCache::is_on_for_dump()) { + movptr(tmp, ExternalAddress(CompressedKlassPointers::base_addr())); + } else { + movptr(tmp, (intptr_t)CompressedKlassPointers::base()); + } addq(r, tmp); } + BLOCK_COMMENT("} decode_klass_not_null"); } void MacroAssembler::decode_and_move_klass_not_null(Register dst, Register src) { + BLOCK_COMMENT("decode_and_move_klass_not_null {"); assert_different_registers(src, dst); // Note: it will change flags assert (UseCompressedClassPointers, "should only be used for compressed headers"); @@ -5454,7 +5482,7 @@ void MacroAssembler::decode_and_move_klass_not_null(Register dst, Register src) } else { if (CompressedKlassPointers::shift() <= Address::times_8) { if (CompressedKlassPointers::base() != nullptr) { - mov64(dst, (int64_t)CompressedKlassPointers::base()); + movptr(dst, (intptr_t)CompressedKlassPointers::base()); } else { xorq(dst, dst); } @@ -5466,9 +5494,9 @@ void MacroAssembler::decode_and_move_klass_not_null(Register dst, Register src) } } else { if (CompressedKlassPointers::base() != nullptr) { - const uint64_t base_right_shifted = - (uint64_t)CompressedKlassPointers::base() >> CompressedKlassPointers::shift(); - mov64(dst, base_right_shifted); + const intptr_t base_right_shifted = + (intptr_t)CompressedKlassPointers::base() >> CompressedKlassPointers::shift(); + movptr(dst, base_right_shifted); } else { xorq(dst, dst); } @@ -5476,6 +5504,7 @@ void MacroAssembler::decode_and_move_klass_not_null(Register dst, Register src) shlq(dst, CompressedKlassPointers::shift()); } } + BLOCK_COMMENT("} decode_and_move_klass_not_null"); } void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { @@ -9584,10 +9613,16 @@ void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Registe movptr(reg_rax, Address(obj, oopDesc::mark_offset_in_bytes())); if (UseObjectMonitorTable) { - // Clear cache in case fast locking succeeds. + // Clear cache in case fast locking succeeds or we need to take the slow-path. movptr(Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))), 0); } + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, obj, rscratch1); + testb(Address(tmp, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); + jcc(Assembler::notZero, slow); + } + // Load top. movl(top, Address(thread, JavaThread::lock_stack_top_offset())); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index efd1a4c154f..f7ac6fb4297 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -995,6 +995,8 @@ class MacroAssembler: public Assembler { void andpd(XMMRegister dst, Address src) { Assembler::andpd(dst, src); } void andpd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); + void andnpd(XMMRegister dst, XMMRegister src) { Assembler::andnpd(dst, src); } + void andps(XMMRegister dst, XMMRegister src) { Assembler::andps(dst, src); } void andps(XMMRegister dst, Address src) { Assembler::andps(dst, src); } void andps(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); @@ -1007,6 +1009,8 @@ class MacroAssembler: public Assembler { void comisd(XMMRegister dst, Address src) { Assembler::comisd(dst, src); } void comisd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); + void orpd(XMMRegister dst, XMMRegister src) { Assembler::orpd(dst, src); } + void cmp32_mxcsr_std(Address mxcsr_save, Register tmp, Register rscratch = noreg); void ldmxcsr(Address src) { Assembler::ldmxcsr(src); } void ldmxcsr(AddressLiteral src, Register rscratch = noreg); @@ -1241,6 +1245,9 @@ class MacroAssembler: public Assembler { void evmovdquq(XMMRegister dst, KRegister mask, AddressLiteral src, bool merge, int vector_len, Register rscratch = noreg); void evmovdqaq(XMMRegister dst, KRegister mask, AddressLiteral src, bool merge, int vector_len, Register rscratch = noreg); + using Assembler::movapd; + void movapd(XMMRegister dst, AddressLiteral src, Register rscratch = noreg); + // Move Aligned Double Quadword void movdqa(XMMRegister dst, XMMRegister src) { Assembler::movdqa(dst, src); } void movdqa(XMMRegister dst, Address src) { Assembler::movdqa(dst, src); } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp index 432f9277549..9f0232075cd 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86_sha.cpp @@ -1511,7 +1511,7 @@ void MacroAssembler::sha512_update_ni_x1(Register arg_hash, Register arg_msg, Re //ymm13 = A B E F, ymm14 = C D G H lea(rax, ExternalAddress(K512_W)); - align(32); + align(CodeEntryAlignment); bind(block_loop); vmovdqu(xmm11, xmm13);//ABEF vmovdqu(xmm12, xmm14);//CDGH diff --git a/src/hotspot/cpu/x86/methodHandles_x86.cpp b/src/hotspot/cpu/x86/methodHandles_x86.cpp index ee4dc26ae40..f3683e7d09c 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.cpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp @@ -122,17 +122,64 @@ void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Registe __ bind(L); } -#endif //ASSERT +void MethodHandles::verify_method(MacroAssembler* _masm, Register method, Register temp, vmIntrinsics::ID iid) { + BLOCK_COMMENT("verify_method {"); + __ verify_method_ptr(method); + if (VerifyMethodHandles) { + Label L_ok; + assert_different_registers(method, temp); + + const Register method_holder = temp; + __ load_method_holder(method_holder, method); + __ push(method_holder); // keep holder around for diagnostic purposes + + switch (iid) { + case vmIntrinsicID::_invokeBasic: + // Require compiled LambdaForm class to be fully initialized. + __ cmpb(Address(method_holder, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); + __ jccb(Assembler::equal, L_ok); + break; + + case vmIntrinsicID::_linkToStatic: + __ clinit_barrier(method_holder, &L_ok); + break; + + case vmIntrinsicID::_linkToVirtual: + case vmIntrinsicID::_linkToSpecial: + case vmIntrinsicID::_linkToInterface: + // Class initialization check is too strong here. Just ensure that initialization has been initiated. + __ cmpb(Address(method_holder, InstanceKlass::init_state_offset()), InstanceKlass::being_initialized); + __ jcc(Assembler::greaterEqual, L_ok); + + // init_state check failed, but it may be an abstract interface method + __ load_unsigned_short(temp, Address(method, Method::access_flags_offset())); + __ testl(temp, JVM_ACC_ABSTRACT); + __ jccb(Assembler::notZero, L_ok); + break; + + default: + fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid)); + } + + // clinit check failed for a concrete method + __ STOP("Method holder klass is not initialized"); + + __ BIND(L_ok); + __ pop(method_holder); // restore stack layout + } + BLOCK_COMMENT("} verify_method"); +} +#endif // ASSERT void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, - bool for_compiler_entry) { + bool for_compiler_entry, vmIntrinsics::ID iid) { assert(method == rbx, "interpreter calling convention"); Label L_no_such_method; __ testptr(rbx, rbx); __ jcc(Assembler::zero, L_no_such_method); - __ verify_method_ptr(method); + verify_method(_masm, method, temp, iid); if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { Label run_compiled_code; @@ -193,7 +240,7 @@ void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, __ BIND(L); } - jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry); + jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry, vmIntrinsics::_invokeBasic); BLOCK_COMMENT("} jump_to_lambda_form"); } @@ -485,8 +532,7 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, // After figuring out which concrete method to call, jump into it. // Note that this works in the interpreter with no data motion. // But the compiled version will require that rcx_recv be shifted out. - __ verify_method_ptr(rbx_method); - jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry); + jump_from_method_handle(_masm, rbx_method, temp1, for_compiler_entry, iid); if (iid == vmIntrinsics::_linkToInterface) { __ bind(L_incompatible_class_change_error); diff --git a/src/hotspot/cpu/x86/methodHandles_x86.hpp b/src/hotspot/cpu/x86/methodHandles_x86.hpp index 9ffe5e198ac..6ba9b5f6a4f 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.hpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.hpp @@ -38,6 +38,8 @@ enum /* platform_dependent_constants */ { Register obj, vmClassID klass_id, const char* error_message = "wrong klass") NOT_DEBUG_RETURN; + static void verify_method(MacroAssembler* _masm, Register method, Register temp, vmIntrinsics::ID iid) NOT_DEBUG_RETURN; + static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) { verify_klass(_masm, mh_reg, VM_CLASS_ID(MethodHandle_klass), "reference is a MH"); @@ -48,7 +50,7 @@ enum /* platform_dependent_constants */ { // Similar to InterpreterMacroAssembler::jump_from_interpreted. // Takes care of special dispatch from single stepping too. static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, - bool for_compiler_entry); + bool for_compiler_entry, vmIntrinsics::ID iid); static void jump_to_lambda_form(MacroAssembler* _masm, Register recv, Register method_temp, diff --git a/src/hotspot/cpu/x86/nativeInst_x86.cpp b/src/hotspot/cpu/x86/nativeInst_x86.cpp index 4ee741077dc..c3345be2172 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.cpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.cpp @@ -67,9 +67,7 @@ void NativeCall::print() { // Inserts a native call instruction at a given pc void NativeCall::insert(address code_pos, address entry) { intptr_t disp = (intptr_t)entry - ((intptr_t)code_pos + 1 + 4); -#ifdef AMD64 guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset"); -#endif // AMD64 *code_pos = instruction_code; *((int32_t *)(code_pos+1)) = (int32_t) disp; ICache::invalidate_range(code_pos, instruction_size); @@ -140,7 +138,7 @@ bool NativeCall::is_displacement_aligned() { // Used in the runtime linkage of calls; see class CompiledIC. // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) void NativeCall::set_destination_mt_safe(address dest) { - debug_only(verify()); + DEBUG_ONLY(verify()); // Make sure patching code is locked. No two threads can patch at the same // time but one may be executing this code. assert(CodeCache_lock->is_locked() || SafepointSynchronize::is_at_safepoint() || @@ -157,7 +155,6 @@ void NativeCall::set_destination_mt_safe(address dest) { void NativeMovConstReg::verify() { -#ifdef AMD64 // make sure code pattern is actually a mov reg64, imm64 instruction bool valid_rex_prefix = ubyte_at(0) == Assembler::REX_W || ubyte_at(0) == Assembler::REX_WB; bool valid_rex2_prefix = ubyte_at(0) == Assembler::REX2 && @@ -169,12 +166,6 @@ void NativeMovConstReg::verify() { print(); fatal("not a REX.W[B] mov reg64, imm64"); } -#else - // make sure code pattern is actually a mov reg, imm32 instruction - u_char test_byte = *(u_char*)instruction_address(); - u_char test_byte_2 = test_byte & ( 0xff ^ register_mask); - if (test_byte_2 != instruction_code) fatal("not a mov reg, imm32"); -#endif // AMD64 } @@ -192,12 +183,10 @@ int NativeMovRegMem::instruction_start() const { // See comment in Assembler::locate_operand() about VEX prefixes. if (instr_0 == instruction_VEX_prefix_2bytes) { assert((UseAVX > 0), "shouldn't have VEX prefix"); - NOT_LP64(assert((0xC0 & ubyte_at(1)) == 0xC0, "shouldn't have LDS and LES instructions")); return 2; } if (instr_0 == instruction_VEX_prefix_3bytes) { assert((UseAVX > 0), "shouldn't have VEX prefix"); - NOT_LP64(assert((0xC0 & ubyte_at(1)) == 0xC0, "shouldn't have LDS and LES instructions")); return 3; } if (instr_0 == instruction_EVEX_prefix_4bytes) { @@ -313,8 +302,7 @@ void NativeMovRegMem::print() { void NativeLoadAddress::verify() { // make sure code pattern is actually a mov [reg+offset], reg instruction u_char test_byte = *(u_char*)instruction_address(); - if ( ! ((test_byte == lea_instruction_code) - LP64_ONLY(|| (test_byte == mov64_instruction_code) ))) { + if ((test_byte != lea_instruction_code) && (test_byte != mov64_instruction_code)) { fatal ("not a lea reg, [reg+offs] instruction"); } } @@ -340,9 +328,7 @@ void NativeJump::verify() { void NativeJump::insert(address code_pos, address entry) { intptr_t disp = (intptr_t)entry - ((intptr_t)code_pos + 1 + 4); -#ifdef AMD64 guarantee(disp == (intptr_t)(int32_t)disp, "must be 32-bit offset"); -#endif // AMD64 *code_pos = instruction_code; *((int32_t*)(code_pos + 1)) = (int32_t)disp; @@ -355,11 +341,7 @@ void NativeJump::check_verified_entry_alignment(address entry, address verified_ // in use. The patching in that instance must happen only when certain // alignment restrictions are true. These guarantees check those // conditions. -#ifdef AMD64 const int linesize = 64; -#else - const int linesize = 32; -#endif // AMD64 // Must be wordSize aligned guarantee(((uintptr_t) verified_entry & (wordSize -1)) == 0, @@ -386,7 +368,6 @@ void NativeJump::check_verified_entry_alignment(address entry, address verified_ // void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { // complete jump instruction (to be inserted) is in code_buffer; -#ifdef _LP64 union { jlong cb_long; unsigned char code_buffer[8]; @@ -402,43 +383,6 @@ void NativeJump::patch_verified_entry(address entry, address verified_entry, add Atomic::store((jlong *) verified_entry, u.cb_long); ICache::invalidate_range(verified_entry, 8); - -#else - unsigned char code_buffer[5]; - code_buffer[0] = instruction_code; - intptr_t disp = (intptr_t)dest - ((intptr_t)verified_entry + 1 + 4); - *(int32_t*)(code_buffer + 1) = (int32_t)disp; - - check_verified_entry_alignment(entry, verified_entry); - - // Can't call nativeJump_at() because it's asserts jump exists - NativeJump* n_jump = (NativeJump*) verified_entry; - - //First patch dummy jmp in place - - unsigned char patch[4]; - assert(sizeof(patch)==sizeof(int32_t), "sanity check"); - patch[0] = 0xEB; // jmp rel8 - patch[1] = 0xFE; // jmp to self - patch[2] = 0xEB; - patch[3] = 0xFE; - - // First patch dummy jmp in place - *(int32_t*)verified_entry = *(int32_t *)patch; - - n_jump->wrote(0); - - // Patch 5th byte (from jump instruction) - verified_entry[4] = code_buffer[4]; - - n_jump->wrote(4); - - // Patch bytes 0-3 (from jump instruction) - *(int32_t*)verified_entry = *(int32_t *)code_buffer; - // Invalidate. Opteron requires a flush after every write. - n_jump->wrote(0); -#endif // _LP64 - } void NativeIllegalInstruction::insert(address code_pos) { @@ -455,9 +399,7 @@ void NativeGeneralJump::verify() { void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { intptr_t disp = (intptr_t)entry - ((intptr_t)code_pos + 1 + 4); -#ifdef AMD64 guarantee(disp == (intptr_t)(int32_t)disp, "must be 32-bit offset"); -#endif // AMD64 *code_pos = unconditional_long_jump; *((int32_t *)(code_pos+1)) = (int32_t) disp; diff --git a/src/hotspot/cpu/x86/nativeInst_x86.hpp b/src/hotspot/cpu/x86/nativeInst_x86.hpp index d02387aa9ff..b2448cb99fd 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.hpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.hpp @@ -126,10 +126,8 @@ class NativeCall: public NativeInstruction { address return_address() const { return addr_at(return_address_offset); } address destination() const; void set_destination(address dest) { -#ifdef AMD64 intptr_t disp = dest - return_address(); guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset"); -#endif // AMD64 set_int_at(displacement_offset, (int)(dest - return_address())); } // Returns whether the 4-byte displacement operand is 4-byte aligned. @@ -211,15 +209,9 @@ class NativeCallReg: public NativeInstruction { // Instruction format for implied addressing mode immediate operand move to register instruction: // [REX/REX2] [OPCODE] [IMM32] class NativeMovConstReg: public NativeInstruction { -#ifdef AMD64 static const bool has_rex = true; static const int rex_size = 1; static const int rex2_size = 2; -#else - static const bool has_rex = false; - static const int rex_size = 0; - static const int rex2_size = 0; -#endif // AMD64 public: enum Intel_specific_constants { instruction_code = 0xB8, @@ -390,13 +382,8 @@ inline NativeMovRegMem* nativeMovRegMem_at (address address) { // leal reg, [reg + offset] class NativeLoadAddress: public NativeMovRegMem { -#ifdef AMD64 static const bool has_rex = true; static const int rex_size = 1; -#else - static const bool has_rex = false; - static const int rex_size = 0; -#endif // AMD64 public: enum Intel_specific_constants { instruction_prefix_wide = Assembler::REX_W, @@ -447,9 +434,7 @@ class NativeJump: public NativeInstruction { if (dest == (address) -1) { val = -5; // jump to self } -#ifdef AMD64 assert((labs(val) & 0xFFFFFFFF00000000) == 0 || dest == (address)-1, "must be 32bit offset or -1"); -#endif // AMD64 set_int_at(data_offset, (jint)val); } @@ -503,7 +488,7 @@ class NativeGeneralJump: public NativeInstruction { inline NativeGeneralJump* nativeGeneralJump_at(address address) { NativeGeneralJump* jump = (NativeGeneralJump*)(address); - debug_only(jump->verify();) + DEBUG_ONLY(jump->verify();) return jump; } @@ -572,19 +557,14 @@ inline bool NativeInstruction::is_jump_reg() { inline bool NativeInstruction::is_cond_jump() { return (int_at(0) & 0xF0FF) == 0x800F /* long jump */ || (ubyte_at(0) & 0xF0) == 0x70; /* short jump */ } inline bool NativeInstruction::is_safepoint_poll() { -#ifdef AMD64 const bool has_rex_prefix = ubyte_at(0) == NativeTstRegMem::instruction_rex_b_prefix; const int test_offset = has_rex2_prefix() ? 2 : (has_rex_prefix ? 1 : 0); -#else - const int test_offset = 0; -#endif const bool is_test_opcode = ubyte_at(test_offset) == NativeTstRegMem::instruction_code_memXregl; const bool is_rax_target = (ubyte_at(test_offset + 1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg; return is_test_opcode && is_rax_target; } inline bool NativeInstruction::is_mov_literal64() { -#ifdef AMD64 bool valid_rex_prefix = ubyte_at(0) == Assembler::REX_W || ubyte_at(0) == Assembler::REX_WB; bool valid_rex2_prefix = ubyte_at(0) == Assembler::REX2 && (ubyte_at(1) == Assembler::REX2BIT_W || @@ -593,9 +573,6 @@ inline bool NativeInstruction::is_mov_literal64() { int opcode = has_rex2_prefix() ? ubyte_at(2) : ubyte_at(1); return ((valid_rex_prefix || valid_rex2_prefix) && (opcode & (0xff ^ NativeMovConstReg::register_mask)) == 0xB8); -#else - return false; -#endif // AMD64 } class NativePostCallNop: public NativeInstruction { diff --git a/src/hotspot/cpu/x86/runtime_x86_64.cpp b/src/hotspot/cpu/x86/runtime_x86_64.cpp index a063c7aeb37..5865bec2e39 100644 --- a/src/hotspot/cpu/x86/runtime_x86_64.cpp +++ b/src/hotspot/cpu/x86/runtime_x86_64.cpp @@ -25,6 +25,7 @@ #ifdef COMPILER2 #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/aotCodeCache.hpp" #include "code/vmreg.hpp" #include "interpreter/interpreter.hpp" #include "opto/runtime.hpp" @@ -56,11 +57,19 @@ class SimpleRuntimeFrame { //------------------------------generate_uncommon_trap_blob-------------------- UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { + const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::C2Blob, (uint)OptoStubId::uncommon_trap_id, name); + if (blob != nullptr) { + return blob->as_uncommon_trap_blob(); + } + // Allocate space for the code ResourceMark rm; // Setup code generation tools - const char* name = OptoRuntime::stub_name(OptoStubId::uncommon_trap_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); @@ -225,8 +234,10 @@ UncommonTrapBlob* OptoRuntime::generate_uncommon_trap_blob() { // Make sure all code is generated masm->flush(); - return UncommonTrapBlob::create(&buffer, oop_maps, - SimpleRuntimeFrame::framesize >> 1); + UncommonTrapBlob *ut_blob = UncommonTrapBlob::create(&buffer, oop_maps, + SimpleRuntimeFrame::framesize >> 1); + AOTCodeCache::store_code_blob(*ut_blob, AOTCodeEntry::C2Blob, (uint)OptoStubId::uncommon_trap_id, name); + return ut_blob; } //------------------------------generate_exception_blob--------------------------- @@ -262,11 +273,19 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::C2Blob, (uint)OptoStubId::exception_id, name); + if (blob != nullptr) { + return blob->as_exception_blob(); + } + // Allocate space for the code ResourceMark rm; // Setup code generation tools - const char* name = OptoRuntime::stub_name(OptoStubId::exception_id); CodeBuffer buffer(name, 2048, 1024); + if (buffer.blob() == nullptr) { + return nullptr; + } MacroAssembler* masm = new MacroAssembler(&buffer); @@ -357,6 +376,8 @@ ExceptionBlob* OptoRuntime::generate_exception_blob() { masm->flush(); // Set exception blob - return ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); + ExceptionBlob* ex_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); + AOTCodeCache::store_code_blob(*ex_blob, AOTCodeEntry::C2Blob, (uint)OptoStubId::exception_id, name); + return ex_blob; } #endif // COMPILER2 diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 621340964ac..78259157dfa 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -27,6 +27,7 @@ #endif #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "code/debugInfoRec.hpp" #include "code/nativeInst.hpp" @@ -675,7 +676,6 @@ static void patch_callers_callsite(MacroAssembler *masm) { __ bind(L); } - static void gen_c2i_adapter(MacroAssembler *masm, int total_args_passed, int comp_args_on_stack, @@ -826,19 +826,6 @@ static void gen_c2i_adapter(MacroAssembler *masm, __ jmp(rcx); } -static void range_check(MacroAssembler* masm, Register pc_reg, Register temp_reg, - address code_start, address code_end, - Label& L_ok) { - Label L_fail; - __ lea(temp_reg, AddressLiteral(code_start, relocInfo::none)); - __ cmpptr(pc_reg, temp_reg); - __ jcc(Assembler::belowEqual, L_fail); - __ lea(temp_reg, AddressLiteral(code_end, relocInfo::none)); - __ cmpptr(pc_reg, temp_reg); - __ jcc(Assembler::below, L_ok); - __ bind(L_fail); -} - void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, int total_args_passed, int comp_args_on_stack, @@ -871,41 +858,6 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, // If this happens, control eventually transfers back to the compiled // caller, but with an uncorrected stack, causing delayed havoc. - if (VerifyAdapterCalls && - (Interpreter::code() != nullptr || StubRoutines::final_stubs_code() != nullptr)) { - // So, let's test for cascading c2i/i2c adapters right now. - // assert(Interpreter::contains($return_addr) || - // StubRoutines::contains($return_addr), - // "i2c adapter must return to an interpreter frame"); - __ block_comment("verify_i2c { "); - // Pick up the return address - __ movptr(rax, Address(rsp, 0)); - Label L_ok; - if (Interpreter::code() != nullptr) { - range_check(masm, rax, r11, - Interpreter::code()->code_start(), - Interpreter::code()->code_end(), - L_ok); - } - if (StubRoutines::initial_stubs_code() != nullptr) { - range_check(masm, rax, r11, - StubRoutines::initial_stubs_code()->code_begin(), - StubRoutines::initial_stubs_code()->code_end(), - L_ok); - } - if (StubRoutines::final_stubs_code() != nullptr) { - range_check(masm, rax, r11, - StubRoutines::final_stubs_code()->code_begin(), - StubRoutines::final_stubs_code()->code_end(), - L_ok); - } - const char* msg = "i2c adapter must return to an interpreter frame"; - __ block_comment(msg); - __ stop(msg); - __ bind(L_ok); - __ block_comment("} verify_i2ce "); - } - // Must preserve original SP for loading incoming arguments because // we need to align the outgoing SP for compiled code. __ movptr(r11, rsp); @@ -1050,12 +1002,12 @@ void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, } // --------------------------------------------------------------- -AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs, - AdapterFingerPrint* fingerprint) { +void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + AdapterHandlerEntry* handler) { address i2c_entry = __ pc(); gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); @@ -1117,7 +1069,8 @@ AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); - return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); + handler->set_entry_points(i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); + return; } int SharedRuntime::c_calling_convention(const BasicType *sig_bt, @@ -2472,6 +2425,23 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, __ leave(); +#if INCLUDE_JFR + // We need to do a poll test after unwind in case the sampler + // managed to sample the native frame after returning to Java. + Label L_return; + address poll_test_pc = __ pc(); + __ relocate(relocInfo::poll_return_type); + __ testb(Address(r15_thread, JavaThread::polling_word_offset()), SafepointMechanism::poll_bit()); + __ jccb(Assembler::zero, L_return); + __ lea(rscratch1, InternalAddress(poll_test_pc)); + __ movptr(Address(r15_thread, JavaThread::saved_exception_pc_offset()), rscratch1); + assert(SharedRuntime::polling_page_return_handler_blob() != nullptr, + "polling page return stub not created yet"); + address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point(); + __ jump(RuntimeAddress(stub)); + __ bind(L_return); +#endif // INCLUDE_JFR + // Any exception pending? __ cmpptr(Address(r15_thread, in_bytes(Thread::pending_exception_offset())), NULL_WORD); __ jcc(Assembler::notEqual, exception_pending); @@ -2648,6 +2618,12 @@ void SharedRuntime::generate_deopt_blob() { } #endif const char* name = SharedRuntime::stub_name(SharedStubId::deopt_id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, (uint)SharedStubId::deopt_id, name); + if (blob != nullptr) { + _deopt_blob = blob->as_deoptimization_blob(); + return; + } + CodeBuffer buffer(name, 2560+pad, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); int frame_size_in_words; @@ -2999,6 +2975,8 @@ void SharedRuntime::generate_deopt_blob() { _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset); } #endif + + AOTCodeCache::store_code_blob(*_deopt_blob, AOTCodeEntry::SharedBlob, (uint)SharedStubId::deopt_id, name); } //------------------------------generate_handler_blob------ @@ -3011,12 +2989,16 @@ SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address cal "must be generated before"); assert(is_polling_page_id(id), "expected a polling page stub id"); + // Allocate space for the code. Setup code generation tools. + const char* name = SharedRuntime::stub_name(id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, (uint)id, name); + if (blob != nullptr) { + return blob->as_safepoint_blob(); + } + ResourceMark rm; OopMapSet *oop_maps = new OopMapSet(); OopMap* map; - - // Allocate space for the code. Setup code generation tools. - const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 2548, 1024); MacroAssembler* masm = new MacroAssembler(&buffer); @@ -3176,7 +3158,10 @@ SafepointBlob* SharedRuntime::generate_handler_blob(SharedStubId id, address cal masm->flush(); // Fill-out other meta info - return SafepointBlob::create(&buffer, oop_maps, frame_size_in_words); + SafepointBlob* sp_blob = SafepointBlob::create(&buffer, oop_maps, frame_size_in_words); + + AOTCodeCache::store_code_blob(*sp_blob, AOTCodeEntry::SharedBlob, (uint)id, name); + return sp_blob; } // @@ -3191,10 +3176,14 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti assert (StubRoutines::forward_exception_entry() != nullptr, "must be generated before"); assert(is_resolve_id(id), "expected a resolve stub id"); + const char* name = SharedRuntime::stub_name(id); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, (uint)id, name); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + // allocate space for the code ResourceMark rm; - - const char* name = SharedRuntime::stub_name(id); CodeBuffer buffer(name, 1552, 512); MacroAssembler* masm = new MacroAssembler(&buffer); @@ -3263,7 +3252,10 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(SharedStubId id, address desti // return the blob // frame_size_words or bytes?? - return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); + RuntimeStub* rs_blob = RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); + + AOTCodeCache::store_code_blob(*rs_blob, AOTCodeEntry::SharedBlob, (uint)id, name); + return rs_blob; } // Continuation point for throwing of implicit exceptions that are @@ -3301,10 +3293,15 @@ RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address ru int insts_size = 512; int locs_size = 64; - ResourceMark rm; const char* timer_msg = "SharedRuntime generate_throw_exception"; TraceTime timer(timer_msg, TRACETIME_LOG(Info, startuptime)); + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::SharedBlob, (uint)id, name); + if (blob != nullptr) { + return blob->as_runtime_stub(); + } + + ResourceMark rm; CodeBuffer code(name, insts_size, locs_size); OopMapSet* oop_maps = new OopMapSet(); MacroAssembler* masm = new MacroAssembler(&code); @@ -3362,6 +3359,8 @@ RuntimeStub* SharedRuntime::generate_throw_exception(SharedStubId id, address ru frame_complete, (framesize >> (LogBytesPerWord - LogBytesPerInt)), oop_maps, false); + AOTCodeCache::store_code_blob(*stub, AOTCodeEntry::SharedBlob, (uint)id, name); + return stub; } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index b88a2bd1f8e..1014c1c376f 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -3692,6 +3692,9 @@ void StubGenerator::generate_libm_stubs() { if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtanh)) { StubRoutines::_dtanh = generate_libmTanh(); // from stubGenerator_x86_64_tanh.cpp } + if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dcbrt)) { + StubRoutines::_dcbrt = generate_libmCbrt(); // from stubGenerator_x86_64_cbrt.cpp + } if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dexp)) { StubRoutines::_dexp = generate_libmExp(); // from stubGenerator_x86_64_exp.cpp } @@ -4204,6 +4207,8 @@ void StubGenerator::generate_compiler_stubs() { generate_chacha_stubs(); + generate_kyber_stubs(); + generate_dilithium_stubs(); generate_sha3_stubs(); @@ -4333,70 +4338,6 @@ void StubGenerator::generate_compiler_stubs() { } } - // Get svml stub routine addresses - void *libjsvml = nullptr; - char ebuf[1024]; - char dll_name[JVM_MAXPATHLEN]; - if (os::dll_locate_lib(dll_name, sizeof(dll_name), Arguments::get_dll_dir(), "jsvml")) { - libjsvml = os::dll_load(dll_name, ebuf, sizeof ebuf); - } - if (libjsvml != nullptr) { - // SVML method naming convention - // All the methods are named as __jsvml_op_ha_ - // Where: - // ha stands for high accuracy - // is optional to indicate float/double - // Set to f for vector float operation - // Omitted for vector double operation - // is the number of elements in the vector - // 1, 2, 4, 8, 16 - // e.g. 128 bit float vector has 4 float elements - // indicates the avx/sse level: - // z0 is AVX512, l9 is AVX2, e9 is AVX1 and ex is for SSE2 - // e.g. __jsvml_expf16_ha_z0 is the method for computing 16 element vector float exp using AVX 512 insns - // __jsvml_exp8_ha_z0 is the method for computing 8 element vector double exp using AVX 512 insns - - log_info(library)("Loaded library %s, handle " INTPTR_FORMAT, JNI_LIB_PREFIX "jsvml" JNI_LIB_SUFFIX, p2i(libjsvml)); - if (UseAVX > 2) { - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - if ((!VM_Version::supports_avx512dq()) && - (vop == VectorSupport::VECTOR_OP_LOG || vop == VectorSupport::VECTOR_OP_LOG10 || vop == VectorSupport::VECTOR_OP_POW)) { - continue; - } - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf16_ha_z0", VectorSupport::mathname[op]); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s8_ha_z0", VectorSupport::mathname[op]); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_512][op] = (address)os::dll_lookup(libjsvml, ebuf); - } - } - const char* avx_sse_str = (UseAVX >= 2) ? "l9" : ((UseAVX == 1) ? "e9" : "ex"); - for (int op = 0; op < VectorSupport::NUM_VECTOR_OP_MATH; op++) { - int vop = VectorSupport::VECTOR_OP_MATH_START + op; - if (vop == VectorSupport::VECTOR_OP_POW) { - continue; - } - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf4_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%sf8_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_f_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s1_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_64][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s2_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_128][op] = (address)os::dll_lookup(libjsvml, ebuf); - - snprintf(ebuf, sizeof(ebuf), "__jsvml_%s4_ha_%s", VectorSupport::mathname[op], avx_sse_str); - StubRoutines::_vector_d_math[VectorSupport::VEC_SIZE_256][op] = (address)os::dll_lookup(libjsvml, ebuf); - } - } - #endif // COMPILER2 #endif // COMPILER2_OR_JVMCI } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index c08b0168796..2f1e46f3132 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -490,10 +490,13 @@ class StubGenerator: public StubCodeGenerator { // SHA3 stubs void generate_sha3_stubs(); - // Dilithium stubs and helper functions + // Kyber stubs + void generate_kyber_stubs(); + + // Dilithium stubs void generate_dilithium_stubs(); - // BASE64 stubs + // BASE64 stubs address base64_shuffle_addr(); address base64_avx2_shuffle_addr(); address base64_avx2_input_mask_addr(); @@ -553,6 +556,7 @@ class StubGenerator: public StubCodeGenerator { address generate_libmCos(); address generate_libmTan(); address generate_libmTanh(); + address generate_libmCbrt(); address generate_libmExp(); address generate_libmPow(); address generate_libmLog(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp new file mode 100644 index 00000000000..da60a9be276 --- /dev/null +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_cbrt.cpp @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2025, Intel Corporation. All rights reserved. + * Intel Math Library (LIBM) Source Code + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 "macroAssembler_x86.hpp" +#include "stubGenerator_x86_64.hpp" + +/******************************************************************************/ +// ALGORITHM DESCRIPTION +// --------------------- +// +// x=2^{3*k+j} * 1.b1 b2 ... b5 b6 ... b52 +// Let r=(x*2^{-3k-j} - 1.b1 b2 ... b5 1)* rcp[b1 b2 ..b5], +// where rcp[b1 b2 .. b5]=1/(1.b1 b2 b3 b4 b5 1) in double precision +// cbrt(2^j * 1. b1 b2 .. b5 1) is approximated as T[j][b1..b5]+D[j][b1..b5] +// (T stores the high 53 bits, D stores the low order bits) +// Result=2^k*T+(2^k*T*r)*P+2^k*D +// where P=p1+p2*r+..+p8*r^7 +// +// Special cases: +// cbrt(NaN) = quiet NaN +// cbrt(+/-INF) = +/-INF +// cbrt(+/-0) = +/-0 +// +/******************************************************************************/ + +ATTRIBUTE_ALIGNED(4) static const juint _SIG_MASK[] = +{ + 0, 1032192 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _EXP_MASK[] = +{ + 0, 3220176896 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _EXP_MSK2[] = +{ + 0, 3220193280 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _EXP_MSK3[] = +{ + 4294967295, 1048575 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _SCALE63[] = +{ + 0, 1138753536 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _ZERON[] = +{ + 0, 2147483648 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _INF[] = +{ + 0, 2146435072 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _NEG_INF[] = +{ + 0, 4293918720 +}; + +ATTRIBUTE_ALIGNED(16) static const juint _coeff_table[] = +{ + 1553778919, 3213899486, 3534952507, 3215266280, 1646371399, + 3214412045, 477218588, 3216798151, 3582521621, 1066628362, + 1007461464, 1068473053, 889629714, 1067378449, 1431655765, + 1070945621 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _rcp_table[] = +{ + 528611360, 3220144632, 2884679527, 3220082993, 1991868891, 3220024928, + 2298714891, 3219970134, 58835168, 3219918343, 3035110223, 3219869313, + 1617585086, 3219822831, 2500867033, 3219778702, 4241943008, 3219736752, + 258732970, 3219696825, 404232216, 3219658776, 2172167368, 3219622476, + 1544257904, 3219587808, 377579543, 3219554664, 1616385542, 3219522945, + 813783277, 3219492562, 3940743189, 3219463431, 2689777499, 3219435478, + 1700977147, 3219408632, 3169102082, 3219382828, 327235604, 3219358008, + 1244336319, 3219334115, 1300311200, 3219311099, 3095471925, 3219288912, + 2166487928, 3219267511, 2913108253, 3219246854, 293672978, 3219226904, + 288737297, 3219207624, 1810275472, 3219188981, 174592167, 3219170945, + 3539053052, 3219153485, 2164392968, 3219136576 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _cbrt_table[] = +{ + 572345495, 1072698681, 1998204467, 1072709382, 3861501553, 1072719872, + 2268192434, 1072730162, 2981979308, 1072740260, 270859143, 1072750176, + 2958651392, 1072759916, 313113243, 1072769490, 919449400, 1072778903, + 2809328903, 1072788162, 2222981587, 1072797274, 2352530781, 1072806244, + 594152517, 1072815078, 1555767199, 1072823780, 4282421314, 1072832355, + 2355578597, 1072840809, 1162590619, 1072849145, 797864051, 1072857367, + 431273680, 1072865479, 2669831148, 1072873484, 733477752, 1072881387, + 4280220604, 1072889189, 801961634, 1072896896, 2915370760, 1072904508, + 1159613482, 1072912030, 2689944798, 1072919463, 1248687822, 1072926811, + 2967951030, 1072934075, 630170432, 1072941259, 3760898254, 1072948363, + 0, 1072955392, 2370273294, 1072962345, 1261754802, 1072972640, + 546334065, 1072986123, 1054893830, 1072999340, 1571187597, 1073012304, + 1107975175, 1073025027, 3606909377, 1073037519, 1113616747, 1073049792, + 4154744632, 1073061853, 3358931423, 1073073713, 4060702372, 1073085379, + 747576176, 1073096860, 3023138255, 1073108161, 1419988548, 1073119291, + 1914185305, 1073130255, 294389948, 1073141060, 3761802570, 1073151710, + 978281566, 1073162213, 823148820, 1073172572, 2420954441, 1073182792, + 3815449908, 1073192878, 2046058587, 1073202835, 1807524753, 1073212666, + 2628681401, 1073222375, 3225667357, 1073231966, 1555307421, 1073241443, + 3454043099, 1073250808, 1208137896, 1073260066, 3659916772, 1073269218, + 1886261264, 1073278269, 3593647839, 1073287220, 3086012205, 1073296075, + 2769796922, 1073304836, 888716057, 1073317807, 2201465623, 1073334794, + 164369365, 1073351447, 3462666733, 1073367780, 2773905457, 1073383810, + 1342879088, 1073399550, 2543933975, 1073415012, 1684477781, 1073430209, + 3532178543, 1073445151, 1147747300, 1073459850, 1928031793, 1073474314, + 2079717015, 1073488553, 4016765315, 1073502575, 3670431139, 1073516389, + 3549227225, 1073530002, 11637607, 1073543422, 588220169, 1073556654, + 2635407503, 1073569705, 2042029317, 1073582582, 1925128962, 1073595290, + 4136375664, 1073607834, 759964600, 1073620221, 4257606771, 1073632453, + 297278907, 1073644538, 3655053093, 1073656477, 2442253172, 1073668277, + 1111876799, 1073679941, 3330973139, 1073691472, 3438879452, 1073702875, + 3671565478, 1073714153, 1317849547, 1073725310, 1642364115, 1073736348 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _D_table[] = +{ + 4050900474, 1014427190, 1157977860, 1016444461, 1374568199, 1017271387, + 2809163288, 1016882676, 3742377377, 1013168191, 3101606597, 1017541672, + 65224358, 1017217597, 2691591250, 1017266643, 4020758549, 1017689313, + 1316310992, 1018030788, 1031537856, 1014090882, 3261395239, 1016413641, + 886424999, 1016313335, 3114776834, 1014195875, 1681120620, 1017825416, + 1329600273, 1016625740, 465474623, 1017097119, 4251633980, 1017169077, + 1986990133, 1017710645, 752958613, 1017159641, 2216216792, 1018020163, + 4282860129, 1015924861, 1557627859, 1016039538, 3889219754, 1018086237, + 3684996408, 1017353275, 723532103, 1017717141, 2951149676, 1012528470, + 831890937, 1017830553, 1031212645, 1017387331, 2741737450, 1017604974, + 2863311531, 1003776682, 4276736099, 1013153088, 4111778382, 1015673686, + 1728065769, 1016413986, 2708718031, 1018078833, 1069335005, 1015291224, + 700037144, 1016482032, 2904566452, 1017226861, 4074156649, 1017622651, + 25019565, 1015245366, 3601952608, 1015771755, 3267129373, 1017904664, + 503203103, 1014921629, 2122011730, 1018027866, 3927295461, 1014189456, + 2790625147, 1016024251, 1330460186, 1016940346, 4033568463, 1015538390, + 3695818227, 1017509621, 257573361, 1017208868, 3227697852, 1017337964, + 234118548, 1017169577, 4009025803, 1017278524, 1948343394, 1017749310, + 678398162, 1018144239, 3083864863, 1016669086, 2415453452, 1017890370, + 175467344, 1017330033, 3197359580, 1010339928, 2071276951, 1015941358, + 268372543, 1016737773, 938132959, 1017389108, 1816750559, 1017337448, + 4119203749, 1017152174, 2578653878, 1013108497, 2470331096, 1014678606, + 123855735, 1016553320, 1265650889, 1014782687, 3414398172, 1017182638, + 1040773369, 1016158401, 3483628886, 1016886550, 4140499405, 1016191425, + 3893477850, 1016964495, 3935319771, 1009634717, 2978982660, 1015027112, + 2452709923, 1017990229, 3190365712, 1015835149, 4237588139, 1015832925, + 2610678389, 1017962711, 2127316774, 1017405770, 824267502, 1017959463, + 2165924042, 1017912225, 2774007076, 1013257418, 4123916326, 1017582284, + 1976417958, 1016959909, 4092806412, 1017711279, 119251817, 1015363631, + 3475418768, 1017675415, 1972580503, 1015470684, 815541017, 1017517969, + 2429917451, 1017397776, 4062888482, 1016749897, 68284153, 1017925678, + 2207779246, 1016320298, 1183466520, 1017408657, 143326427, 1017060403 +}; + +#define __ _masm-> + +address StubGenerator::generate_libmCbrt() { + StubGenStubId stub_id = StubGenStubId::dcbrt_id; + StubCodeMark mark(this, stub_id); + address start = __ pc(); + + Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1, L_2TAG_PACKET_3_0_1; + Label L_2TAG_PACKET_4_0_1, L_2TAG_PACKET_5_0_1, L_2TAG_PACKET_6_0_1; + Label B1_1, B1_2, B1_4; + + address SIG_MASK = (address)_SIG_MASK; + address EXP_MASK = (address)_EXP_MASK; + address EXP_MSK2 = (address)_EXP_MSK2; + address EXP_MSK3 = (address)_EXP_MSK3; + address SCALE63 = (address)_SCALE63; + address ZERON = (address)_ZERON; + address INF = (address)_INF; + address NEG_INF = (address)_NEG_INF; + address coeff_table = (address)_coeff_table; + address rcp_table = (address)_rcp_table; + address cbrt_table = (address)_cbrt_table; + address D_table = (address)_D_table; + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + __ bind(B1_1); + __ subq(rsp, 24); + __ movsd(Address(rsp), xmm0); + + __ bind(B1_2); + __ movq(xmm7, xmm0); + __ movl(rdx, 524032); + __ movsd(xmm5, ExternalAddress(EXP_MSK3), r11 /*rscratch*/); + __ movsd(xmm3, ExternalAddress(EXP_MSK2), r11 /*rscratch*/); + __ psrlq(xmm7, 44); + __ pextrw(rcx, xmm7, 0); + __ movdl(rax, xmm7); + __ movsd(xmm1, ExternalAddress(EXP_MASK), r11 /*rscratch*/); + __ movsd(xmm2, ExternalAddress(SIG_MASK), r11 /*rscratch*/); + __ andl(rcx, 248); + __ lea(r8, ExternalAddress(rcp_table)); + __ movsd(xmm4, Address(rcx, r8, Address::times_1)); + __ movq(r9, rax); + __ andl(rdx, rax); + __ cmpl(rdx, 0); + __ jcc(Assembler::equal, L_2TAG_PACKET_0_0_1); // Branch only if |x| is denormalized + __ cmpl(rdx, 524032); + __ jcc(Assembler::equal, L_2TAG_PACKET_1_0_1); // Branch only if |x| is INF or NaN + __ shrl(rdx, 8); + __ shrq(r9, 8); + __ andpd(xmm2, xmm0); + __ andpd(xmm0, xmm5); + __ orpd(xmm3, xmm2); + __ orpd(xmm1, xmm0); + __ movapd(xmm5, ExternalAddress(coeff_table), r11 /*rscratch*/); + __ movl(rax, 5462); + __ movapd(xmm6, ExternalAddress(coeff_table + 16), r11 /*rscratch*/); + __ mull(rdx); + __ movq(rdx, r9); + __ andq(r9, 2047); + __ shrl(rax, 14); + __ andl(rdx, 2048); + __ subq(r9, rax); + __ subq(r9, rax); + __ subq(r9, rax); + __ shlq(r9, 8); + __ addl(rax, 682); + __ orl(rax, rdx); + __ movdl(xmm7, rax); + __ addq(rcx, r9); + __ psllq(xmm7, 52); + + __ bind(L_2TAG_PACKET_2_0_1); + __ movapd(xmm2, ExternalAddress(coeff_table + 32), r11 /*rscratch*/); + __ movapd(xmm0, ExternalAddress(coeff_table + 48), r11 /*rscratch*/); + __ subsd(xmm1, xmm3); + __ movq(xmm3, xmm7); + __ lea(r8, ExternalAddress(cbrt_table)); + __ mulsd(xmm7, Address(rcx, r8, Address::times_1)); + __ mulsd(xmm1, xmm4); + __ lea(r8, ExternalAddress(D_table)); + __ mulsd(xmm3, Address(rcx, r8, Address::times_1)); + __ movapd(xmm4, xmm1); + __ unpcklpd(xmm1, xmm1); + __ mulpd(xmm5, xmm1); + __ mulpd(xmm6, xmm1); + __ mulpd(xmm1, xmm1); + __ addpd(xmm2, xmm5); + __ addpd(xmm0, xmm6); + __ mulpd(xmm2, xmm1); + __ mulpd(xmm1, xmm1); + __ mulsd(xmm4, xmm7); + __ addpd(xmm0, xmm2); + __ mulsd(xmm1, xmm0); + __ unpckhpd(xmm0, xmm0); + __ addsd(xmm0, xmm1); + __ mulsd(xmm0, xmm4); + __ addsd(xmm0, xmm3); + __ addsd(xmm0, xmm7); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_0_0_1); + __ mulsd(xmm0, ExternalAddress(SCALE63), r11 /*rscratch*/); + __ movq(xmm7, xmm0); + __ movl(rdx, 524032); + __ psrlq(xmm7, 44); + __ pextrw(rcx, xmm7, 0); + __ movdl(rax, xmm7); + __ andl(rcx, 248); + __ lea(r8, ExternalAddress(rcp_table)); + __ movsd(xmm4, Address(rcx, r8, Address::times_1)); + __ movq(r9, rax); + __ andl(rdx, rax); + __ shrl(rdx, 8); + __ shrq(r9, 8); + __ cmpl(rdx, 0); + __ jcc(Assembler::equal, L_2TAG_PACKET_3_0_1); // Branch only if |x| is zero + __ andpd(xmm2, xmm0); + __ andpd(xmm0, xmm5); + __ orpd(xmm3, xmm2); + __ orpd(xmm1, xmm0); + __ movapd(xmm5, ExternalAddress(coeff_table), r11 /*rscratch*/); + __ movl(rax, 5462); + __ movapd(xmm6, ExternalAddress(coeff_table + 16), r11 /*rscratch*/); + __ mull(rdx); + __ movq(rdx, r9); + __ andq(r9, 2047); + __ shrl(rax, 14); + __ andl(rdx, 2048); + __ subq(r9, rax); + __ subq(r9, rax); + __ subq(r9, rax); + __ shlq(r9, 8); + __ addl(rax, 661); + __ orl(rax, rdx); + __ movdl(xmm7, rax); + __ addq(rcx, r9); + __ psllq(xmm7, 52); + __ jmp(L_2TAG_PACKET_2_0_1); + + __ bind(L_2TAG_PACKET_3_0_1); + __ cmpq(r9, 0); + __ jcc(Assembler::notEqual, L_2TAG_PACKET_4_0_1); // Branch only if x is negative zero + __ xorpd(xmm0, xmm0); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_4_0_1); + __ movsd(xmm0, ExternalAddress(ZERON), r11 /*rscratch*/); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_1_0_1); + __ movl(rax, Address(rsp, 4)); + __ movl(rdx, Address(rsp)); + __ movl(rcx, rax); + __ andl(rcx, 2147483647); + __ cmpl(rcx, 2146435072); + __ jcc(Assembler::above, L_2TAG_PACKET_5_0_1); // Branch only if |x| is NaN + __ cmpl(rdx, 0); + __ jcc(Assembler::notEqual, L_2TAG_PACKET_5_0_1); // Branch only if |x| is NaN + __ cmpl(rax, 2146435072); + __ jcc(Assembler::notEqual, L_2TAG_PACKET_6_0_1); // Branch only if x is negative INF + __ movsd(xmm0, ExternalAddress(INF), r11 /*rscratch*/); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_6_0_1); + __ movsd(xmm0, ExternalAddress(NEG_INF), r11 /*rscratch*/); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_5_0_1); + __ movsd(xmm0, Address(rsp)); + __ addsd(xmm0, xmm0); + __ movq(Address(rsp, 8), xmm0); + + __ bind(B1_4); + __ addq(rsp, 24); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; +} + +#undef __ diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp new file mode 100644 index 00000000000..91c005e92de --- /dev/null +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_kyber.cpp @@ -0,0 +1,952 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "runtime/stubRoutines.hpp" +#include "macroAssembler_x86.hpp" +#include "stubGenerator_x86_64.hpp" + +#define __ _masm-> + +#define xmm(i) as_XMMRegister(i) + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif // PRODUCT + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +// Constants +// +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512Consts[] = { + 0xF301, 0xF301, 0xF301, 0xF301, // q^-1 mod montR + 0x0D01, 0x0D01, 0x0D01, 0x0D01, // q + 0x4EBF, 0x4EBF, 0x4EBF, 0x4EBF, // Barrett multiplier + 0x0200, 0x0200, 0x0200, 0x0200, //(dim/2)^-1 mod q + 0x0549, 0x0549, 0x0549, 0x0549, // montR^2 mod q + 0x0F00, 0x0F00, 0x0F00, 0x0F00 // mask for kyber12to16 + }; + +static int qInvModROffset = 0; +static int qOffset = 8; +static int barretMultiplierOffset = 16; +static int dimHalfInverseOffset = 24; +static int montRSquareModqOffset = 32; +static int f00Offset = 40; + +static address kyberAvx512ConstsAddr(int offset) { + return ((address) kyberAvx512Consts) + offset; +} + +const Register scratch = r10; + +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512NttPerms[] = { +// 0 + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, +// 128 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +// 256 + 0x00, 0x01, 0x02, 0x03, 0x20, 0x21, 0x22, 0x23, + 0x08, 0x09, 0x0A, 0x0B, 0x28, 0x29, 0x2A, 0x2B, + 0x10, 0x11, 0x12, 0x13, 0x30, 0x31, 0x32, 0x33, + 0x18, 0x19, 0x1A, 0x1B, 0x38, 0x39, 0x3A, 0x3B, + 0x04, 0x05, 0x06, 0x07, 0x24, 0x25, 0x26, 0x27, + 0x0C, 0x0D, 0x0E, 0x0F, 0x2C, 0x2D, 0x2E, 0x2F, + 0x14, 0x15, 0x16, 0x17, 0x34, 0x35, 0x36, 0x37, + 0x1C, 0x1D, 0x1E, 0x1F, 0x3C, 0x3D, 0x3E, 0x3F, +// 384 + 0x00, 0x01, 0x20, 0x21, 0x04, 0x05, 0x24, 0x25, + 0x08, 0x09, 0x28, 0x29, 0x0C, 0x0D, 0x2C, 0x2D, + 0x10, 0x11, 0x30, 0x31, 0x14, 0x15, 0x34, 0x35, + 0x18, 0x19, 0x38, 0x39, 0x1C, 0x1D, 0x3C, 0x3D, + 0x02, 0x03, 0x22, 0x23, 0x06, 0x07, 0x26, 0x27, + 0x0A, 0x0B, 0x2A, 0x2B, 0x0E, 0x0F, 0x2E, 0x2F, + 0x12, 0x13, 0x32, 0x33, 0x16, 0x17, 0x36, 0x37, + 0x1A, 0x1B, 0x3A, 0x3B, 0x1E, 0x1F, 0x3E, 0x3F, +// 512 + 0x10, 0x11, 0x30, 0x31, 0x12, 0x13, 0x32, 0x33, + 0x14, 0x15, 0x34, 0x35, 0x16, 0x17, 0x36, 0x37, + 0x18, 0x19, 0x38, 0x39, 0x1A, 0x1B, 0x3A, 0x3B, + 0x1C, 0x1D, 0x3C, 0x3D, 0x1E, 0x1F, 0x3E, 0x3F, + 0x00, 0x01, 0x20, 0x21, 0x02, 0x03, 0x22, 0x23, + 0x04, 0x05, 0x24, 0x25, 0x06, 0x07, 0x26, 0x27, + 0x08, 0x09, 0x28, 0x29, 0x0A, 0x0B, 0x2A, 0x2B, + 0x0C, 0x0D, 0x2C, 0x2D, 0x0E, 0x0F, 0x2E, 0x2F + }; + +static address kyberAvx512NttPermsAddr() { + return (address) kyberAvx512NttPerms; +} + +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512InverseNttPerms[] = { +// 0 + 0x02, 0x03, 0x06, 0x07, 0x0A, 0x0B, 0x0E, 0x0F, + 0x12, 0x13, 0x16, 0x17, 0x1A, 0x1B, 0x1E, 0x1F, + 0x22, 0x23, 0x26, 0x27, 0x2A, 0x2B, 0x2E, 0x2F, + 0x32, 0x33, 0x36, 0x37, 0x3A, 0x3B, 0x3E, 0x3F, + 0x00, 0x01, 0x04, 0x05, 0x08, 0x09, 0x0C, 0x0D, + 0x10, 0x11, 0x14, 0x15, 0x18, 0x19, 0x1C, 0x1D, + 0x20, 0x21, 0x24, 0x25, 0x28, 0x29, 0x2C, 0x2D, + 0x30, 0x31, 0x34, 0x35, 0x38, 0x39, 0x3C, 0x3D, +// 128 + 0x00, 0x01, 0x20, 0x21, 0x04, 0x05, 0x24, 0x25, + 0x08, 0x09, 0x28, 0x29, 0x0C, 0x0D, 0x2C, 0x2D, + 0x10, 0x11, 0x30, 0x31, 0x14, 0x15, 0x34, 0x35, + 0x18, 0x19, 0x38, 0x39, 0x1C, 0x1D, 0x3C, 0x3D, + 0x02, 0x03, 0x22, 0x23, 0x06, 0x07, 0x26, 0x27, + 0x0A, 0x0B, 0x2A, 0x2B, 0x0E, 0x0F, 0x2E, 0x2F, + 0x12, 0x13, 0x32, 0x33, 0x16, 0x17, 0x36, 0x37, + 0x1A, 0x1B, 0x3A, 0x3B, 0x1E, 0x1F, 0x3E, 0x3F, +// 256 + 0x00, 0x01, 0x02, 0x03, 0x20, 0x21, 0x22, 0x23, + 0x08, 0x09, 0x0A, 0x0B, 0x28, 0x29, 0x2A, 0x2B, + 0x10, 0x11, 0x12, 0x13, 0x30, 0x31, 0x32, 0x33, + 0x18, 0x19, 0x1A, 0x1B, 0x38, 0x39, 0x3A, 0x3B, + 0x04, 0x05, 0x06, 0x07, 0x24, 0x25, 0x26, 0x27, + 0x0C, 0x0D, 0x0E, 0x0F, 0x2C, 0x2D, 0x2E, 0x2F, + 0x14, 0x15, 0x16, 0x17, 0x34, 0x35, 0x36, 0x37, + 0x1C, 0x1D, 0x1E, 0x1F, 0x3C, 0x3D, 0x3E, 0x3F, +// 384 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +// 512 + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F + }; + +static address kyberAvx512InverseNttPermsAddr() { + return (address) kyberAvx512InverseNttPerms; +} + +ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512_nttMultPerms[] = { + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E, + + 0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x11, 0x13, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F, + 0x21, 0x23, 0x25, 0x27, 0x29, 0x2B, 0x2D, 0x2F, + 0x31, 0x33, 0x35, 0x37, 0x39, 0x3B, 0x3D, 0x3F, + + 0x00, 0x20, 0x01, 0x21, 0x02, 0x22, 0x03, 0x23, + 0x04, 0x24, 0x05, 0x25, 0x06, 0x26, 0x07, 0x27, + 0x08, 0x28, 0x09, 0x29, 0x0A, 0x2A, 0x0B, 0x2B, + 0x0C, 0x2C, 0x0D, 0x2D, 0x0E, 0x2E, 0x0F, 0x2F, + + 0x10, 0x30, 0x11, 0x31, 0x12, 0x32, 0x13, 0x33, + 0x14, 0x34, 0x15, 0x35, 0x16, 0x36, 0x17, 0x37, + 0x18, 0x38, 0x19, 0x39, 0x1A, 0x3A, 0x1B, 0x3B, + 0x1C, 0x3C, 0x1D, 0x3D, 0x1E, 0x3E, 0x1F, 0x3F + }; + +static address kyberAvx512_nttMultPermsAddr() { + return (address) kyberAvx512_nttMultPerms; +} + + ATTRIBUTE_ALIGNED(64) static const uint16_t kyberAvx512_12To16Perms[] = { +// 0 + 0x00, 0x03, 0x06, 0x09, 0x0C, 0x0F, 0x12, 0x15, + 0x18, 0x1B, 0x1E, 0x21, 0x24, 0x27, 0x2A, 0x2D, + 0x30, 0x33, 0x36, 0x39, 0x3C, 0x3F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x04, 0x07, 0x0A, 0x0D, 0x10, 0x13, 0x16, + 0x19, 0x1C, 0x1F, 0x22, 0x25, 0x28, 0x2B, 0x2E, + 0x31, 0x34, 0x37, 0x3A, 0x3D, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +// 128 + 0x02, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x17, + 0x1A, 0x1D, 0x20, 0x23, 0x26, 0x29, 0x2C, 0x2F, + 0x32, 0x35, 0x38, 0x3B, 0x3E, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x22, 0x25, + 0x28, 0x2B, 0x2E, 0x31, 0x34, 0x37, 0x3A, 0x3D, +// 256 + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x20, 0x23, 0x26, + 0x29, 0x2C, 0x2F, 0x32, 0x35, 0x38, 0x3B, 0x3E, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x21, 0x24, 0x27, + 0x2A, 0x2D, 0x30, 0x33, 0x36, 0x39, 0x3C, 0x3F, +// 384 + 0x00, 0x20, 0x01, 0x21, 0x02, 0x22, 0x03, 0x23, + 0x04, 0x24, 0x05, 0x25, 0x06, 0x26, 0x07, 0x27, + 0x08, 0x28, 0x09, 0x29, 0x0A, 0x2A, 0x0B, 0x2B, + 0x0C, 0x2C, 0x0D, 0x2D, 0x0E, 0x2E, 0x0F, 0x2F, + 0x10, 0x30, 0x11, 0x31, 0x12, 0x32, 0x13, 0x33, + 0x14, 0x34, 0x15, 0x35, 0x16, 0x36, 0x17, 0x37, + 0x18, 0x38, 0x19, 0x39, 0x1A, 0x3A, 0x1B, 0x3B, + 0x1C, 0x3C, 0x1D, 0x3D, 0x1E, 0x3E, 0x1F, 0x3F + }; + +static address kyberAvx512_12To16PermsAddr() { + return (address) kyberAvx512_12To16Perms; +} + +static void load4regs(int destRegs[], Register address, int offset, + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evmovdquw(xmm(destRegs[i]), Address(address, offset + i * 64), + Assembler::AVX_512bit); + } +} + +// For z = montmul(a,b), z will be between -q and q and congruent +// to a * b * R^-1 mod q, where R > 2 * q, R is a power of 2, +// -R/2 * q <= a * b < R/2 * q. +// (See e.g. Algorithm 3 in https://eprint.iacr.org/2018/039.pdf) +// For the Java code, we use R = 2^20 and for the intrinsic, R = 2^16. +// In our computations, b is always c * R mod q, so the montmul() really +// computes a * c mod q. In the Java code, we use 32-bit numbers for the +// computations, and we use R = 2^20 because that way the a * b numbers +// that occur during all computations stay in the required range. +// For the intrinsics, we use R = 2^16, because this way we can do twice +// as much work in parallel, the only drawback is that we should do some Barrett +// reductions in kyberInverseNtt so that the numbers stay in the required range. +static void montmul(int outputRegs[], int inputRegs1[], int inputRegs2[], + int scratchRegs1[], int scratchRegs2[], MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evpmullw(xmm(scratchRegs1[i]), k0, xmm(inputRegs1[i]), + xmm(inputRegs2[i]), false, Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpmulhw(xmm(scratchRegs2[i]), k0, xmm(inputRegs1[i]), + xmm(inputRegs2[i]), false, Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpmullw(xmm(scratchRegs1[i]), k0, xmm(scratchRegs1[i]), + xmm31, false, Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpmulhw(xmm(scratchRegs1[i]), k0, xmm(scratchRegs1[i]), + xmm30, false, Assembler::AVX_512bit); + } + for (int i = 0; i < 4; i++) { + __ evpsubw(xmm(outputRegs[i]), k0, xmm(scratchRegs2[i]), + xmm(scratchRegs1[i]), false, Assembler::AVX_512bit); + } +} + +static void sub_add(int subResult[], int addResult[], int input1[], int input2[], + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evpsubw(xmm(subResult[i]), k0, xmm(input1[i]), xmm(input2[i]), + false, Assembler::AVX_512bit); + __ evpaddw(xmm(addResult[i]), k0, xmm(input1[i]), xmm(input2[i]), + false, Assembler::AVX_512bit); + } +} + +// result2 also acts as input1 +// result1 also acts as perm1 +static void permute(int result1[], int result2[], int input2[], int perm2, + MacroAssembler *_masm) { + + for (int i = 1; i < 4; i++) { + __ evmovdquw(xmm(result1[i]), xmm(result1[0]), Assembler::AVX_512bit); + } + + for (int i = 0; i < 4; i++) { + __ evpermi2w(xmm(result1[i]), xmm(result2[i]), xmm(input2[i]), + Assembler::AVX_512bit); + __ evpermt2w(xmm(result2[i]), xmm(perm2), xmm(input2[i]), + Assembler::AVX_512bit); + } +} + +static void store4regs(Register address, int offset, int sourceRegs[], + MacroAssembler *_masm) { + for (int i = 0; i < 4; i++) { + __ evmovdquw(Address(address, offset + i * 64), xmm(sourceRegs[i]), + Assembler::AVX_512bit); + } +} + +// In all 3 invocations of this function we use the same registers: +// xmm0-xmm7 for the input and the result, +// xmm8-xmm15 as scratch registers and +// xmm16-xmm17 for the constants, +// so we don't pass register arguments. +static void barrettReduce(MacroAssembler *_masm) { + for (int i = 0; i < 8; i++) { + __ evpmulhw(xmm(i + 8), k0, xmm(i), xmm16, false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpsraw(xmm(i + 8), k0, xmm(i + 8), 10, false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpmullw(xmm(i + 8), k0, xmm(i + 8), xmm17, false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpsubw(xmm(i), k0, xmm(i), xmm(i + 8), false, Assembler::AVX_512bit); + } +} + +static int xmm0_3[] = {0, 1, 2, 3}; +static int xmm0145[] = {0, 1, 4, 5}; +static int xmm0246[] = {0, 2, 4, 6}; +static int xmm0829[] = {0, 8, 2, 9}; +static int xmm1001[] = {1, 0, 0, 1}; +static int xmm1357[] = {1, 3, 5, 7}; +static int xmm2367[] = {2, 3, 6, 7}; +static int xmm2_0_10_8[] = {2, 0, 10, 8}; +static int xmm3223[] = {3, 2, 2, 3}; +static int xmm4_7[] = {4, 5, 6, 7}; +static int xmm5454[] = {5, 4, 5, 4}; +static int xmm7676[] = {7, 6, 7, 6}; +static int xmm8_11[] = {8, 9, 10, 11}; +static int xmm12_15[] = {12, 13, 14, 15}; +static int xmm16_19[] = {16, 17, 18, 19}; +static int xmm20_23[] = {20, 21, 22, 23}; +static int xmm23_23[] = {23, 23, 23, 23}; +static int xmm24_27[] = {24, 25, 26, 27}; +static int xmm26_29[] = {26, 27, 28, 29}; +static int xmm28_31[] = {28, 29, 30, 31}; +static int xmm29_29[] = {29, 29, 29, 29}; + +// Kyber NTT function. +// +// coeffs (short[256]) = c_rarg0 +// ntt_zetas (short[256]) = c_rarg1 +address generate_kyberNtt_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + __ align(CodeEntryAlignment); + StubGenStubId stub_id = kyberNtt_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register perms = r11; + + __ lea(perms, ExternalAddress(kyberAvx512NttPermsAddr())); + + load4regs(xmm4_7, coeffs, 256, _masm); + load4regs(xmm20_23, zetas, 0, _masm); + + __ vpbroadcastq(xmm30, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qInvModROffset)), + Assembler::AVX_512bit, scratch); // q^-1 mod montR + + load4regs(xmm0_3, coeffs, 0, _masm); + + // Each level represents one iteration of the outer for loop of the Java version. + // level 0 + montmul(xmm8_11, xmm4_7, xmm20_23, xmm8_11, xmm4_7, _masm); + load4regs(xmm20_23, zetas, 256, _masm); + sub_add(xmm4_7, xmm0_3, xmm0_3, xmm8_11, _masm); + + //level 1 + montmul(xmm12_15, xmm2367, xmm20_23, xmm12_15, xmm8_11, _masm); + load4regs(xmm20_23, zetas, 512, _masm); + sub_add(xmm2367, xmm0145, xmm0145, xmm12_15, _masm); + + // level 2 + montmul(xmm8_11, xmm1357, xmm20_23, xmm12_15, xmm8_11, _masm); + __ evmovdquw(xmm12, Address(perms, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm16, Address(perms, 64), Assembler::AVX_512bit); + load4regs(xmm20_23, zetas, 768, _masm); + sub_add(xmm1357, xmm0246, xmm0246, xmm8_11, _masm); + + //level 3 + permute(xmm12_15, xmm0246, xmm1357, 16, _masm); + montmul(xmm8_11, xmm12_15, xmm20_23, xmm16_19, xmm8_11, _masm); + __ evmovdquw(xmm16, Address(perms, 128), Assembler::AVX_512bit); + __ evmovdquw(xmm24, Address(perms, 192), Assembler::AVX_512bit); + load4regs(xmm20_23, zetas, 1024, _masm); + sub_add(xmm1357, xmm0246, xmm0246, xmm8_11, _masm); + + // level 4 + permute(xmm16_19, xmm0246, xmm1357, 24, _masm); + montmul(xmm8_11, xmm0246, xmm20_23, xmm24_27, xmm8_11, _masm); + __ evmovdquw(xmm1, Address(perms, 256), Assembler::AVX_512bit); + __ evmovdquw(xmm24, Address(perms, 320), Assembler::AVX_512bit); + load4regs(xmm20_23, zetas, 1280, _masm); + sub_add(xmm12_15, xmm0246, xmm16_19, xmm8_11, _masm); + + // level 5 + permute(xmm1357, xmm0246, xmm12_15, 24, _masm); + montmul(xmm16_19, xmm0246, xmm20_23, xmm16_19, xmm8_11, _masm); + + __ evmovdquw(xmm12, Address(perms, 384), Assembler::AVX_512bit); + __ evmovdquw(xmm8, Address(perms, 448), Assembler::AVX_512bit); + + load4regs(xmm20_23, zetas, 1536, _masm); + sub_add(xmm24_27, xmm0246, xmm1357, xmm16_19, _masm); + + // level 6 + permute(xmm12_15, xmm0246, xmm24_27, 8, _masm); + + __ evmovdquw(xmm1, Address(perms, 512), Assembler::AVX_512bit); + __ evmovdquw(xmm24, Address(perms, 576), Assembler::AVX_512bit); + + montmul(xmm16_19, xmm0246, xmm20_23, xmm16_19, xmm8_11, _masm); + sub_add(xmm20_23, xmm0246, xmm12_15, xmm16_19, _masm); + + permute(xmm1357, xmm0246, xmm20_23, 24, _masm); + + store4regs(coeffs, 0, xmm0_3, _masm); + store4regs(coeffs, 256, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber Inverse NTT function +// +// coeffs (short[256]) = c_rarg0 +// ntt_zetas (short[256]) = c_rarg1 +address generate_kyberInverseNtt_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = kyberInverseNtt_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + const Register zetas = c_rarg1; + + const Register perms = r11; + + __ lea(perms, ExternalAddress(kyberAvx512InverseNttPermsAddr())); + __ evmovdquw(xmm12, Address(perms, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm16, Address(perms, 64), Assembler::AVX_512bit); + + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qInvModROffset)), + Assembler::AVX_512bit, scratch); // q^-1 mod montR + __ vpbroadcastq(xmm30, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastq(xmm29, + ExternalAddress(kyberAvx512ConstsAddr(dimHalfInverseOffset)), + Assembler::AVX_512bit, scratch); // (dim/2)^-1 mod q + + load4regs(xmm0_3, coeffs, 0, _masm); + load4regs(xmm4_7, coeffs, 256, _masm); + + // Each level represents one iteration of the outer for loop of the Java version. + // level 0 + load4regs(xmm8_11, zetas, 0, _masm); + permute(xmm12_15, xmm0246, xmm1357, 16, _masm); + + __ evmovdquw(xmm1, Address(perms, 128), Assembler::AVX_512bit); + __ evmovdquw(xmm20, Address(perms, 192), Assembler::AVX_512bit); + + sub_add(xmm16_19, xmm0246, xmm0246, xmm12_15, _masm); + montmul(xmm12_15, xmm16_19, xmm8_11, xmm12_15, xmm8_11, _masm); + + // level 1 + load4regs(xmm8_11, zetas, 256, _masm); + permute(xmm1357, xmm0246, xmm12_15, 20, _masm); + sub_add(xmm16_19, xmm0246, xmm1357, xmm0246, _masm); + + __ evmovdquw(xmm1, Address(perms, 256), Assembler::AVX_512bit); + __ evmovdquw(xmm20, Address(perms, 320), Assembler::AVX_512bit); + + montmul(xmm12_15, xmm16_19, xmm8_11, xmm12_15, xmm8_11, _masm); + + // level2 + load4regs(xmm8_11, zetas, 512, _masm); + permute(xmm1357, xmm0246, xmm12_15, 20, _masm); + sub_add(xmm16_19, xmm0246, xmm1357, xmm0246,_masm); + + __ evmovdquw(xmm1, Address(perms, 384), Assembler::AVX_512bit); + __ evmovdquw(xmm20, Address(perms, 448), Assembler::AVX_512bit); + + montmul(xmm12_15, xmm16_19, xmm8_11, xmm12_15, xmm8_11, _masm); + + __ vpbroadcastq(xmm16, + ExternalAddress(kyberAvx512ConstsAddr(barretMultiplierOffset)), + Assembler::AVX_512bit, scratch); // Barrett multiplier + __ vpbroadcastq(xmm17, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + permute(xmm1357, xmm0246, xmm12_15, 20, _masm); + barrettReduce(_masm); + +// level 3 + load4regs(xmm8_11, zetas, 768, _masm); + sub_add(xmm16_19, xmm0246, xmm1357, xmm0246, _masm); + + __ evmovdquw(xmm1, Address(perms, 512), Assembler::AVX_512bit); + __ evmovdquw(xmm20, Address(perms, 576), Assembler::AVX_512bit); + + montmul(xmm12_15, xmm16_19, xmm8_11, xmm12_15, xmm8_11, _masm); + permute(xmm1357, xmm0246, xmm12_15, 20, _masm); + + // level 4 + load4regs(xmm8_11, zetas, 1024, _masm); + + __ vpbroadcastq(xmm16, + ExternalAddress(kyberAvx512ConstsAddr(barretMultiplierOffset)), + Assembler::AVX_512bit, scratch); // Barrett multiplier + __ vpbroadcastq(xmm17, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + sub_add(xmm12_15, xmm0246, xmm0246, xmm1357, _masm); + montmul(xmm1357, xmm12_15, xmm8_11, xmm1357, xmm8_11, _masm); + barrettReduce(_masm); + + // level 5 + load4regs(xmm8_11, zetas, 1280, _masm); + sub_add(xmm12_15, xmm0145, xmm0145, xmm2367, _masm); + montmul(xmm2367, xmm12_15, xmm8_11, xmm2367, xmm8_11, _masm); + + // level 6 + load4regs(xmm8_11, zetas, 1536, _masm); + sub_add(xmm12_15, xmm0_3, xmm0_3, xmm4_7, _masm); + montmul(xmm4_7, xmm12_15, xmm8_11, xmm4_7, xmm8_11, _masm); + + montmul(xmm8_11, xmm29_29, xmm0_3, xmm8_11, xmm0_3, _masm); + montmul(xmm12_15, xmm29_29, xmm4_7, xmm12_15, xmm4_7, _masm); + + store4regs(coeffs, 0, xmm8_11, _masm); + store4regs(coeffs, 256, xmm12_15, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber multiply polynomials in the NTT domain. +// +// result (short[256]) = c_rarg0 +// ntta (short[256]) = c_rarg1 +// nttb (short[256]) = c_rarg2 +// zetas (short[128]) = c_rarg3 +address generate_kyberNttMult_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = kyberNttMult_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register ntta = c_rarg1; + const Register nttb = c_rarg2; + const Register zetas = c_rarg3; + + const Register perms = r11; + const Register loopCnt = r12; + + __ push(r12); + __ movl(loopCnt, 2); + + Label Loop; + + __ lea(perms, ExternalAddress(kyberAvx512_nttMultPermsAddr())); + + + load4regs(xmm26_29, perms, 0, _masm); + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qInvModROffset)), + Assembler::AVX_512bit, scratch); // q^-1 mod montR + __ vpbroadcastq(xmm30, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + __ vpbroadcastq(xmm23, + ExternalAddress(kyberAvx512ConstsAddr(montRSquareModqOffset)), + Assembler::AVX_512bit, scratch); // montR^2 mod q + + __ BIND(Loop); + + __ evmovdquw(xmm1, Address(ntta, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm8, Address(ntta, 64), Assembler::AVX_512bit); + __ evmovdquw(xmm3, Address(ntta, 128), Assembler::AVX_512bit); + __ evmovdquw(xmm9, Address(ntta, 192), Assembler::AVX_512bit); + + __ evmovdquw(xmm5, Address(nttb, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm10, Address(nttb, 64), Assembler::AVX_512bit); + __ evmovdquw(xmm7, Address(nttb, 128), Assembler::AVX_512bit); + __ evmovdquw(xmm11, Address(nttb, 192), Assembler::AVX_512bit); + + __ evmovdquw(xmm0, xmm26, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm26, Assembler::AVX_512bit); + __ evmovdquw(xmm4, xmm26, Assembler::AVX_512bit); + __ evmovdquw(xmm6, xmm26, Assembler::AVX_512bit); + + __ evpermi2w(xmm0, xmm1, xmm8, Assembler::AVX_512bit); + __ evpermt2w(xmm1, xmm27, xmm8, Assembler::AVX_512bit); + __ evpermi2w(xmm2, xmm3, xmm9, Assembler::AVX_512bit); + __ evpermt2w(xmm3, xmm27, xmm9, Assembler::AVX_512bit); + + __ evpermi2w(xmm4, xmm5, xmm10, Assembler::AVX_512bit); + __ evpermt2w(xmm5, xmm27, xmm10, Assembler::AVX_512bit); + __ evpermi2w(xmm6, xmm7, xmm11, Assembler::AVX_512bit); + __ evpermt2w(xmm7, xmm27, xmm11, Assembler::AVX_512bit); + + __ evmovdquw(xmm24, Address(zetas, 0), Assembler::AVX_512bit); + __ evmovdquw(xmm25, Address(zetas, 64), Assembler::AVX_512bit); + + montmul(xmm16_19, xmm1001, xmm5454, xmm16_19, xmm12_15, _masm); + + montmul(xmm0145, xmm3223, xmm7676, xmm0145, xmm12_15, _masm); + + __ evpmullw(xmm2, k0, xmm16, xmm24, false, Assembler::AVX_512bit); + __ evpmullw(xmm3, k0, xmm0, xmm25, false, Assembler::AVX_512bit); + __ evpmulhw(xmm12, k0, xmm16, xmm24, false, Assembler::AVX_512bit); + __ evpmulhw(xmm13, k0, xmm0, xmm25, false, Assembler::AVX_512bit); + + __ evpmullw(xmm2, k0, xmm2, xmm31, false, Assembler::AVX_512bit); + __ evpmullw(xmm3, k0, xmm3, xmm31, false, Assembler::AVX_512bit); + __ evpmulhw(xmm2, k0, xmm30, xmm2, false, Assembler::AVX_512bit); + __ evpmulhw(xmm3, k0, xmm30, xmm3, false, Assembler::AVX_512bit); + + __ evpsubw(xmm2, k0, xmm12, xmm2, false, Assembler::AVX_512bit); + __ evpsubw(xmm3, k0, xmm13, xmm3, false, Assembler::AVX_512bit); + + __ evpaddw(xmm0, k0, xmm2, xmm17, false, Assembler::AVX_512bit); + __ evpaddw(xmm8, k0, xmm3, xmm1, false, Assembler::AVX_512bit); + __ evpaddw(xmm2, k0, xmm18, xmm19, false, Assembler::AVX_512bit); + __ evpaddw(xmm9, k0, xmm4, xmm5, false, Assembler::AVX_512bit); + + montmul(xmm1357, xmm0829, xmm23_23, xmm1357, xmm0829, _masm); + + __ evmovdquw(xmm0, xmm28, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm28, Assembler::AVX_512bit); + __ evpermi2w(xmm0, xmm1, xmm5, Assembler::AVX_512bit); + __ evpermt2w(xmm1, xmm29, xmm5, Assembler::AVX_512bit); + __ evpermi2w(xmm2, xmm3, xmm7, Assembler::AVX_512bit); + __ evpermt2w(xmm3, xmm29, xmm7, Assembler::AVX_512bit); + + store4regs(result, 0, xmm0_3, _masm); + + __ addptr(ntta, 256); + __ addptr(nttb, 256); + __ addptr(result, 256); + __ addptr(zetas, 128); + __ subl(loopCnt, 1); + __ jcc(Assembler::greater, Loop); + + __ pop(r12); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber add 2 polynomials. +// +// result (short[256]) = c_rarg0 +// a (short[256]) = c_rarg1 +// b (short[256]) = c_rarg2 +address generate_kyberAddPoly_2_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = kyberAddPoly_2_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register a = c_rarg1; + const Register b = c_rarg2; + + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + for (int i = 0; i < 8; i++) { + __ evmovdquw(xmm(i), Address(a, 64 * i), Assembler::AVX_512bit); + __ evmovdquw(xmm(i + 8), Address(b, 64 * i), Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm(i + 8), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm31, false, Assembler::AVX_512bit); + } + + store4regs(result, 0, xmm0_3, _masm); + store4regs(result, 256, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber add 3 polynomials. +// +// result (short[256]) = c_rarg0 +// a (short[256]) = c_rarg1 +// b (short[256]) = c_rarg2 +// c (short[256]) = c_rarg3 +address generate_kyberAddPoly_3_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = kyberAddPoly_3_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + const Register result = c_rarg0; + const Register a = c_rarg1; + const Register b = c_rarg2; + const Register c = c_rarg3; + + __ vpbroadcastq(xmm31, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + for (int i = 0; i < 8; i++) { + __ evmovdquw(xmm(i), Address(a, 64 * i), Assembler::AVX_512bit); + __ evmovdquw(xmm(i + 8), Address(b, 64 * i), Assembler::AVX_512bit); + __ evmovdquw(xmm(i + 16), Address(c, 64 * i), Assembler::AVX_512bit); + } + + __ evpaddw(xmm31, k0, xmm31, xmm31, false, Assembler::AVX_512bit); + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm(i + 8), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm(i + 16), false, Assembler::AVX_512bit); + } + + for (int i = 0; i < 8; i++) { + __ evpaddw(xmm(i), k0, xmm(i), xmm31, false, Assembler::AVX_512bit); + } + + store4regs(result, 0, xmm0_3, _masm); + store4regs(result, 256, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +// Kyber parse XOF output to polynomial coefficient candidates. +// +// condensed (byte[168]) = c_rarg0 +// condensedOffs (int) = c_rarg1 +// parsed (short[112]) = c_rarg2 +// parsedLength (int) = c_rarg3 +address generate_kyber12To16_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = kyber12To16_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + const Register condensed = c_rarg0; + const Register condensedOffs = c_rarg1; + const Register parsed = c_rarg2; + const Register parsedLength = c_rarg3; + + const Register perms = r11; + + Label Loop; + + __ addptr(condensed, condensedOffs); + + __ lea(perms, ExternalAddress(kyberAvx512_12To16PermsAddr())); + + load4regs(xmm24_27, perms, 0, _masm); + load4regs(xmm28_31, perms, 256, _masm); + __ vpbroadcastq(xmm23, + ExternalAddress(kyberAvx512ConstsAddr(f00Offset)), + Assembler::AVX_512bit, scratch); // 0xF00 + + __ BIND(Loop); + __ evmovdqub(xmm0, Address(condensed, 0),Assembler::AVX_256bit); + __ evmovdqub(xmm1, Address(condensed, 32),Assembler::AVX_256bit); + __ evmovdqub(xmm2, Address(condensed, 64),Assembler::AVX_256bit); + __ evmovdqub(xmm8, Address(condensed, 96),Assembler::AVX_256bit); + __ evmovdqub(xmm9, Address(condensed, 128),Assembler::AVX_256bit); + __ evmovdqub(xmm10, Address(condensed, 160),Assembler::AVX_256bit); + __ vpmovzxbw(xmm0, xmm0, Assembler::AVX_512bit); + __ vpmovzxbw(xmm1, xmm1, Assembler::AVX_512bit); + __ vpmovzxbw(xmm2, xmm2, Assembler::AVX_512bit); + __ vpmovzxbw(xmm8, xmm8, Assembler::AVX_512bit); + __ vpmovzxbw(xmm9, xmm9, Assembler::AVX_512bit); + __ vpmovzxbw(xmm10, xmm10, Assembler::AVX_512bit); + __ evmovdquw(xmm3, xmm24, Assembler::AVX_512bit); + __ evmovdquw(xmm4, xmm25, Assembler::AVX_512bit); + __ evmovdquw(xmm5, xmm26, Assembler::AVX_512bit); + __ evmovdquw(xmm11, xmm24, Assembler::AVX_512bit); + __ evmovdquw(xmm12, xmm25, Assembler::AVX_512bit); + __ evmovdquw(xmm13, xmm26, Assembler::AVX_512bit); + __ evpermi2w(xmm3, xmm0, xmm1, Assembler::AVX_512bit); + __ evpermi2w(xmm4, xmm0, xmm1, Assembler::AVX_512bit); + __ evpermi2w(xmm5, xmm0, xmm1, Assembler::AVX_512bit); + __ evpermi2w(xmm11, xmm8, xmm9, Assembler::AVX_512bit); + __ evpermi2w(xmm12, xmm8, xmm9, Assembler::AVX_512bit); + __ evpermi2w(xmm13, xmm8, xmm9, Assembler::AVX_512bit); + __ evpermt2w(xmm3, xmm27, xmm2, Assembler::AVX_512bit); + __ evpermt2w(xmm4, xmm28, xmm2, Assembler::AVX_512bit); + __ evpermt2w(xmm5, xmm29, xmm2, Assembler::AVX_512bit); + __ evpermt2w(xmm11, xmm27, xmm10, Assembler::AVX_512bit); + __ evpermt2w(xmm12, xmm28, xmm10, Assembler::AVX_512bit); + __ evpermt2w(xmm13, xmm29, xmm10, Assembler::AVX_512bit); + + __ evpsraw(xmm2, k0, xmm4, 4, false, Assembler::AVX_512bit); + __ evpsllw(xmm0, k0, xmm4, 8, false, Assembler::AVX_512bit); + __ evpsllw(xmm1, k0, xmm5, 4, false, Assembler::AVX_512bit); + __ evpsllw(xmm8, k0, xmm12, 8, false, Assembler::AVX_512bit); + __ evpsraw(xmm10, k0, xmm12, 4, false, Assembler::AVX_512bit); + __ evpsllw(xmm9, k0, xmm13, 4, false, Assembler::AVX_512bit); + __ evpandq(xmm0, k0, xmm0, xmm23, false, Assembler::AVX_512bit); + __ evpandq(xmm8, k0, xmm8, xmm23, false, Assembler::AVX_512bit); + __ evpaddw(xmm1, k0, xmm1, xmm2, false, Assembler::AVX_512bit); + __ evpaddw(xmm0, k0, xmm0, xmm3, false, Assembler::AVX_512bit); + __ evmovdquw(xmm2, xmm30, Assembler::AVX_512bit); + __ evpaddw(xmm9, k0, xmm9, xmm10, false, Assembler::AVX_512bit); + __ evpaddw(xmm8, k0, xmm8, xmm11, false, Assembler::AVX_512bit); + __ evmovdquw(xmm10, xmm30, Assembler::AVX_512bit); + __ evpermi2w(xmm2, xmm0, xmm1, Assembler::AVX_512bit); + __ evpermt2w(xmm0, xmm31, xmm1, Assembler::AVX_512bit); + __ evpermi2w(xmm10, xmm8, xmm9, Assembler::AVX_512bit); + __ evpermt2w(xmm8, xmm31, xmm9, Assembler::AVX_512bit); + + store4regs(parsed, 0, xmm2_0_10_8, _masm); + + __ addptr(condensed, 192); + __ addptr(parsed, 256); + __ subl(parsedLength, 128); + __ jcc(Assembler::greater, Loop); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + + +// Kyber barrett reduce function. +// +// coeffs (short[256]) = c_rarg0 +address generate_kyberBarrettReduce_avx512(StubGenerator *stubgen, + MacroAssembler *_masm) { + + __ align(CodeEntryAlignment); + StubGenStubId stub_id = kyberBarrettReduce_id; + StubCodeMark mark(stubgen, stub_id); + address start = __ pc(); + __ enter(); + + const Register coeffs = c_rarg0; + + __ vpbroadcastq(xmm16, + ExternalAddress(kyberAvx512ConstsAddr(barretMultiplierOffset)), + Assembler::AVX_512bit, scratch); // Barrett multiplier + __ vpbroadcastq(xmm17, + ExternalAddress(kyberAvx512ConstsAddr(qOffset)), + Assembler::AVX_512bit, scratch); // q + + load4regs(xmm0_3, coeffs, 0, _masm); + load4regs(xmm4_7, coeffs, 256, _masm); + + barrettReduce(_masm); + + store4regs(coeffs, 0, xmm0_3, _masm); + store4regs(coeffs, 256, xmm4_7, _masm); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ mov64(rax, 0); // return 0 + __ ret(0); + + return start; +} + +void StubGenerator::generate_kyber_stubs() { + // Generate Kyber intrinsics code + if (UseKyberIntrinsics) { + if (VM_Version::supports_evex()) { + StubRoutines::_kyberNtt = generate_kyberNtt_avx512(this, _masm); + StubRoutines::_kyberInverseNtt = generate_kyberInverseNtt_avx512(this, _masm); + StubRoutines::_kyberNttMult = generate_kyberNttMult_avx512(this, _masm); + StubRoutines::_kyberAddPoly_2 = generate_kyberAddPoly_2_avx512(this, _masm); + StubRoutines::_kyberAddPoly_3 = generate_kyberAddPoly_3_avx512(this, _masm); + StubRoutines::_kyber12To16 = generate_kyber12To16_avx512(this, _masm); + StubRoutines::_kyberBarrettReduce = generate_kyberBarrettReduce_avx512(this, _masm); + } + } +} diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp index d13809bfcd9..52ce2731b1f 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024, Intel Corporation. All rights reserved. +* Copyright (c) 2024, 2025, Intel Corporation. All rights reserved. * Intel Math Library (LIBM) Source Code * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -46,7 +46,7 @@ // for |x| in [23/64,3*2^7) // e^{-2*|x|}=2^{-k-f}*2^{-r} ~ 2^{-k}*(Tn+Dn)*(1+p)=(T0+D0)*(1+p) // -// For |x| in [2^{-4},2^5): +// For |x| in [2^{-4},22): // 2^{-r}-1 ~ p=c1*r+c2*r^2+..+c5*r^5 // Let R=1/(1+T0+p*T0), truncated to 35 significant bits // R=1/(1+T0+D0+p*(T0+D0))*(1+eps), |eps|<2^{-33} @@ -66,11 +66,11 @@ // // For |x|<2^{-64}: x is returned // -// For |x|>=2^32: return +/-1 +// For |x|>=22: return +/-1 // // Special cases: // tanh(NaN) = quiet NaN, and raise invalid exception -// tanh(INF) = that INF +// tanh(+/-INF) = +/-1 // tanh(+/-0) = +/-0 // /******************************************************************************/ @@ -324,6 +324,12 @@ address StubGenerator::generate_libmTanh() { __ enter(); // required for proper stackwalking of RuntimeStub frame __ bind(B1_2); + __ pextrw(rcx, xmm0, 3); + __ movl(rdx, 32768); + __ andl(rdx, rcx); + __ andl(rcx, 32767); + __ cmpl(rcx, 16438); + __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_2_0_1); // Branch only if |x| >= 22 __ movsd(xmm3, ExternalAddress(HALFMASK), r11 /*rscratch*/); __ xorpd(xmm4, xmm4); __ movsd(xmm1, ExternalAddress(L2E), r11 /*rscratch*/); @@ -331,16 +337,12 @@ address StubGenerator::generate_libmTanh() { __ movl(rax, 32768); __ pinsrw(xmm4, rax, 3); __ movsd(xmm6, ExternalAddress(Shifter), r11 /*rscratch*/); - __ pextrw(rcx, xmm0, 3); __ andpd(xmm3, xmm0); __ andnpd(xmm4, xmm0); __ pshufd(xmm5, xmm4, 68); - __ movl(rdx, 32768); - __ andl(rdx, rcx); - __ andl(rcx, 32767); __ subl(rcx, 16304); - __ cmpl(rcx, 144); - __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_1); + __ cmpl(rcx, 134); + __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_1); // Branch only if |x| is not in [2^{-4},22) __ subsd(xmm4, xmm3); __ mulsd(xmm3, xmm1); __ mulsd(xmm2, xmm5); @@ -427,8 +429,8 @@ address StubGenerator::generate_libmTanh() { __ bind(L_2TAG_PACKET_0_0_1); __ addl(rcx, 960); - __ cmpl(rcx, 1104); - __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_1_0_1); + __ cmpl(rcx, 1094); + __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_1_0_1); // Branch only if |x| not in [2^{-64}, 2^{-4}) __ movdqu(xmm2, ExternalAddress(pv), r11 /*rscratch*/); __ pshufd(xmm1, xmm0, 68); __ movdqu(xmm3, ExternalAddress(pv + 16), r11 /*rscratch*/); @@ -449,11 +451,8 @@ address StubGenerator::generate_libmTanh() { __ jmp(B1_4); __ bind(L_2TAG_PACKET_1_0_1); - __ addl(rcx, 15344); - __ cmpl(rcx, 16448); - __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_2_0_1); __ cmpl(rcx, 16); - __ jcc(Assembler::below, L_2TAG_PACKET_3_0_1); + __ jcc(Assembler::below, L_2TAG_PACKET_3_0_1); // Branch only if |x| is denormalized __ xorpd(xmm2, xmm2); __ movl(rax, 17392); __ pinsrw(xmm2, rax, 3); @@ -468,7 +467,7 @@ address StubGenerator::generate_libmTanh() { __ bind(L_2TAG_PACKET_2_0_1); __ cmpl(rcx, 32752); - __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_4_0_1); + __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_4_0_1); // Branch only if |x| is INF or NaN __ xorpd(xmm2, xmm2); __ movl(rcx, 15344); __ pinsrw(xmm2, rcx, 3); @@ -489,7 +488,7 @@ address StubGenerator::generate_libmTanh() { __ movdl(rcx, xmm2); __ orl(rcx, rax); __ cmpl(rcx, 0); - __ jcc(Assembler::equal, L_2TAG_PACKET_5_0_1); + __ jcc(Assembler::equal, L_2TAG_PACKET_5_0_1); // Branch only if |x| is not NaN __ addsd(xmm0, xmm0); __ bind(B1_4); diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index 45e30a8b4fb..bd061d45fbd 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -1147,6 +1147,30 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { __ bind(L); } +#if INCLUDE_JFR + __ enter_jfr_critical_section(); + + // This poll test is to uphold the invariant that a JFR sampled frame + // must not return to its caller without a prior safepoint poll check. + // The earlier poll check in this routine is insufficient for this purpose + // because the thread has transitioned back to Java. + + Label slow_path; + Label fast_path; + __ safepoint_poll(slow_path, true /* at_return */, false /* in_nmethod */); + __ jmp(fast_path); + __ bind(slow_path); + __ push(dtos); + __ push(ltos); + __ set_last_Java_frame(noreg, rbp, (address)__ pc(), rscratch1); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), r15_thread); + __ reset_last_Java_frame(true); + __ pop(ltos); + __ pop(dtos); + __ bind(fast_path); + +#endif // INCLUDE_JFR + // jvmti support // Note: This must happen _after_ handling/throwing any exceptions since // the exception handler code notifies the runtime of method exits @@ -1169,8 +1193,12 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp __ leave(); // remove frame anchor + + JFR_ONLY(__ leave_jfr_critical_section();) + __ pop(rdi); // get return address __ mov(rsp, t); // set sp to sender sp + __ jmp(rdi); if (inc_counter) { @@ -1413,6 +1441,7 @@ void TemplateInterpreterGenerator::generate_throw_exception() { Interpreter::_remove_activation_preserving_args_entry = __ pc(); __ empty_expression_stack(); + __ restore_bcp(); // We could have returned from deoptimizing this frame, so restore rbcp. // Set the popframe_processing bit in pending_popframe_condition // indicating that we are currently handling popframe, so that // call_VMs that may happen later do not trigger new popframe diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp index 6be702f2699..9ea4aeeccfa 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp @@ -468,6 +468,10 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M assert(StubRoutines::dtanh() != nullptr, "not initialized"); __ movdbl(xmm0, Address(rsp, wordSize)); __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dtanh()))); + } else if (kind == Interpreter::java_lang_math_cbrt) { + assert(StubRoutines::dcbrt() != nullptr, "not initialized"); + __ movdbl(xmm0, Address(rsp, wordSize)); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dcbrt()))); } else if (kind == Interpreter::java_lang_math_abs) { assert(StubRoutines::x86::double_sign_mask() != nullptr, "not initialized"); __ movdbl(xmm0, Address(rsp, wordSize)); diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 43da80f4082..82ca18d8a1f 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -1687,8 +1687,7 @@ void TemplateTable::float_cmp(bool is_float, int unordered_result) { void TemplateTable::branch(bool is_jsr, bool is_wide) { __ get_method(rcx); // rcx holds method - __ profile_taken_branch(rax, rbx); // rax holds updated MDP, rbx - // holds bumped taken count + __ profile_taken_branch(rax); // rax holds updated MDP const ByteSize be_offset = MethodCounters::backedge_counter_offset() + InvocationCounter::counter_offset(); @@ -1739,7 +1738,6 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { if (UseLoopCounter) { // increment backedge counter for backward branches // rax: MDO - // rbx: MDO bumped taken-count // rcx: method // rdx: target offset // r13: target bcp @@ -1825,6 +1823,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // it will be preserved in rbx. __ mov(rbx, rax); + JFR_ONLY(__ enter_jfr_critical_section();) + call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin)); // rax is OSR buffer, move it to expected parameter location @@ -1839,14 +1839,12 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // pop the interpreter frame __ movptr(sender_sp, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp __ leave(); // remove frame anchor + JFR_ONLY(__ leave_jfr_critical_section();) __ pop(retaddr); // get return address - __ mov(rsp, sender_sp); // set sp to sender sp + __ mov(rsp, sender_sp); // set sp to sender sp // Ensure compiled code always sees stack at proper alignment __ andptr(rsp, -(StackAlignmentInBytes)); - // unlike x86 we need no specialized return from compiled code - // to the interpreter or the call stub. - // push the return address __ push(retaddr); diff --git a/src/hotspot/cpu/x86/vmStructs_x86.hpp b/src/hotspot/cpu/x86/vmStructs_x86.hpp index d894d8b09a7..b8089a6413e 100644 --- a/src/hotspot/cpu/x86/vmStructs_x86.hpp +++ b/src/hotspot/cpu/x86/vmStructs_x86.hpp @@ -29,15 +29,20 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ - volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \ + static_field(VM_Version, _features, VM_Version::VM_Features) \ + nonstatic_field(VM_Version::VM_Features, _features_bitmap[0], uint64_t) \ + static_field(VM_Version::VM_Features, _features_bitmap_size, int) #define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type) \ + declare_toplevel_type(VM_Version::VM_Features) #define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) \ - LP64_ONLY(declare_constant(frame::arg_reg_save_area_bytes)) \ - declare_constant(frame::interpreter_frame_sender_sp_offset) \ - declare_constant(frame::interpreter_frame_last_sp_offset) + declare_constant(frame::arg_reg_save_area_bytes) \ + declare_constant(frame::interpreter_frame_sender_sp_offset) \ + declare_constant(frame::interpreter_frame_last_sp_offset) \ + declare_constant(frame::entry_frame_call_wrapper_offset) #define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant) diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 32e6e33d133..152866e65f3 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -63,6 +63,11 @@ address VM_Version::_cpuinfo_cont_addr_apx = nullptr; static BufferBlob* stub_blob; static const int stub_size = 2000; +int VM_Version::VM_Features::_features_bitmap_size = sizeof(VM_Version::VM_Features::_features_bitmap) / BytesPerLong; + +VM_Version::VM_Features VM_Version::_features; +VM_Version::VM_Features VM_Version::_cpu_features; + extern "C" { typedef void (*get_cpu_info_stub_t)(void*); typedef void (*detect_virt_stub_t)(uint32_t, uint32_t*); @@ -72,8 +77,6 @@ static get_cpu_info_stub_t get_cpu_info_stub = nullptr; static detect_virt_stub_t detect_virt_stub = nullptr; static clear_apx_test_state_t clear_apx_test_state_stub = nullptr; -#ifdef _LP64 - bool VM_Version::supports_clflush() { // clflush should always be available on x86_64 // if not we are in real trouble because we rely on it @@ -84,10 +87,9 @@ bool VM_Version::supports_clflush() { // up. Assembler::flush calls this routine to check that clflush // is allowed. So, we give the caller a free pass if Universe init // is still in progress. - assert ((!Universe::is_fully_initialized() || (_features & CPU_FLUSH) != 0), "clflush should be available"); + assert ((!Universe::is_fully_initialized() || _features.supports_feature(CPU_FLUSH)), "clflush should be available"); return true; } -#endif #define CPUID_STANDARD_FN 0x0 #define CPUID_STANDARD_FN_1 0x1 @@ -107,7 +109,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator { VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {} -#if defined(_LP64) address clear_apx_test_state() { # define __ _masm-> address start = __ pc(); @@ -126,7 +127,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ ret(0); return start; } -#endif address generate_get_cpu_info() { // Flags to test CPU type. @@ -138,7 +138,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { const uint32_t CPU_FAMILY_486 = (4 << CPU_FAMILY_SHIFT); bool use_evex = FLAG_IS_DEFAULT(UseAVX) || (UseAVX > 2); - Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4; + Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4, std_cpuid24; Label sef_cpuid, sefsl1_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7; Label ext_cpuid8, done, wrapup, vector_save_restore, apx_save_restore_warning; Label legacy_setup, save_restore_except, legacy_save_restore, start_simd_check; @@ -151,14 +151,10 @@ class VM_Version_StubGenerator: public StubCodeGenerator { // // void get_cpu_info(VM_Version::CpuidInfo* cpuid_info); // - // LP64: rcx and rdx are first and second argument registers on windows + // 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 @@ -341,6 +337,17 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movl(Address(rsi, 0), rax); __ movl(Address(rsi, 4), rdx); + // + // cpuid(0x24) Converged Vector ISA Main Leaf (EAX = 24H, ECX = 0). + // + __ bind(std_cpuid24); + __ movl(rax, 0x24); + __ movl(rcx, 0); + __ cpuid(); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::std_cpuid24_offset()))); + __ movl(Address(rsi, 0), rax); + __ movl(Address(rsi, 4), rbx); + // // Extended cpuid(0x80000000) // @@ -418,7 +425,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movl(Address(rsi, 8), rcx); __ movl(Address(rsi,12), rdx); -#if defined(_LP64) // // Check if OS has enabled XGETBV instruction to access XCR0 // (OSXSAVE feature flag) and CPU supports APX @@ -428,13 +434,11 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ lea(rsi, Address(rbp, in_bytes(VM_Version::sefsl1_cpuid7_offset()))); __ movl(rax, 0x200000); __ andl(rax, Address(rsi, 4)); - __ cmpl(rax, 0x200000); - __ jcc(Assembler::notEqual, vector_save_restore); + __ jcc(Assembler::equal, vector_save_restore); // check _cpuid_info.xem_xcr0_eax.bits.apx_f __ movl(rax, 0x80000); __ andl(rax, Address(rbp, in_bytes(VM_Version::xem_xcr0_offset()))); // xcr0 bits apx_f - __ cmpl(rax, 0x80000); - __ jcc(Assembler::notEqual, vector_save_restore); + __ jcc(Assembler::equal, vector_save_restore); #ifndef PRODUCT bool save_apx = UseAPX; @@ -453,7 +457,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movq(Address(rsi, 8), r31); UseAPX = save_apx; -#endif #endif __ bind(vector_save_restore); // @@ -488,11 +491,15 @@ class VM_Version_StubGenerator: public StubCodeGenerator { // If UseAVX is uninitialized or is set by the user to include EVEX if (use_evex) { // check _cpuid_info.sef_cpuid7_ebx.bits.avx512f + // OR check _cpuid_info.sefsl1_cpuid7_edx.bits.avx10 __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset()))); __ movl(rax, 0x10000); - __ andl(rax, Address(rsi, 4)); // xcr0 bits sse | ymm - __ cmpl(rax, 0x10000); - __ jccb(Assembler::notEqual, legacy_setup); // jump if EVEX is not supported + __ andl(rax, Address(rsi, 4)); + __ lea(rsi, Address(rbp, in_bytes(VM_Version::sefsl1_cpuid7_offset()))); + __ movl(rbx, 0x80000); + __ andl(rbx, Address(rsi, 4)); + __ orl(rax, rbx); + __ jccb(Assembler::equal, legacy_setup); // jump if EVEX is not supported // check _cpuid_info.xem_xcr0_eax.bits.opmask // check _cpuid_info.xem_xcr0_eax.bits.zmm512 // check _cpuid_info.xem_xcr0_eax.bits.zmm32 @@ -527,10 +534,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ movdl(xmm0, rcx); __ vpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit); __ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit); -#ifdef _LP64 __ evmovdqul(xmm8, xmm0, Assembler::AVX_512bit); __ evmovdqul(xmm31, xmm0, Assembler::AVX_512bit); -#endif VM_Version::clean_cpuFeatures(); __ jmp(save_restore_except); } @@ -556,10 +561,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ pshufd(xmm0, xmm0, 0x00); __ vinsertf128_high(xmm0, xmm0); __ vmovdqu(xmm7, xmm0); -#ifdef _LP64 __ vmovdqu(xmm8, xmm0); __ vmovdqu(xmm15, xmm0); -#endif VM_Version::clean_cpuFeatures(); __ bind(save_restore_except); @@ -577,8 +580,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ lea(rsi, Address(rbp, in_bytes(VM_Version::sef_cpuid7_offset()))); __ movl(rax, 0x10000); __ andl(rax, Address(rsi, 4)); - __ cmpl(rax, 0x10000); - __ jcc(Assembler::notEqual, legacy_save_restore); + __ jcc(Assembler::equal, legacy_save_restore); // check _cpuid_info.xem_xcr0_eax.bits.opmask // check _cpuid_info.xem_xcr0_eax.bits.zmm512 // check _cpuid_info.xem_xcr0_eax.bits.zmm32 @@ -600,10 +602,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ lea(rsi, Address(rbp, in_bytes(VM_Version::zmm_save_offset()))); __ evmovdqul(Address(rsi, 0), xmm0, Assembler::AVX_512bit); __ evmovdqul(Address(rsi, 64), xmm7, Assembler::AVX_512bit); -#ifdef _LP64 __ evmovdqul(Address(rsi, 128), xmm8, Assembler::AVX_512bit); __ evmovdqul(Address(rsi, 192), xmm31, Assembler::AVX_512bit); -#endif #ifdef _WINDOWS __ evmovdqul(xmm31, Address(rsp, 0), Assembler::AVX_512bit); @@ -628,10 +628,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ lea(rsi, Address(rbp, in_bytes(VM_Version::ymm_save_offset()))); __ vmovdqu(Address(rsi, 0), xmm0); __ vmovdqu(Address(rsi, 32), xmm7); -#ifdef _LP64 __ vmovdqu(Address(rsi, 64), xmm8); __ vmovdqu(Address(rsi, 96), xmm15); -#endif #ifdef _WINDOWS __ vmovdqu(xmm15, Address(rsp, 0)); @@ -687,13 +685,8 @@ class VM_Version_StubGenerator: public StubCodeGenerator { __ push(rbx); __ push(rsi); // for Windows -#ifdef _LP64 __ mov(rax, c_rarg0); // CPUID leaf __ mov(rsi, c_rarg1); // register array address (eax, ebx, ecx, edx) -#else - __ movptr(rax, Address(rsp, 16)); // CPUID leaf - __ movptr(rsi, Address(rsp, 20)); // register array address -#endif __ cpuid(); @@ -734,14 +727,10 @@ class VM_Version_StubGenerator: public StubCodeGenerator { // // void getCPUIDBrandString(VM_Version::CpuidInfo* cpuid_info); // - // LP64: rcx and rdx are first and second argument registers on windows + // 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 @@ -863,7 +852,6 @@ void VM_Version::get_processor_features() { _cpu = 4; // 486 by default _model = 0; _stepping = 0; - _features = 0; _logical_processors_per_package = 1; // i486 internal cache is both I&D and has a 16-byte line size _L1_data_cache_line_size = 16; @@ -879,7 +867,7 @@ void VM_Version::get_processor_features() { if (cpu_family() > 4) { // it supports CPUID _features = _cpuid_info.feature_flags(); // These can be changed by VM settings - _cpu_features = _features; // Preserve features + _cpu_features = _features; // Preserve features // Logical processors are only available on P4s and above, // and only if hyperthreading is available. _logical_processors_per_package = logical_processor_count(); @@ -889,19 +877,16 @@ void VM_Version::get_processor_features() { // xchg and xadd instructions _supports_atomic_getset4 = true; _supports_atomic_getadd4 = true; - LP64_ONLY(_supports_atomic_getset8 = true); - LP64_ONLY(_supports_atomic_getadd8 = true); + _supports_atomic_getset8 = true; + _supports_atomic_getadd8 = true; -#ifdef _LP64 // OS should support SSE for x64 and hardware should support at least SSE2. if (!VM_Version::supports_sse2()) { vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported"); } // in 64 bit the use of SSE2 is the minimum if (UseSSE < 2) UseSSE = 2; -#endif -#ifdef AMD64 // flush_icache_stub have to be generated first. // That is why Icache line size is hard coded in ICache class, // see icache_x86.hpp. It is also the reason why we can't use @@ -913,9 +898,7 @@ void VM_Version::get_processor_features() { guarantee(_cpuid_info.std_cpuid1_edx.bits.clflush != 0, "clflush is not supported"); // clflush_size is size in quadwords (8 bytes). guarantee(_cpuid_info.std_cpuid1_ebx.bits.clflush_size == 8, "such clflush size is not supported"); -#endif -#ifdef _LP64 // assigning this field effectively enables Unsafe.writebackMemory() // by initing UnsafeConstant.DATA_CACHE_LINE_FLUSH_SIZE to non-zero // that is only implemented on x86_64 and only if the OS plays ball @@ -924,31 +907,30 @@ void VM_Version::get_processor_features() { // let if default to zero thereby disabling writeback _data_cache_line_flush_size = _cpuid_info.std_cpuid1_ebx.bits.clflush_size * 8; } -#endif // Check if processor has Intel Ecore - if (FLAG_IS_DEFAULT(EnableX86ECoreOpts) && is_intel() && cpu_family() == 6 && + if (FLAG_IS_DEFAULT(EnableX86ECoreOpts) && is_intel() && is_intel_server_family() && (_model == 0x97 || _model == 0xAA || _model == 0xAC || _model == 0xAF || _model == 0xCC || _model == 0xDD)) { FLAG_SET_DEFAULT(EnableX86ECoreOpts, true); } if (UseSSE < 4) { - _features &= ~CPU_SSE4_1; - _features &= ~CPU_SSE4_2; + _features.clear_feature(CPU_SSE4_1); + _features.clear_feature(CPU_SSE4_2); } if (UseSSE < 3) { - _features &= ~CPU_SSE3; - _features &= ~CPU_SSSE3; - _features &= ~CPU_SSE4A; + _features.clear_feature(CPU_SSE3); + _features.clear_feature(CPU_SSSE3); + _features.clear_feature(CPU_SSE4A); } if (UseSSE < 2) - _features &= ~CPU_SSE2; + _features.clear_feature(CPU_SSE2); if (UseSSE < 1) - _features &= ~CPU_SSE; + _features.clear_feature(CPU_SSE); //since AVX instructions is slower than SSE in some ZX cpus, force USEAVX=0. if (is_zx() && ((cpu_family() == 6) || (cpu_family() == 7))) { @@ -1014,21 +996,25 @@ void VM_Version::get_processor_features() { } if (UseAVX < 3) { - _features &= ~CPU_AVX512F; - _features &= ~CPU_AVX512DQ; - _features &= ~CPU_AVX512CD; - _features &= ~CPU_AVX512BW; - _features &= ~CPU_AVX512VL; - _features &= ~CPU_AVX512_VPOPCNTDQ; - _features &= ~CPU_AVX512_VPCLMULQDQ; - _features &= ~CPU_AVX512_VAES; - _features &= ~CPU_AVX512_VNNI; - _features &= ~CPU_AVX512_VBMI; - _features &= ~CPU_AVX512_VBMI2; - _features &= ~CPU_AVX512_BITALG; - _features &= ~CPU_AVX512_IFMA; - _features &= ~CPU_APX_F; - _features &= ~CPU_AVX512_FP16; + _features.clear_feature(CPU_AVX512F); + _features.clear_feature(CPU_AVX512DQ); + _features.clear_feature(CPU_AVX512CD); + _features.clear_feature(CPU_AVX512BW); + _features.clear_feature(CPU_AVX512ER); + _features.clear_feature(CPU_AVX512PF); + _features.clear_feature(CPU_AVX512VL); + _features.clear_feature(CPU_AVX512_VPOPCNTDQ); + _features.clear_feature(CPU_AVX512_VPCLMULQDQ); + _features.clear_feature(CPU_AVX512_VAES); + _features.clear_feature(CPU_AVX512_VNNI); + _features.clear_feature(CPU_AVX512_VBMI); + _features.clear_feature(CPU_AVX512_VBMI2); + _features.clear_feature(CPU_AVX512_BITALG); + _features.clear_feature(CPU_AVX512_IFMA); + _features.clear_feature(CPU_APX_F); + _features.clear_feature(CPU_AVX512_FP16); + _features.clear_feature(CPU_AVX10_1); + _features.clear_feature(CPU_AVX10_2); } // Currently APX support is only enabled for targets supporting AVX512VL feature. @@ -1041,45 +1027,47 @@ void VM_Version::get_processor_features() { } if (!UseAPX) { - _features &= ~CPU_APX_F; + _features.clear_feature(CPU_APX_F); } if (UseAVX < 2) { - _features &= ~CPU_AVX2; - _features &= ~CPU_AVX_IFMA; + _features.clear_feature(CPU_AVX2); + _features.clear_feature(CPU_AVX_IFMA); } if (UseAVX < 1) { - _features &= ~CPU_AVX; - _features &= ~CPU_VZEROUPPER; - _features &= ~CPU_F16C; - _features &= ~CPU_SHA512; + _features.clear_feature(CPU_AVX); + _features.clear_feature(CPU_VZEROUPPER); + _features.clear_feature(CPU_F16C); + _features.clear_feature(CPU_SHA512); } if (logical_processors_per_package() == 1) { // HT processor could be installed on a system which doesn't support HT. - _features &= ~CPU_HT; + _features.clear_feature(CPU_HT); } if (is_intel()) { // Intel cpus specific settings if (is_knights_family()) { - _features &= ~CPU_VZEROUPPER; - _features &= ~CPU_AVX512BW; - _features &= ~CPU_AVX512VL; - _features &= ~CPU_AVX512DQ; - _features &= ~CPU_AVX512_VNNI; - _features &= ~CPU_AVX512_VAES; - _features &= ~CPU_AVX512_VPOPCNTDQ; - _features &= ~CPU_AVX512_VPCLMULQDQ; - _features &= ~CPU_AVX512_VBMI; - _features &= ~CPU_AVX512_VBMI2; - _features &= ~CPU_CLWB; - _features &= ~CPU_FLUSHOPT; - _features &= ~CPU_GFNI; - _features &= ~CPU_AVX512_BITALG; - _features &= ~CPU_AVX512_IFMA; - _features &= ~CPU_AVX_IFMA; - _features &= ~CPU_AVX512_FP16; + _features.clear_feature(CPU_VZEROUPPER); + _features.clear_feature(CPU_AVX512BW); + _features.clear_feature(CPU_AVX512VL); + _features.clear_feature(CPU_AVX512DQ); + _features.clear_feature(CPU_AVX512_VNNI); + _features.clear_feature(CPU_AVX512_VAES); + _features.clear_feature(CPU_AVX512_VPOPCNTDQ); + _features.clear_feature(CPU_AVX512_VPCLMULQDQ); + _features.clear_feature(CPU_AVX512_VBMI); + _features.clear_feature(CPU_AVX512_VBMI2); + _features.clear_feature(CPU_CLWB); + _features.clear_feature(CPU_FLUSHOPT); + _features.clear_feature(CPU_GFNI); + _features.clear_feature(CPU_AVX512_BITALG); + _features.clear_feature(CPU_AVX512_IFMA); + _features.clear_feature(CPU_AVX_IFMA); + _features.clear_feature(CPU_AVX512_FP16); + _features.clear_feature(CPU_AVX10_1); + _features.clear_feature(CPU_AVX10_2); } } @@ -1089,16 +1077,44 @@ void VM_Version::get_processor_features() { _has_intel_jcc_erratum = IntelJccErratumMitigation; } - char buf[1024]; - int res = jio_snprintf( + assert(supports_clflush(), "Always present"); + if (X86ICacheSync == -1) { + // Auto-detect, choosing the best performant one that still flushes + // the cache. We could switch to CPUID/SERIALIZE ("4"/"5") going forward. + if (supports_clwb()) { + FLAG_SET_ERGO(X86ICacheSync, 3); + } else if (supports_clflushopt()) { + FLAG_SET_ERGO(X86ICacheSync, 2); + } else { + FLAG_SET_ERGO(X86ICacheSync, 1); + } + } else { + if ((X86ICacheSync == 2) && !supports_clflushopt()) { + vm_exit_during_initialization("CPU does not support CLFLUSHOPT, unable to use X86ICacheSync=2"); + } + if ((X86ICacheSync == 3) && !supports_clwb()) { + vm_exit_during_initialization("CPU does not support CLWB, unable to use X86ICacheSync=3"); + } + if ((X86ICacheSync == 5) && !supports_serialize()) { + vm_exit_during_initialization("CPU does not support SERIALIZE, unable to use X86ICacheSync=5"); + } + } + + char buf[2048]; + size_t cpu_info_size = jio_snprintf( buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d microcode 0x%x", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, os::cpu_microcode_revision()); - assert(res > 0, "not enough temporary space allocated"); - insert_features_names(buf + res, sizeof(buf) - res, _features_names); + assert(cpu_info_size > 0, "not enough temporary space allocated"); - _features_string = os::strdup(buf); + insert_features_names(_features, buf + cpu_info_size, sizeof(buf) - cpu_info_size); + + _cpu_info_string = os::strdup(buf); + + _features_string = extract_features_string(_cpu_info_string, + strnlen(_cpu_info_string, sizeof(buf)), + cpu_info_size); // Use AES instructions if available. if (supports_aes()) { @@ -1182,7 +1198,6 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } -#ifdef _LP64 if (supports_avx2()) { if (FLAG_IS_DEFAULT(UseAdler32Intrinsics)) { UseAdler32Intrinsics = true; @@ -1193,12 +1208,6 @@ void VM_Version::get_processor_features() { } FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); } -#else - if (UseAdler32Intrinsics) { - warning("Adler32Intrinsics not available on this CPU."); - FLAG_SET_DEFAULT(UseAdler32Intrinsics, false); - } -#endif if (supports_sse4_2() && supports_clmul()) { if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) { @@ -1222,7 +1231,6 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); } -#ifdef _LP64 // ChaCha20 Intrinsics // As long as the system supports AVX as a baseline we can do a // SIMD-enabled block function. StubGenerator makes the determination @@ -1238,24 +1246,28 @@ void VM_Version::get_processor_features() { } FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); } -#else - // No support currently for ChaCha20 intrinsics on 32-bit platforms - if (UseChaCha20Intrinsics) { - warning("ChaCha20 intrinsics are not available on this CPU."); - FLAG_SET_DEFAULT(UseChaCha20Intrinsics, false); + + // Kyber Intrinsics + // Currently we only have them for AVX512 +#ifdef _LP64 + if (supports_evex() && supports_avx512bw()) { + if (FLAG_IS_DEFAULT(UseKyberIntrinsics)) { + UseKyberIntrinsics = true; + } + } else +#endif + if (UseKyberIntrinsics) { + warning("Intrinsics for ML-KEM are not available on this CPU."); + FLAG_SET_DEFAULT(UseKyberIntrinsics, false); } -#endif // _LP64 // Dilithium Intrinsics // Currently we only have them for AVX512 -#ifdef _LP64 if (supports_evex() && supports_avx512bw()) { if (FLAG_IS_DEFAULT(UseDilithiumIntrinsics)) { UseDilithiumIntrinsics = true; } - } else -#endif - if (UseDilithiumIntrinsics) { + } else if (UseDilithiumIntrinsics) { warning("Intrinsics for ML-DSA are not available on this CPU."); FLAG_SET_DEFAULT(UseDilithiumIntrinsics, false); } @@ -1284,7 +1296,7 @@ void VM_Version::get_processor_features() { UseMD5Intrinsics = true; } - if (supports_sha() LP64_ONLY(|| (supports_avx2() && supports_bmi2()))) { + if (supports_sha() || (supports_avx2() && supports_bmi2())) { if (FLAG_IS_DEFAULT(UseSHA)) { UseSHA = true; } @@ -1311,27 +1323,20 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); } -#ifdef _LP64 - // These are only supported on 64-bit if (UseSHA && supports_avx2() && (supports_bmi2() || supports_sha512())) { if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) { FLAG_SET_DEFAULT(UseSHA512Intrinsics, true); } - } else -#endif - if (UseSHA512Intrinsics) { + } else if (UseSHA512Intrinsics) { warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); } -#ifdef _LP64 if (supports_evex() && supports_avx512bw()) { if (FLAG_IS_DEFAULT(UseSHA3Intrinsics)) { UseSHA3Intrinsics = true; } - } else -#endif - if (UseSHA3Intrinsics) { + } else if (UseSHA3Intrinsics) { warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); } @@ -1353,11 +1358,7 @@ void VM_Version::get_processor_features() { max_vector_size = 64; } -#ifdef _LP64 int min_vector_size = 4; // We require MaxVectorSize to be at least 4 on 64bit -#else - int min_vector_size = 0; -#endif if (!FLAG_IS_DEFAULT(MaxVectorSize)) { if (MaxVectorSize < min_vector_size) { @@ -1381,7 +1382,7 @@ void VM_Version::get_processor_features() { if (MaxVectorSize > 0) { if (supports_avx() && PrintMiscellaneous && Verbose && TraceNewVectors) { tty->print_cr("State of YMM registers after signal handle:"); - int nreg = 2 LP64_ONLY(+2); + int nreg = 4; const char* ymm_name[4] = {"0", "7", "8", "15"}; for (int i = 0; i < nreg; i++) { tty->print("YMM%s:", ymm_name[i]); @@ -1394,31 +1395,24 @@ void VM_Version::get_processor_features() { } #endif // COMPILER2 && ASSERT -#ifdef _LP64 if ((supports_avx512ifma() && supports_avx512vlbw()) || supports_avxifma()) { if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) { FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true); } - } else -#endif - if (UsePoly1305Intrinsics) { + } else if (UsePoly1305Intrinsics) { warning("Intrinsics for Poly1305 crypto hash functions not available on this CPU."); FLAG_SET_DEFAULT(UsePoly1305Intrinsics, false); } -#ifdef _LP64 if ((supports_avx512ifma() && supports_avx512vlbw()) || supports_avxifma()) { if (FLAG_IS_DEFAULT(UseIntPolyIntrinsics)) { FLAG_SET_DEFAULT(UseIntPolyIntrinsics, true); } - } else -#endif - if (UseIntPolyIntrinsics) { + } else if (UseIntPolyIntrinsics) { warning("Intrinsics for Polynomial crypto functions not available on this CPU."); FLAG_SET_DEFAULT(UseIntPolyIntrinsics, false); } -#ifdef _LP64 if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { UseMultiplyToLenIntrinsic = true; } @@ -1434,38 +1428,6 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { UseMontgomerySquareIntrinsic = true; } -#else - if (UseMultiplyToLenIntrinsic) { - if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { - warning("multiplyToLen intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false); - } - if (UseMontgomeryMultiplyIntrinsic) { - if (!FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { - warning("montgomeryMultiply intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, false); - } - if (UseMontgomerySquareIntrinsic) { - if (!FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { - warning("montgomerySquare intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, false); - } - if (UseSquareToLenIntrinsic) { - if (!FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { - warning("squareToLen intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, false); - } - if (UseMulAddIntrinsic) { - if (!FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { - warning("mulAdd intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseMulAddIntrinsic, false); - } -#endif // _LP64 #endif // COMPILER2_OR_JVMCI // On new cpus instructions which update whole XMM register should be used @@ -1632,7 +1594,7 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(UseStoreImmI16)) { UseStoreImmI16 = false; // don't use it on Intel cpus } - if (cpu_family() == 6 || cpu_family() == 15) { + if (is_intel_server_family() || cpu_family() == 15) { if (FLAG_IS_DEFAULT(UseAddressNop)) { // Use it on all Intel cpus starting from PentiumPro UseAddressNop = true; @@ -1648,7 +1610,7 @@ void VM_Version::get_processor_features() { UseXmmRegToRegMoveAll = false; } } - if (cpu_family() == 6 && supports_sse3()) { // New Intel cpus + if (is_intel_server_family() && supports_sse3()) { // New Intel cpus #ifdef COMPILER2 if (FLAG_IS_DEFAULT(MaxLoopPad)) { // For new Intel cpus do the next optimization: @@ -1742,7 +1704,6 @@ void VM_Version::get_processor_features() { } #endif -#ifdef _LP64 if (UseSSE42Intrinsics) { if (FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { UseVectorizedMismatchIntrinsic = true; @@ -1759,20 +1720,6 @@ void VM_Version::get_processor_features() { warning("vectorizedHashCode intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, false); } -#else - if (UseVectorizedMismatchIntrinsic) { - if (!FLAG_IS_DEFAULT(UseVectorizedMismatchIntrinsic)) { - warning("vectorizedMismatch intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); - } - if (UseVectorizedHashCodeIntrinsic) { - if (!FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { - warning("vectorizedHashCode intrinsic is not available in 32-bit VM"); - } - FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, false); - } -#endif // _LP64 // Use count leading zeros count instruction if available. if (supports_lzcnt()) { @@ -1901,7 +1848,7 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(AllocatePrefetchDistance, allocate_prefetch_distance(use_watermark_prefetch)); } - if (is_intel() && cpu_family() == 6 && supports_sse3()) { + if (is_intel() && is_intel_server_family() && supports_sse3()) { if (FLAG_IS_DEFAULT(AllocatePrefetchLines) && supports_sse4_2() && supports_ht()) { // Nehalem based cpus FLAG_SET_DEFAULT(AllocatePrefetchLines, 4); @@ -1921,7 +1868,6 @@ void VM_Version::get_processor_features() { #endif } -#ifdef _LP64 // Prefetch settings // Prefetch interval for gc copy/scan == 9 dcache lines. Derived from @@ -1940,7 +1886,6 @@ void VM_Version::get_processor_features() { if (FLAG_IS_DEFAULT(PrefetchScanIntervalInBytes)) { FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 576); } -#endif if (FLAG_IS_DEFAULT(ContendedPaddingWidth) && (cache_line_size > ContendedPaddingWidth)) @@ -2171,16 +2116,15 @@ int VM_Version::avx3_threshold() { FLAG_IS_DEFAULT(AVX3Threshold)) ? 0 : AVX3Threshold; } -#if defined(_LP64) void VM_Version::clear_apx_test_state() { clear_apx_test_state_stub(); } -#endif static bool _vm_version_initialized = false; void VM_Version::initialize() { ResourceMark rm; + // Making this stub must be FIRST use of assembler stub_blob = BufferBlob::create("VM_Version stub", stub_size); if (stub_blob == nullptr) { @@ -2193,14 +2137,11 @@ void VM_Version::initialize() { g.generate_get_cpu_info()); detect_virt_stub = CAST_TO_FN_PTR(detect_virt_stub_t, g.generate_detect_virt()); - -#if defined(_LP64) clear_apx_test_state_stub = CAST_TO_FN_PTR(clear_apx_test_state_t, g.clear_apx_test_state()); -#endif get_processor_features(); - LP64_ONLY(Assembler::precompute_instructions();) + Assembler::precompute_instructions(); if (VM_Version::supports_hv()) { // Supports hypervisor check_virtualizations(); @@ -2959,192 +2900,217 @@ int64_t VM_Version::maximum_qualified_cpu_frequency(void) { return _max_qualified_cpu_frequency; } -uint64_t VM_Version::CpuidInfo::feature_flags() const { - uint64_t result = 0; +VM_Version::VM_Features VM_Version::CpuidInfo::feature_flags() const { + VM_Features vm_features; if (std_cpuid1_edx.bits.cmpxchg8 != 0) - result |= CPU_CX8; + vm_features.set_feature(CPU_CX8); if (std_cpuid1_edx.bits.cmov != 0) - result |= CPU_CMOV; + vm_features.set_feature(CPU_CMOV); if (std_cpuid1_edx.bits.clflush != 0) - result |= CPU_FLUSH; -#ifdef _LP64 + vm_features.set_feature(CPU_FLUSH); // clflush should always be available on x86_64 // if not we are in real trouble because we rely on it // to flush the code cache. - assert ((result & CPU_FLUSH) != 0, "clflush should be available"); -#endif + assert (vm_features.supports_feature(CPU_FLUSH), "clflush should be available"); if (std_cpuid1_edx.bits.fxsr != 0 || (is_amd_family() && ext_cpuid1_edx.bits.fxsr != 0)) - result |= CPU_FXSR; + vm_features.set_feature(CPU_FXSR); // HT flag is set for multi-core processors also. if (threads_per_core() > 1) - result |= CPU_HT; + vm_features.set_feature(CPU_HT); if (std_cpuid1_edx.bits.mmx != 0 || (is_amd_family() && ext_cpuid1_edx.bits.mmx != 0)) - result |= CPU_MMX; + vm_features.set_feature(CPU_MMX); if (std_cpuid1_edx.bits.sse != 0) - result |= CPU_SSE; + vm_features.set_feature(CPU_SSE); if (std_cpuid1_edx.bits.sse2 != 0) - result |= CPU_SSE2; + vm_features.set_feature(CPU_SSE2); if (std_cpuid1_ecx.bits.sse3 != 0) - result |= CPU_SSE3; + vm_features.set_feature(CPU_SSE3); if (std_cpuid1_ecx.bits.ssse3 != 0) - result |= CPU_SSSE3; + vm_features.set_feature(CPU_SSSE3); if (std_cpuid1_ecx.bits.sse4_1 != 0) - result |= CPU_SSE4_1; + vm_features.set_feature(CPU_SSE4_1); if (std_cpuid1_ecx.bits.sse4_2 != 0) - result |= CPU_SSE4_2; + vm_features.set_feature(CPU_SSE4_2); if (std_cpuid1_ecx.bits.popcnt != 0) - result |= CPU_POPCNT; + vm_features.set_feature(CPU_POPCNT); if (sefsl1_cpuid7_edx.bits.apx_f != 0 && xem_xcr0_eax.bits.apx_f != 0) { - result |= CPU_APX_F; + vm_features.set_feature(CPU_APX_F); } if (std_cpuid1_ecx.bits.avx != 0 && std_cpuid1_ecx.bits.osxsave != 0 && xem_xcr0_eax.bits.sse != 0 && xem_xcr0_eax.bits.ymm != 0) { - result |= CPU_AVX; - result |= CPU_VZEROUPPER; + vm_features.set_feature(CPU_AVX); + vm_features.set_feature(CPU_VZEROUPPER); if (sefsl1_cpuid7_eax.bits.sha512 != 0) - result |= CPU_SHA512; + vm_features.set_feature(CPU_SHA512); if (std_cpuid1_ecx.bits.f16c != 0) - result |= CPU_F16C; + vm_features.set_feature(CPU_F16C); if (sef_cpuid7_ebx.bits.avx2 != 0) { - result |= CPU_AVX2; + vm_features.set_feature(CPU_AVX2); if (sefsl1_cpuid7_eax.bits.avx_ifma != 0) - result |= CPU_AVX_IFMA; + vm_features.set_feature(CPU_AVX_IFMA); } if (sef_cpuid7_ecx.bits.gfni != 0) - result |= CPU_GFNI; + vm_features.set_feature(CPU_GFNI); if (sef_cpuid7_ebx.bits.avx512f != 0 && xem_xcr0_eax.bits.opmask != 0 && xem_xcr0_eax.bits.zmm512 != 0 && xem_xcr0_eax.bits.zmm32 != 0) { - result |= CPU_AVX512F; + vm_features.set_feature(CPU_AVX512F); if (sef_cpuid7_ebx.bits.avx512cd != 0) - result |= CPU_AVX512CD; + vm_features.set_feature(CPU_AVX512CD); if (sef_cpuid7_ebx.bits.avx512dq != 0) - result |= CPU_AVX512DQ; + vm_features.set_feature(CPU_AVX512DQ); if (sef_cpuid7_ebx.bits.avx512ifma != 0) - result |= CPU_AVX512_IFMA; + vm_features.set_feature(CPU_AVX512_IFMA); if (sef_cpuid7_ebx.bits.avx512pf != 0) - result |= CPU_AVX512PF; + vm_features.set_feature(CPU_AVX512PF); if (sef_cpuid7_ebx.bits.avx512er != 0) - result |= CPU_AVX512ER; + vm_features.set_feature(CPU_AVX512ER); if (sef_cpuid7_ebx.bits.avx512bw != 0) - result |= CPU_AVX512BW; + vm_features.set_feature(CPU_AVX512BW); if (sef_cpuid7_ebx.bits.avx512vl != 0) - result |= CPU_AVX512VL; + vm_features.set_feature(CPU_AVX512VL); if (sef_cpuid7_ecx.bits.avx512_vpopcntdq != 0) - result |= CPU_AVX512_VPOPCNTDQ; + vm_features.set_feature(CPU_AVX512_VPOPCNTDQ); if (sef_cpuid7_ecx.bits.avx512_vpclmulqdq != 0) - result |= CPU_AVX512_VPCLMULQDQ; + vm_features.set_feature(CPU_AVX512_VPCLMULQDQ); if (sef_cpuid7_ecx.bits.vaes != 0) - result |= CPU_AVX512_VAES; + vm_features.set_feature(CPU_AVX512_VAES); if (sef_cpuid7_ecx.bits.avx512_vnni != 0) - result |= CPU_AVX512_VNNI; + vm_features.set_feature(CPU_AVX512_VNNI); if (sef_cpuid7_ecx.bits.avx512_bitalg != 0) - result |= CPU_AVX512_BITALG; + vm_features.set_feature(CPU_AVX512_BITALG); if (sef_cpuid7_ecx.bits.avx512_vbmi != 0) - result |= CPU_AVX512_VBMI; + vm_features.set_feature(CPU_AVX512_VBMI); if (sef_cpuid7_ecx.bits.avx512_vbmi2 != 0) - result |= CPU_AVX512_VBMI2; + vm_features.set_feature(CPU_AVX512_VBMI2); + } + if (is_intel()) { + if (sefsl1_cpuid7_edx.bits.avx10 != 0 && + std_cpuid24_ebx.bits.avx10_vlen_512 !=0 && + std_cpuid24_ebx.bits.avx10_converged_isa_version >= 1 && + xem_xcr0_eax.bits.opmask != 0 && + xem_xcr0_eax.bits.zmm512 != 0 && + xem_xcr0_eax.bits.zmm32 != 0) { + vm_features.set_feature(CPU_AVX10_1); + vm_features.set_feature(CPU_AVX512F); + vm_features.set_feature(CPU_AVX512CD); + vm_features.set_feature(CPU_AVX512DQ); + vm_features.set_feature(CPU_AVX512PF); + vm_features.set_feature(CPU_AVX512ER); + vm_features.set_feature(CPU_AVX512BW); + vm_features.set_feature(CPU_AVX512VL); + vm_features.set_feature(CPU_AVX512_VPOPCNTDQ); + vm_features.set_feature(CPU_AVX512_VPCLMULQDQ); + vm_features.set_feature(CPU_AVX512_VAES); + vm_features.set_feature(CPU_AVX512_VNNI); + vm_features.set_feature(CPU_AVX512_BITALG); + vm_features.set_feature(CPU_AVX512_VBMI); + vm_features.set_feature(CPU_AVX512_VBMI2); + if (std_cpuid24_ebx.bits.avx10_converged_isa_version >= 2) { + vm_features.set_feature(CPU_AVX10_2); + } + } } } + if (std_cpuid1_ecx.bits.hv != 0) - result |= CPU_HV; + vm_features.set_feature(CPU_HV); if (sef_cpuid7_ebx.bits.bmi1 != 0) - result |= CPU_BMI1; + vm_features.set_feature(CPU_BMI1); if (std_cpuid1_edx.bits.tsc != 0) - result |= CPU_TSC; + vm_features.set_feature(CPU_TSC); if (ext_cpuid7_edx.bits.tsc_invariance != 0) - result |= CPU_TSCINV_BIT; + vm_features.set_feature(CPU_TSCINV_BIT); if (std_cpuid1_ecx.bits.aes != 0) - result |= CPU_AES; + vm_features.set_feature(CPU_AES); if (ext_cpuid1_ecx.bits.lzcnt != 0) - result |= CPU_LZCNT; + vm_features.set_feature(CPU_LZCNT); if (ext_cpuid1_ecx.bits.prefetchw != 0) - result |= CPU_3DNOW_PREFETCH; + vm_features.set_feature(CPU_3DNOW_PREFETCH); if (sef_cpuid7_ebx.bits.erms != 0) - result |= CPU_ERMS; + vm_features.set_feature(CPU_ERMS); if (sef_cpuid7_edx.bits.fast_short_rep_mov != 0) - result |= CPU_FSRM; + vm_features.set_feature(CPU_FSRM); if (std_cpuid1_ecx.bits.clmul != 0) - result |= CPU_CLMUL; + vm_features.set_feature(CPU_CLMUL); if (sef_cpuid7_ebx.bits.rtm != 0) - result |= CPU_RTM; + vm_features.set_feature(CPU_RTM); if (sef_cpuid7_ebx.bits.adx != 0) - result |= CPU_ADX; + vm_features.set_feature(CPU_ADX); if (sef_cpuid7_ebx.bits.bmi2 != 0) - result |= CPU_BMI2; + vm_features.set_feature(CPU_BMI2); if (sef_cpuid7_ebx.bits.sha != 0) - result |= CPU_SHA; + vm_features.set_feature(CPU_SHA); if (std_cpuid1_ecx.bits.fma != 0) - result |= CPU_FMA; + vm_features.set_feature(CPU_FMA); if (sef_cpuid7_ebx.bits.clflushopt != 0) - result |= CPU_FLUSHOPT; + vm_features.set_feature(CPU_FLUSHOPT); if (sef_cpuid7_ebx.bits.clwb != 0) - result |= CPU_CLWB; + vm_features.set_feature(CPU_CLWB); if (ext_cpuid1_edx.bits.rdtscp != 0) - result |= CPU_RDTSCP; + vm_features.set_feature(CPU_RDTSCP); if (sef_cpuid7_ecx.bits.rdpid != 0) - result |= CPU_RDPID; + vm_features.set_feature(CPU_RDPID); // AMD|Hygon additional features. if (is_amd_family()) { // PREFETCHW was checked above, check TDNOW here. if ((ext_cpuid1_edx.bits.tdnow != 0)) - result |= CPU_3DNOW_PREFETCH; + vm_features.set_feature(CPU_3DNOW_PREFETCH); if (ext_cpuid1_ecx.bits.sse4a != 0) - result |= CPU_SSE4A; + vm_features.set_feature(CPU_SSE4A); } // Intel additional features. if (is_intel()) { if (sef_cpuid7_edx.bits.serialize != 0) - result |= CPU_SERIALIZE; + vm_features.set_feature(CPU_SERIALIZE); if (_cpuid_info.sef_cpuid7_edx.bits.avx512_fp16 != 0) - result |= CPU_AVX512_FP16; + vm_features.set_feature(CPU_AVX512_FP16); } // ZX additional features. if (is_zx()) { // We do not know if these are supported by ZX, so we cannot trust // common CPUID bit for them. - assert((result & CPU_CLWB) == 0, "Check if it is supported?"); - result &= ~CPU_CLWB; + assert(vm_features.supports_feature(CPU_CLWB), "Check if it is supported?"); + vm_features.clear_feature(CPU_CLWB); } // Protection key features. if (sef_cpuid7_ecx.bits.pku != 0) { - result |= CPU_PKU; + vm_features.set_feature(CPU_PKU); } if (sef_cpuid7_ecx.bits.ospke != 0) { - result |= CPU_OSPKE; + vm_features.set_feature(CPU_OSPKE); } // Control flow enforcement (CET) features. if (sef_cpuid7_ecx.bits.cet_ss != 0) { - result |= CPU_CET_SS; + vm_features.set_feature(CPU_CET_SS); } if (sef_cpuid7_edx.bits.cet_ibt != 0) { - result |= CPU_CET_IBT; + vm_features.set_feature(CPU_CET_IBT); } // Composite features. if (supports_tscinv_bit() && ((is_amd_family() && !is_amd_Barcelona()) || is_intel_tsc_synched_at_init())) { - result |= CPU_TSCINV; + vm_features.set_feature(CPU_TSCINV); } - - return result; + return vm_features; } bool VM_Version::os_supports_avx_vectors() { bool retVal = false; - int nreg = 2 LP64_ONLY(+2); + int nreg = 4; if (supports_evex()) { // Verify that OS save/restore all bits of EVEX registers // during signal processing. @@ -3296,19 +3262,15 @@ int VM_Version::allocate_prefetch_distance(bool use_watermark_prefetch) { return 128; // Athlon } } else { // Intel - if (supports_sse3() && cpu_family() == 6) { + if (supports_sse3() && is_intel_server_family()) { if (supports_sse4_2() && supports_ht()) { // Nehalem based cpus return 192; } else if (use_watermark_prefetch) { // watermark prefetching on Core -#ifdef _LP64 return 384; -#else - return 320; -#endif } } if (supports_sse2()) { - if (cpu_family() == 6) { + if (is_intel_server_family()) { return 256; // Pentium M, Core, Core2 } else { return 512; // Pentium 4 @@ -3333,3 +3295,14 @@ bool VM_Version::is_intrinsic_supported(vmIntrinsicID id) { } return true; } + +void VM_Version::insert_features_names(VM_Version::VM_Features features, char* buf, size_t buflen) { + for (int i = 0; i < MAX_CPU_FEATURES; i++) { + if (features.supports_feature((VM_Version::Feature_Flag)i)) { + int res = jio_snprintf(buf, buflen, ", %s", _features_names[i]); + assert(res > 0, "not enough temporary space allocated"); + buf += res; + buflen -= res; + } + } +} diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index cc5c6c1c639..3c8971e474b 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -295,12 +295,32 @@ class VM_Version : public Abstract_VM_Version { union SefCpuid7SubLeaf1Edx { uint32_t value; struct { - uint32_t : 21, + uint32_t : 19, + avx10 : 1, + : 1, apx_f : 1, : 10; } bits; }; + union StdCpuid24MainLeafEax { + uint32_t value; + struct { + uint32_t sub_leaves_cnt : 31; + } bits; + }; + + union StdCpuid24MainLeafEbx { + uint32_t value; + struct { + uint32_t avx10_converged_isa_version : 8, + : 8, + : 2, + avx10_vlen_512 : 1, + : 13; + } bits; + }; + union ExtCpuid1EEbx { uint32_t value; struct { @@ -342,9 +362,9 @@ class VM_Version : public Abstract_VM_Version { /* * Update following files when declaring new flags: * test/lib-test/jdk/test/whitebox/CPUInfoTest.java - * src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java + * src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java */ - enum Feature_Flag : uint64_t { + enum Feature_Flag { #define CPU_FEATURE_FLAGS(decl) \ decl(CX8, "cx8", 0) /* next bits are from cpuid 1 (EDX) */ \ decl(CMOV, "cmov", 1) \ @@ -420,15 +440,85 @@ class VM_Version : public Abstract_VM_Version { decl(AVX_IFMA, "avx_ifma", 59) /* 256-bit VEX-coded variant of AVX512-IFMA*/ \ decl(APX_F, "apx_f", 60) /* Intel Advanced Performance Extensions*/ \ decl(SHA512, "sha512", 61) /* SHA512 instructions*/ \ - decl(AVX512_FP16, "avx512_fp16", 62) /* AVX512 FP16 ISA support*/ + decl(AVX512_FP16, "avx512_fp16", 62) /* AVX512 FP16 ISA support*/ \ + decl(AVX10_1, "avx10_1", 63) /* AVX10 512 bit vector ISA Version 1 support*/ \ + decl(AVX10_2, "avx10_2", 64) /* AVX10 512 bit vector ISA Version 2 support*/ -#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1ULL << bit), +#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (bit), CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG) #undef DECLARE_CPU_FEATURE_FLAG + MAX_CPU_FEATURES }; + class VM_Features { + friend class VMStructs; + friend class JVMCIVMStructs; + + private: + uint64_t _features_bitmap[(MAX_CPU_FEATURES / BitsPerLong) + 1]; + + STATIC_ASSERT(sizeof(_features_bitmap) * BitsPerByte >= MAX_CPU_FEATURES); + + // Number of 8-byte elements in _bitmap. + constexpr static int features_bitmap_element_count() { + return sizeof(_features_bitmap) / sizeof(uint64_t); + } + + constexpr static int features_bitmap_element_shift_count() { + return LogBitsPerLong; + } + + constexpr static uint64_t features_bitmap_element_mask() { + return (1ULL << features_bitmap_element_shift_count()) - 1; + } + + static int index(Feature_Flag feature) { + int idx = feature >> features_bitmap_element_shift_count(); + assert(idx < features_bitmap_element_count(), "Features array index out of bounds"); + return idx; + } + + static uint64_t bit_mask(Feature_Flag feature) { + return (1ULL << (feature & features_bitmap_element_mask())); + } + + static int _features_bitmap_size; // for JVMCI purposes + public: + VM_Features() { + for (int i = 0; i < features_bitmap_element_count(); i++) { + _features_bitmap[i] = 0; + } + } + + void set_feature(Feature_Flag feature) { + int idx = index(feature); + _features_bitmap[idx] |= bit_mask(feature); + } + + void clear_feature(VM_Version::Feature_Flag feature) { + int idx = index(feature); + _features_bitmap[idx] &= ~bit_mask(feature); + } + + bool supports_feature(VM_Version::Feature_Flag feature) { + int idx = index(feature); + return (_features_bitmap[idx] & bit_mask(feature)) != 0; + } + }; + + // CPU feature flags vector, can be affected by VM settings. + static VM_Features _features; + + // Original CPU feature flags vector, not affected by VM settings. + static VM_Features _cpu_features; + static const char* _features_names[]; + static void clear_cpu_features() { + _features = VM_Features(); + _cpu_features = VM_Features(); + } + enum Extended_Family { // AMD CPU_FAMILY_AMD_11H = 0x11, @@ -492,6 +582,11 @@ class VM_Version : public Abstract_VM_Version { SefCpuid7SubLeaf1Eax sefsl1_cpuid7_eax; SefCpuid7SubLeaf1Edx sefsl1_cpuid7_edx; + // cpuid function 24 converged vector ISA main leaf + // eax = 24, ecx = 0 + StdCpuid24MainLeafEax std_cpuid24_eax; + StdCpuid24MainLeafEbx std_cpuid24_ebx; + // cpuid function 0xB (processor topology) // ecx = 0 uint32_t tpl_cpuidB0_eax; @@ -565,7 +660,7 @@ class VM_Version : public Abstract_VM_Version { // Space to save apx registers after signal handle jlong apx_save[2]; // Save r16 and r31 - uint64_t feature_flags() const; + VM_Features feature_flags() const; // Asserts void assert_is_initialized() const { @@ -611,6 +706,7 @@ class VM_Version : public Abstract_VM_Version { // Offsets for cpuid asm stub static ByteSize std_cpuid0_offset() { return byte_offset_of(CpuidInfo, std_max_function); } static ByteSize std_cpuid1_offset() { return byte_offset_of(CpuidInfo, std_cpuid1_eax); } + static ByteSize std_cpuid24_offset() { return byte_offset_of(CpuidInfo, std_cpuid24_eax); } static ByteSize dcp_cpuid4_offset() { return byte_offset_of(CpuidInfo, dcp_cpuid4_eax); } static ByteSize sef_cpuid7_offset() { return byte_offset_of(CpuidInfo, sef_cpuid7_eax); } static ByteSize sefsl1_cpuid7_offset() { return byte_offset_of(CpuidInfo, sefsl1_cpuid7_eax); } @@ -642,13 +738,31 @@ class VM_Version : public Abstract_VM_Version { static void set_cpuinfo_cont_addr_apx(address pc) { _cpuinfo_cont_addr_apx = pc; } static address cpuinfo_cont_addr_apx() { return _cpuinfo_cont_addr_apx; } - LP64_ONLY(static void clear_apx_test_state()); + static void clear_apx_test_state(); - static void clean_cpuFeatures() { _features = 0; } - static void set_avx_cpuFeatures() { _features |= (CPU_SSE | CPU_SSE2 | CPU_AVX | CPU_VZEROUPPER ); } - static void set_evex_cpuFeatures() { _features |= (CPU_AVX512F | CPU_SSE | CPU_SSE2 | CPU_VZEROUPPER ); } - static void set_apx_cpuFeatures() { _features |= CPU_APX_F; } - static void set_bmi_cpuFeatures() { _features |= (CPU_BMI1 | CPU_BMI2 | CPU_LZCNT | CPU_POPCNT); } + static void clean_cpuFeatures() { + VM_Version::clear_cpu_features(); + } + static void set_avx_cpuFeatures() { + _features.set_feature(CPU_SSE); + _features.set_feature(CPU_SSE2); + _features.set_feature(CPU_AVX); + _features.set_feature(CPU_VZEROUPPER); + } + static void set_evex_cpuFeatures() { + _features.set_feature(CPU_AVX10_1); + _features.set_feature(CPU_AVX512F); + _features.set_feature(CPU_SSE); + _features.set_feature(CPU_SSE2); + _features.set_feature(CPU_VZEROUPPER); + } + static void set_apx_cpuFeatures() { _features.set_feature(CPU_APX_F); } + static void set_bmi_cpuFeatures() { + _features.set_feature(CPU_BMI1); + _features.set_feature(CPU_BMI2); + _features.set_feature(CPU_LZCNT); + _features.set_feature(CPU_POPCNT); + } // Initialization static void initialize(); @@ -677,6 +791,7 @@ class VM_Version : public Abstract_VM_Version { static uint32_t cpu_stepping() { return _cpuid_info.cpu_stepping(); } static int cpu_family() { return _cpu;} static bool is_P6() { return cpu_family() >= 6; } + static bool is_intel_server_family() { return cpu_family() == 6 || cpu_family() == 19; } static bool is_amd() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x68747541; } // 'htuA' static bool is_hygon() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x6F677948; } // 'ogyH' static bool is_amd_family() { return is_amd() || is_hygon(); } @@ -703,40 +818,39 @@ class VM_Version : public Abstract_VM_Version { // // Feature identification which can be affected by VM settings // - static bool supports_cpuid() { return _features != 0; } - static bool supports_cmov() { return (_features & CPU_CMOV) != 0; } - static bool supports_fxsr() { return (_features & CPU_FXSR) != 0; } - static bool supports_ht() { return (_features & CPU_HT) != 0; } - static bool supports_mmx() { return (_features & CPU_MMX) != 0; } - static bool supports_sse() { return (_features & CPU_SSE) != 0; } - static bool supports_sse2() { return (_features & CPU_SSE2) != 0; } - static bool supports_sse3() { return (_features & CPU_SSE3) != 0; } - static bool supports_ssse3() { return (_features & CPU_SSSE3)!= 0; } - static bool supports_sse4_1() { return (_features & CPU_SSE4_1) != 0; } - static bool supports_sse4_2() { return (_features & CPU_SSE4_2) != 0; } - static bool supports_popcnt() { return (_features & CPU_POPCNT) != 0; } - static bool supports_avx() { return (_features & CPU_AVX) != 0; } - static bool supports_avx2() { return (_features & CPU_AVX2) != 0; } - static bool supports_tsc() { return (_features & CPU_TSC) != 0; } - static bool supports_rdtscp() { return (_features & CPU_RDTSCP) != 0; } - static bool supports_rdpid() { return (_features & CPU_RDPID) != 0; } - static bool supports_aes() { return (_features & CPU_AES) != 0; } - static bool supports_erms() { return (_features & CPU_ERMS) != 0; } - static bool supports_fsrm() { return (_features & CPU_FSRM) != 0; } - static bool supports_clmul() { return (_features & CPU_CLMUL) != 0; } - static bool supports_rtm() { return (_features & CPU_RTM) != 0; } - static bool supports_bmi1() { return (_features & CPU_BMI1) != 0; } - static bool supports_bmi2() { return (_features & CPU_BMI2) != 0; } - static bool supports_adx() { return (_features & CPU_ADX) != 0; } - static bool supports_evex() { return (_features & CPU_AVX512F) != 0; } - static bool supports_avx512dq() { return (_features & CPU_AVX512DQ) != 0; } - static bool supports_avx512ifma() { return (_features & CPU_AVX512_IFMA) != 0; } - static bool supports_avxifma() { return (_features & CPU_AVX_IFMA) != 0; } - static bool supports_avx512pf() { return (_features & CPU_AVX512PF) != 0; } - static bool supports_avx512er() { return (_features & CPU_AVX512ER) != 0; } - static bool supports_avx512cd() { return (_features & CPU_AVX512CD) != 0; } - static bool supports_avx512bw() { return (_features & CPU_AVX512BW) != 0; } - static bool supports_avx512vl() { return (_features & CPU_AVX512VL) != 0; } + static bool supports_cmov() { return _features.supports_feature(CPU_CMOV); } + static bool supports_fxsr() { return _features.supports_feature(CPU_FXSR); } + static bool supports_ht() { return _features.supports_feature(CPU_HT); } + static bool supports_mmx() { return _features.supports_feature(CPU_MMX); } + static bool supports_sse() { return _features.supports_feature(CPU_SSE); } + static bool supports_sse2() { return _features.supports_feature(CPU_SSE2); } + static bool supports_sse3() { return _features.supports_feature(CPU_SSE3); } + static bool supports_ssse3() { return _features.supports_feature(CPU_SSSE3); } + static bool supports_sse4_1() { return _features.supports_feature(CPU_SSE4_1); } + static bool supports_sse4_2() { return _features.supports_feature(CPU_SSE4_2); } + static bool supports_popcnt() { return _features.supports_feature(CPU_POPCNT); } + static bool supports_avx() { return _features.supports_feature(CPU_AVX); } + static bool supports_avx2() { return _features.supports_feature(CPU_AVX2); } + static bool supports_tsc() { return _features.supports_feature(CPU_TSC); } + static bool supports_rdtscp() { return _features.supports_feature(CPU_RDTSCP); } + static bool supports_rdpid() { return _features.supports_feature(CPU_RDPID); } + static bool supports_aes() { return _features.supports_feature(CPU_AES); } + static bool supports_erms() { return _features.supports_feature(CPU_ERMS); } + static bool supports_fsrm() { return _features.supports_feature(CPU_FSRM); } + static bool supports_clmul() { return _features.supports_feature(CPU_CLMUL); } + static bool supports_rtm() { return _features.supports_feature(CPU_RTM); } + static bool supports_bmi1() { return _features.supports_feature(CPU_BMI1); } + static bool supports_bmi2() { return _features.supports_feature(CPU_BMI2); } + static bool supports_adx() { return _features.supports_feature(CPU_ADX); } + static bool supports_evex() { return _features.supports_feature(CPU_AVX512F); } + static bool supports_avx512dq() { return _features.supports_feature(CPU_AVX512DQ); } + static bool supports_avx512ifma() { return _features.supports_feature(CPU_AVX512_IFMA); } + static bool supports_avxifma() { return _features.supports_feature(CPU_AVX_IFMA); } + static bool supports_avx512pf() { return _features.supports_feature(CPU_AVX512PF); } + static bool supports_avx512er() { return _features.supports_feature(CPU_AVX512ER); } + static bool supports_avx512cd() { return _features.supports_feature(CPU_AVX512CD); } + static bool supports_avx512bw() { return _features.supports_feature(CPU_AVX512BW); } + static bool supports_avx512vl() { return _features.supports_feature(CPU_AVX512VL); } static bool supports_avx512vlbw() { return (supports_evex() && supports_avx512bw() && supports_avx512vl()); } static bool supports_avx512bwdq() { return (supports_evex() && supports_avx512bw() && supports_avx512dq()); } static bool supports_avx512vldq() { return (supports_evex() && supports_avx512dq() && supports_avx512vl()); } @@ -745,33 +859,39 @@ class VM_Version : public Abstract_VM_Version { static bool supports_avx512novl() { return (supports_evex() && !supports_avx512vl()); } static bool supports_avx512nobw() { return (supports_evex() && !supports_avx512bw()); } static bool supports_avx256only() { return (supports_avx2() && !supports_evex()); } - static bool supports_apx_f() { return (_features & CPU_APX_F) != 0; } + static bool supports_apx_f() { return _features.supports_feature(CPU_APX_F); } static bool supports_avxonly() { return ((supports_avx2() || supports_avx()) && !supports_evex()); } - static bool supports_sha() { return (_features & CPU_SHA) != 0; } - static bool supports_fma() { return (_features & CPU_FMA) != 0 && supports_avx(); } - static bool supports_vzeroupper() { return (_features & CPU_VZEROUPPER) != 0; } - static bool supports_avx512_vpopcntdq() { return (_features & CPU_AVX512_VPOPCNTDQ) != 0; } - static bool supports_avx512_vpclmulqdq() { return (_features & CPU_AVX512_VPCLMULQDQ) != 0; } - static bool supports_avx512_vaes() { return (_features & CPU_AVX512_VAES) != 0; } - static bool supports_gfni() { return (_features & CPU_GFNI) != 0; } - static bool supports_avx512_vnni() { return (_features & CPU_AVX512_VNNI) != 0; } - static bool supports_avx512_bitalg() { return (_features & CPU_AVX512_BITALG) != 0; } - static bool supports_avx512_vbmi() { return (_features & CPU_AVX512_VBMI) != 0; } - static bool supports_avx512_vbmi2() { return (_features & CPU_AVX512_VBMI2) != 0; } - static bool supports_avx512_fp16() { return (_features & CPU_AVX512_FP16) != 0; } - static bool supports_hv() { return (_features & CPU_HV) != 0; } - static bool supports_serialize() { return (_features & CPU_SERIALIZE) != 0; } - static bool supports_f16c() { return (_features & CPU_F16C) != 0; } - static bool supports_pku() { return (_features & CPU_PKU) != 0; } - static bool supports_ospke() { return (_features & CPU_OSPKE) != 0; } - static bool supports_cet_ss() { return (_features & CPU_CET_SS) != 0; } - static bool supports_cet_ibt() { return (_features & CPU_CET_IBT) != 0; } - static bool supports_sha512() { return (_features & CPU_SHA512) != 0; } + static bool supports_sha() { return _features.supports_feature(CPU_SHA); } + static bool supports_fma() { return _features.supports_feature(CPU_FMA) && supports_avx(); } + static bool supports_vzeroupper() { return _features.supports_feature(CPU_VZEROUPPER); } + static bool supports_avx512_vpopcntdq() { return _features.supports_feature(CPU_AVX512_VPOPCNTDQ); } + static bool supports_avx512_vpclmulqdq() { return _features.supports_feature(CPU_AVX512_VPCLMULQDQ); } + static bool supports_avx512_vaes() { return _features.supports_feature(CPU_AVX512_VAES); } + static bool supports_gfni() { return _features.supports_feature(CPU_GFNI); } + static bool supports_avx512_vnni() { return _features.supports_feature(CPU_AVX512_VNNI); } + static bool supports_avx512_bitalg() { return _features.supports_feature(CPU_AVX512_BITALG); } + static bool supports_avx512_vbmi() { return _features.supports_feature(CPU_AVX512_VBMI); } + static bool supports_avx512_vbmi2() { return _features.supports_feature(CPU_AVX512_VBMI2); } + static bool supports_avx512_fp16() { return _features.supports_feature(CPU_AVX512_FP16); } + static bool supports_hv() { return _features.supports_feature(CPU_HV); } + static bool supports_serialize() { return _features.supports_feature(CPU_SERIALIZE); } + static bool supports_f16c() { return _features.supports_feature(CPU_F16C); } + static bool supports_pku() { return _features.supports_feature(CPU_PKU); } + static bool supports_ospke() { return _features.supports_feature(CPU_OSPKE); } + static bool supports_cet_ss() { return _features.supports_feature(CPU_CET_SS); } + static bool supports_cet_ibt() { return _features.supports_feature(CPU_CET_IBT); } + static bool supports_sha512() { return _features.supports_feature(CPU_SHA512); } + + // Intel® AVX10 introduces a versioned approach for enumeration that is monotonically increasing, inclusive, + // and supporting all vector lengths. Feature set supported by an AVX10 vector ISA version is also supported + // by all the versions above it. + static bool supports_avx10_1() { return _features.supports_feature(CPU_AVX10_1);} + static bool supports_avx10_2() { return _features.supports_feature(CPU_AVX10_2);} // // Feature identification not affected by VM flags // - static bool cpu_supports_evex() { return (_cpu_features & CPU_AVX512F) != 0; } + static bool cpu_supports_evex() { return _cpu_features.supports_feature(CPU_AVX512F); } static bool supports_avx512_simd_sort() { if (supports_avx512dq()) { @@ -802,6 +922,8 @@ class VM_Version : public Abstract_VM_Version { static bool is_intel_tsc_synched_at_init(); + static void insert_features_names(VM_Version::VM_Features features, char* buf, size_t buflen); + // This checks if the JVM is potentially affected by an erratum on Intel CPUs (SKX102) // that causes unpredictable behaviour when jcc crosses 64 byte boundaries. Its microcode // mitigation causes regressions when jumps or fused conditional branches cross or end at @@ -809,23 +931,23 @@ class VM_Version : public Abstract_VM_Version { static bool has_intel_jcc_erratum() { return _has_intel_jcc_erratum; } // AMD features - static bool supports_3dnow_prefetch() { return (_features & CPU_3DNOW_PREFETCH) != 0; } - static bool supports_lzcnt() { return (_features & CPU_LZCNT) != 0; } - static bool supports_sse4a() { return (_features & CPU_SSE4A) != 0; } + static bool supports_3dnow_prefetch() { return _features.supports_feature(CPU_3DNOW_PREFETCH); } + static bool supports_lzcnt() { return _features.supports_feature(CPU_LZCNT); } + static bool supports_sse4a() { return _features.supports_feature(CPU_SSE4A); } static bool is_amd_Barcelona() { return is_amd() && extended_cpu_family() == CPU_FAMILY_AMD_11H; } // Intel and AMD newer cores support fast timestamps well static bool supports_tscinv_bit() { - return (_features & CPU_TSCINV_BIT) != 0; + return _features.supports_feature(CPU_TSCINV_BIT); } static bool supports_tscinv() { - return (_features & CPU_TSCINV) != 0; + return _features.supports_feature(CPU_TSCINV); } // Intel Core and newer cpus have fast IDIV instruction (excluding Atom). - static bool has_fast_idiv() { return is_intel() && cpu_family() == 6 && + static bool has_fast_idiv() { return is_intel() && is_intel_server_family() && supports_sse3() && _model != 0x1C; } static bool supports_compare_and_exchange() { return true; } @@ -839,12 +961,12 @@ class VM_Version : public Abstract_VM_Version { // x86_64 supports fast class initialization checks static bool supports_fast_class_init_checks() { - return LP64_ONLY(true) NOT_LP64(false); // not implemented on x86_32 + return true; } // x86_64 supports secondary supers table constexpr static bool supports_secondary_supers_table() { - return LP64_ONLY(true) NOT_LP64(false); // not implemented on x86_32 + return true; } constexpr static bool supports_stack_watermark_barrier() { @@ -879,15 +1001,11 @@ class VM_Version : public Abstract_VM_Version { // synchronize with other memory ops. so, it needs preceding // and trailing StoreStore fences. -#ifdef _LP64 static bool supports_clflush(); // Can't inline due to header file conflict -#else - static bool supports_clflush() { return ((_features & CPU_FLUSH) != 0); } -#endif // _LP64 // Note: CPU_FLUSHOPT and CPU_CLWB bits should always be zero for 32-bit - static bool supports_clflushopt() { return ((_features & CPU_FLUSHOPT) != 0); } - static bool supports_clwb() { return ((_features & CPU_CLWB) != 0); } + static bool supports_clflushopt() { return (_features.supports_feature(CPU_FLUSHOPT)); } + static bool supports_clwb() { return (_features.supports_feature(CPU_CLWB)); } // Old CPUs perform lea on AGU which causes additional latency transferring the // value from/to ALU for other operations diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 078150c61fb..22490ba7bb3 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -422,6 +422,18 @@ source_hpp %{ #include "peephole_x86_64.hpp" +bool castLL_is_imm32(const Node* n); + +%} + +source %{ + +bool castLL_is_imm32(const Node* n) { + assert(n->is_CastLL(), "must be a CastLL"); + const TypeLong* t = n->bottom_type()->is_long(); + return (t->_lo == min_jlong || Assembler::is_simm32(t->_lo)) && (t->_hi == max_jlong || Assembler::is_simm32(t->_hi)); +} + %} // Register masks @@ -1584,14 +1596,11 @@ uint MachUEPNode::size(PhaseRegAlloc* ra_) const //============================================================================= bool Matcher::supports_vector_calling_convention(void) { - if (EnableVectorSupport && UseVectorStubs) { - return true; - } - return false; + return EnableVectorSupport; } OptoRegPair Matcher::vector_return_value(uint ideal_reg) { - assert(EnableVectorSupport && UseVectorStubs, "sanity"); + assert(EnableVectorSupport, "sanity"); int lo = XMM0_num; int hi = XMM0b_num; if (ideal_reg == Op_VecX) hi = XMM0d_num; @@ -1838,20 +1847,19 @@ encode %{ %} enc_class clear_avx %{ - debug_only(int off0 = __ offset()); + DEBUG_ONLY(int off0 = __ offset()); if (generate_vzeroupper(Compile::current())) { // Clear upper bits of YMM registers to avoid AVX <-> SSE transition penalty // Clear upper bits of YMM registers when current compiled code uses // wide vectors to avoid AVX <-> SSE transition penalty during call. __ vzeroupper(); } - debug_only(int off1 = __ offset()); + DEBUG_ONLY(int off1 = __ offset()); assert(off1 - off0 == clear_avx_size(), "correct size prediction"); %} enc_class Java_To_Runtime(method meth) %{ - // No relocation needed - __ mov64(r10, (int64_t) $meth$$method); + __ lea(r10, RuntimeAddress((address)$meth$$method)); __ call(r10); __ post_call_nop(); %} @@ -6258,13 +6266,14 @@ instruct cmovI_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) instruct cmovI_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src1, rRegI src2) %{ predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); + effect(TEMP dst); ins_cost(200); format %{ "ecmovpl $dst, $src1, $src2\n\t" - "ecmovnel $dst, $src1, $src2" %} + "cmovnel $dst, $src2" %} ins_encode %{ __ ecmovl(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ ecmovl(Assembler::notEqual, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovl(Assembler::notEqual, $dst$$Register, $src2$$Register); %} ins_pipe(pipe_cmov_reg); %} @@ -6274,6 +6283,7 @@ instruct cmovI_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI s instruct cmovI_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) %{ predicate(!UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); match(Set dst (CMoveI (Binary cop cr) (Binary src dst))); + effect(TEMP dst); ins_cost(200); // XXX format %{ "cmovpl $dst, $src\n\t" @@ -6289,14 +6299,15 @@ instruct cmovI_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src) // and parity flag bit is set if any of the operand is a NaN. instruct cmovI_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegI dst, rRegI src1, rRegI src2) %{ predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveI (Binary cop cr) (Binary src1 src2))); + match(Set dst (CMoveI (Binary cop cr) (Binary src2 src1))); + effect(TEMP dst); ins_cost(200); format %{ "ecmovpl $dst, $src1, $src2\n\t" - "ecmovnel $dst, $src1, $src2" %} + "cmovnel $dst, $src2" %} ins_encode %{ __ ecmovl(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ ecmovl(Assembler::notEqual, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovl(Assembler::notEqual, $dst$$Register, $src2$$Register); %} ins_pipe(pipe_cmov_reg); %} @@ -6539,6 +6550,7 @@ instruct cmovP_regU_ndd(rRegP dst, cmpOpU cop, rFlagsRegU cr, rRegP src1, rRegP %} instruct cmovP_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ + predicate(!UseAPX); match(Set dst (CMoveP (Binary cop cr) (Binary dst src))); ins_cost(200); expand %{ @@ -6547,6 +6559,7 @@ instruct cmovP_regUCF(cmpOpUCF cop, rFlagsRegUCF cr, rRegP dst, rRegP src) %{ %} instruct cmovP_regUCF_ndd(rRegP dst, cmpOpUCF cop, rFlagsRegUCF cr, rRegP src1, rRegP src2) %{ + predicate(UseAPX); match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); ins_cost(200); format %{ "ecmovq$cop $dst, $src1, $src2\t# unsigned, ptr ndd" %} @@ -6573,13 +6586,14 @@ instruct cmovP_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) instruct cmovP_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src1, rRegP src2) %{ predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); + effect(TEMP dst); ins_cost(200); format %{ "ecmovpq $dst, $src1, $src2\n\t" - "ecmovneq $dst, $src1, $src2" %} + "cmovneq $dst, $src2" %} ins_encode %{ __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ ecmovq(Assembler::notEqual, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); %} ins_pipe(pipe_cmov_reg); %} @@ -6602,14 +6616,15 @@ instruct cmovP_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src) instruct cmovP_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegP dst, rRegP src1, rRegP src2) %{ predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveP (Binary cop cr) (Binary src1 src2))); + match(Set dst (CMoveP (Binary cop cr) (Binary src2 src1))); + effect(TEMP dst); ins_cost(200); format %{ "ecmovpq $dst, $src1, $src2\n\t" - "ecmovneq $dst, $src1, $src2" %} + "cmovneq $dst, $src2" %} ins_encode %{ __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ ecmovq(Assembler::notEqual, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); %} ins_pipe(pipe_cmov_reg); %} @@ -6772,13 +6787,14 @@ instruct cmovL_regUCF2_ne(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) instruct cmovL_regUCF2_ne_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src1, rRegL src2) %{ predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::ne); match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); + effect(TEMP dst); ins_cost(200); format %{ "ecmovpq $dst, $src1, $src2\n\t" - "ecmovneq $dst, $src1, $src2" %} + "cmovneq $dst, $src2" %} ins_encode %{ __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ ecmovq(Assembler::notEqual, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); %} ins_pipe(pipe_cmov_reg); %} @@ -6801,14 +6817,15 @@ instruct cmovL_regUCF2_eq(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src) instruct cmovL_regUCF2_eq_ndd(cmpOpUCF2 cop, rFlagsRegUCF cr, rRegL dst, rRegL src1, rRegL src2) %{ predicate(UseAPX && n->in(1)->in(1)->as_Bool()->_test._test == BoolTest::eq); - match(Set dst (CMoveL (Binary cop cr) (Binary src1 src2))); + match(Set dst (CMoveL (Binary cop cr) (Binary src2 src1))); + effect(TEMP dst); ins_cost(200); format %{ "ecmovpq $dst, $src1, $src2\n\t" - "ecmovneq $dst, $src1, $src2" %} + "cmovneq $dst, $src2" %} ins_encode %{ __ ecmovq(Assembler::parity, $dst$$Register, $src1$$Register, $src2$$Register); - __ ecmovq(Assembler::notEqual, $dst$$Register, $src1$$Register, $src2$$Register); + __ cmovq(Assembler::notEqual, $dst$$Register, $src2$$Register); %} ins_pipe(pipe_cmov_reg); %} @@ -7035,21 +7052,6 @@ instruct addI_rReg_mem(rRegI dst, memory src, rFlagsReg cr) ins_pipe(ialu_reg_mem); %} -instruct addI_rReg_mem_rReg_ndd(rRegI dst, memory src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddI (LoadI src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "eaddl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eaddl($dst$$Register, $src1$$Address, $src2$$Register, false); - %} - ins_pipe(ialu_reg_mem); -%} - instruct addI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr) %{ predicate(UseAPX); @@ -7353,21 +7355,6 @@ instruct addL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr ins_pipe(ialu_reg_mem); %} -instruct addL_rReg_mem_rReg_ndd(rRegL dst, memory src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AddL (LoadL src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_overflow_flag, PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_carry_flag, PD::Flag_sets_parity_flag); - - ins_cost(150); - format %{ "eaddq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eaddq($dst$$Register, $src1$$Address, $src2$$Register, false); - %} - ins_pipe(ialu_reg_mem); -%} - instruct addL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ match(Set dst (StoreL dst (AddL (LoadL dst) src))); @@ -7605,6 +7592,7 @@ instruct castPP(rRegP dst) instruct castII(rRegI dst) %{ + predicate(VerifyConstraintCasts == 0); match(Set dst (CastII dst)); size(0); @@ -7614,8 +7602,22 @@ instruct castII(rRegI dst) ins_pipe(empty); %} +instruct castII_checked(rRegI dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0); + match(Set dst (CastII dst)); + + effect(KILL cr); + format %{ "# cast_checked_II $dst" %} + ins_encode %{ + __ verify_int_in_range(_idx, bottom_type()->is_int(), $dst$$Register); + %} + ins_pipe(pipe_slow); +%} + instruct castLL(rRegL dst) %{ + predicate(VerifyConstraintCasts == 0); match(Set dst (CastLL dst)); size(0); @@ -7625,6 +7627,32 @@ instruct castLL(rRegL dst) ins_pipe(empty); %} +instruct castLL_checked_L32(rRegL dst, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0 && castLL_is_imm32(n)); + match(Set dst (CastLL dst)); + + effect(KILL cr); + format %{ "# cast_checked_LL $dst" %} + ins_encode %{ + __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, noreg); + %} + ins_pipe(pipe_slow); +%} + +instruct castLL_checked(rRegL dst, rRegL tmp, rFlagsReg cr) +%{ + predicate(VerifyConstraintCasts > 0 && !castLL_is_imm32(n)); + match(Set dst (CastLL dst)); + + effect(KILL cr, TEMP tmp); + format %{ "# cast_checked_LL $dst\tusing $tmp as TEMP" %} + ins_encode %{ + __ verify_long_in_range(_idx, bottom_type()->is_long(), $dst$$Register, $tmp$$Register); + %} + ins_pipe(pipe_slow); +%} + instruct castFF(regF dst) %{ match(Set dst (CastFF dst)); @@ -8538,7 +8566,6 @@ instruct mulI_rReg_ndd(rRegI dst, rRegI src1, rRegI src2, rFlagsReg cr) instruct mulI_rReg_imm(rRegI dst, rRegI src, immI imm, rFlagsReg cr) %{ - predicate(!UseAPX); match(Set dst (MulI src imm)); effect(KILL cr); @@ -8550,20 +8577,6 @@ instruct mulI_rReg_imm(rRegI dst, rRegI src, immI imm, rFlagsReg cr) ins_pipe(ialu_reg_reg_alu0); %} -instruct mulI_rReg_rReg_imm_ndd(rRegI dst, rRegI src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (MulI src1 src2)); - effect(KILL cr); - - ins_cost(300); - format %{ "eimull $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eimull($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - instruct mulI_mem(rRegI dst, memory src, rFlagsReg cr) %{ predicate(!UseAPX); @@ -8594,7 +8607,6 @@ instruct mulI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr instruct mulI_mem_imm(rRegI dst, memory src, immI imm, rFlagsReg cr) %{ - predicate(!UseAPX); match(Set dst (MulI (LoadI src) imm)); effect(KILL cr); @@ -8606,20 +8618,6 @@ instruct mulI_mem_imm(rRegI dst, memory src, immI imm, rFlagsReg cr) ins_pipe(ialu_reg_mem_alu0); %} -instruct mulI_rReg_mem_imm(rRegI dst, memory src1, immI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (MulI (LoadI src1) src2)); - effect(KILL cr); - - ins_cost(300); - format %{ "eimull $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ eimull($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg_mem_alu0); -%} - instruct mulAddS2I_rReg(rRegI dst, rRegI src1, rRegI src2, rRegI src3, rFlagsReg cr) %{ match(Set dst (MulAddS2I (Binary dst src1) (Binary src2 src3))); @@ -8660,7 +8658,6 @@ instruct mulL_rReg_ndd(rRegL dst, rRegL src1, rRegL src2, rFlagsReg cr) instruct mulL_rReg_imm(rRegL dst, rRegL src, immL32 imm, rFlagsReg cr) %{ - predicate(!UseAPX); match(Set dst (MulL src imm)); effect(KILL cr); @@ -8672,20 +8669,6 @@ instruct mulL_rReg_imm(rRegL dst, rRegL src, immL32 imm, rFlagsReg cr) ins_pipe(ialu_reg_reg_alu0); %} -instruct mulL_rReg_rReg_imm_ndd(rRegL dst, rRegL src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (MulL src1 src2)); - effect(KILL cr); - - ins_cost(300); - format %{ "eimulq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eimulq($dst$$Register, $src1$$Register, $src2$$constant, false); - %} - ins_pipe(ialu_reg_reg_alu0); -%} - instruct mulL_mem(rRegL dst, memory src, rFlagsReg cr) %{ predicate(!UseAPX); @@ -8716,7 +8699,6 @@ instruct mulL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr instruct mulL_mem_imm(rRegL dst, memory src, immL32 imm, rFlagsReg cr) %{ - predicate(!UseAPX); match(Set dst (MulL (LoadL src) imm)); effect(KILL cr); @@ -8728,20 +8710,6 @@ instruct mulL_mem_imm(rRegL dst, memory src, immL32 imm, rFlagsReg cr) ins_pipe(ialu_reg_mem_alu0); %} -instruct mulL_rReg_mem_imm_ndd(rRegL dst, memory src1, immL32 src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (MulL (LoadL src1) src2)); - effect(KILL cr); - - ins_cost(300); - format %{ "eimulq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eimulq($dst$$Register, $src1$$Address, $src2$$constant, false); - %} - ins_pipe(ialu_reg_mem_alu0); -%} - instruct mulHiL_rReg(rdx_RegL dst, rRegL src, rax_RegL rax, rFlagsReg cr) %{ match(Set dst (MulHiL src rax)); @@ -10631,21 +10599,6 @@ instruct xorI_rReg_rReg_mem_ndd(rRegI dst, rRegI src1, memory src2, rFlagsReg cr ins_pipe(ialu_reg_mem); %} -instruct xorI_rReg_mem_rReg_ndd(rRegI dst, memory src1, rRegI src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (XorI (LoadI src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "exorl $dst, $src1, $src2\t# int ndd" %} - ins_encode %{ - __ exorl($dst$$Register, $src1$$Address, $src2$$Register, false); - %} - ins_pipe(ialu_reg_mem); -%} - // Xor Memory with Register instruct xorB_mem_rReg(memory dst, rRegI src, rFlagsReg cr) %{ @@ -10825,21 +10778,6 @@ instruct andL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr ins_pipe(ialu_reg_mem); %} -instruct andL_rReg_mem_rReg_ndd(rRegL dst, memory src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (AndL (LoadL src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "eandq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ eandq($dst$$Register, $src1$$Address, $src2$$Register, false); - %} - ins_pipe(ialu_reg_mem); -%} - // And Memory with Register instruct andL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ @@ -11335,21 +11273,6 @@ instruct xorL_rReg_rReg_mem_ndd(rRegL dst, rRegL src1, memory src2, rFlagsReg cr ins_pipe(ialu_reg_mem); %} -instruct xorL_rReg_mem_rReg_ndd(rRegL dst, memory src1, rRegL src2, rFlagsReg cr) -%{ - predicate(UseAPX); - match(Set dst (XorL (LoadL src1) src2)); - effect(KILL cr); - flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_sets_parity_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); - - ins_cost(150); - format %{ "exorq $dst, $src1, $src2\t# long ndd" %} - ins_encode %{ - __ exorq($dst$$Register, $src1$$Address, $src2$$Register, false); - %} - ins_pipe(ialu_reg_mem); -%} - // Xor Memory with Register instruct xorL_mem_rReg(memory dst, rRegL src, rFlagsReg cr) %{ diff --git a/src/hotspot/cpu/zero/icache_zero.hpp b/src/hotspot/cpu/zero/icache_zero.hpp index b40e07d5e3b..781021a2b20 100644 --- a/src/hotspot/cpu/zero/icache_zero.hpp +++ b/src/hotspot/cpu/zero/icache_zero.hpp @@ -33,7 +33,7 @@ class ICache : public AbstractICache { public: - static void initialize() {} + static void initialize(int phase) {} static void invalidate_word(address addr) {} static void invalidate_range(address start, int nbytes) {} }; diff --git a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp index f141135ff95..60a873ab31f 100644 --- a/src/hotspot/cpu/zero/sharedRuntime_zero.cpp +++ b/src/hotspot/cpu/zero/sharedRuntime_zero.cpp @@ -50,18 +50,17 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, return 0; } -AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters( - MacroAssembler *masm, - int total_args_passed, - int comp_args_on_stack, - const BasicType *sig_bt, - const VMRegPair *regs, - AdapterFingerPrint *fingerprint) { - return AdapterHandlerLibrary::new_entry( - fingerprint, - CAST_FROM_FN_PTR(address,zero_null_code_stub), - CAST_FROM_FN_PTR(address,zero_null_code_stub), - CAST_FROM_FN_PTR(address,zero_null_code_stub)); +void SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + AdapterHandlerEntry* handler) { + handler->set_entry_points(CAST_FROM_FN_PTR(address,zero_null_code_stub), + CAST_FROM_FN_PTR(address,zero_null_code_stub), + CAST_FROM_FN_PTR(address,zero_null_code_stub), + nullptr); + return; } nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp index e38561e19c5..3ce9227c193 100644 --- a/src/hotspot/cpu/zero/vm_version_zero.cpp +++ b/src/hotspot/cpu/zero/vm_version_zero.cpp @@ -151,6 +151,6 @@ void VM_Version::initialize_cpu_information(void) { _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); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "%s", _cpu_info_string); _initialized = true; } diff --git a/src/hotspot/os/aix/libodm_aix.cpp b/src/hotspot/os/aix/libodm_aix.cpp index 9fe0fb7abd8..854fd5e2b79 100644 --- a/src/hotspot/os/aix/libodm_aix.cpp +++ b/src/hotspot/os/aix/libodm_aix.cpp @@ -30,6 +30,7 @@ #include #include "runtime/arguments.hpp" #include "runtime/os.hpp" +#include "utilities/permitForbiddenFunctions.hpp" dynamicOdm::dynamicOdm() { @@ -59,7 +60,7 @@ dynamicOdm::~dynamicOdm() { } -void odmWrapper::clean_data() { if (_data) { free(_data); _data = nullptr; } } +void odmWrapper::clean_data() { if (_data) { permit_forbidden_function::free(_data); _data = nullptr; } } int odmWrapper::class_offset(const char *field, bool is_aix_5) diff --git a/src/hotspot/os/aix/loadlib_aix.cpp b/src/hotspot/os/aix/loadlib_aix.cpp index 90a7271ad6d..e7dbd775e37 100644 --- a/src/hotspot/os/aix/loadlib_aix.cpp +++ b/src/hotspot/os/aix/loadlib_aix.cpp @@ -38,6 +38,7 @@ #include "logging/log.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" // For loadquery() #include @@ -58,7 +59,7 @@ class StringList { // Enlarge list. If oom, leave old list intact and return false. bool enlarge() { int cap2 = _cap + 64; - char** l2 = (char**) ::realloc(_list, sizeof(char*) * cap2); + char** l2 = (char**) permit_forbidden_function::realloc(_list, sizeof(char*) * cap2); if (!l2) { return false; } @@ -76,7 +77,7 @@ class StringList { } } assert0(_cap > _num); - char* s2 = ::strdup(s); + char* s2 = permit_forbidden_function::strdup(s); if (!s2) { return nullptr; } @@ -170,7 +171,7 @@ 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); + permit_forbidden_function::free(lm); lm = lm2; } *start = nullptr; @@ -193,7 +194,7 @@ static bool reload_table() { uint8_t* buffer = nullptr; size_t buflen = 1024; for (;;) { - buffer = (uint8_t*) ::realloc(buffer, buflen); + buffer = (uint8_t*) permit_forbidden_function::realloc(buffer, buflen); if (loadquery(L_GETINFO, buffer, buflen) == -1) { if (errno == ENOMEM) { buflen *= 2; @@ -229,7 +230,7 @@ static bool reload_table() { for (;;) { - loaded_module_t* lm = (loaded_module_t*) ::malloc(sizeof(loaded_module_t)); + loaded_module_t* lm = (loaded_module_t*) permit_forbidden_function::malloc(sizeof(loaded_module_t)); if (!lm) { log_warning(os)("OOM."); goto cleanup; @@ -250,7 +251,7 @@ static bool reload_table() { if (!lm->path) { log_warning(os)("OOM."); - free(lm); + permit_forbidden_function::free(lm); goto cleanup; } @@ -272,7 +273,7 @@ static bool reload_table() { lm->member = g_stringlist.add(p_mbr_name); if (!lm->member) { log_warning(os)("OOM."); - free(lm); + permit_forbidden_function::free(lm); goto cleanup; } } else { @@ -320,7 +321,7 @@ static bool reload_table() { free_entry_list(&new_list); } - ::free(buffer); + permit_forbidden_function::free(buffer); return rc; diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index d913139ffdf..e7b401701ac 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -58,8 +58,6 @@ #include "runtime/perfMemory.hpp" #include "runtime/safefetch.hpp" #include "runtime/sharedRuntime.hpp" -#include "runtime/statSampler.hpp" -#include "runtime/threadCritical.hpp" #include "runtime/threads.hpp" #include "runtime/timer.hpp" #include "runtime/vm_version.hpp" @@ -73,6 +71,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/vmError.hpp" #if INCLUDE_JFR #include "jfr/support/jfrNativeLibraryLoadEvent.hpp" @@ -131,8 +130,6 @@ extern "C" int getargs(procsinfo*, int, char*, int); #define MAX_PATH (2 * K) -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) // for multipage initialization error analysis (in 'g_multipage_error') #define ERROR_MP_OS_TOO_OLD 100 #define ERROR_MP_EXTSHM_ACTIVE 101 @@ -140,12 +137,6 @@ extern "C" int getargs(procsinfo*, int, char*, int); #define ERROR_MP_VMGETINFO_CLAIMS_NO_SUPPORT_FOR_64K 103 // excerpts from sys/systemcfg.h that might be missing on older os levels -#ifndef PV_7 - #define PV_7 0x200000 /* Power PC 7 */ -#endif -#ifndef PV_7_Compat - #define PV_7_Compat 0x208000 /* Power PC 7 */ -#endif #ifndef PV_8 #define PV_8 0x300000 /* Power PC 8 */ #endif @@ -369,9 +360,9 @@ static void query_multipage_support() { // or by environment variable LDR_CNTRL (suboption DATAPSIZE). If none is given, // default should be 4K. { - void* p = ::malloc(16*M); + void* p = permit_forbidden_function::malloc(16*M); g_multipage_support.datapsize = os::Aix::query_pagesize(p); - ::free(p); + permit_forbidden_function::free(p); } // Query default shm page size (LDR_CNTRL SHMPSIZE). @@ -762,10 +753,23 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, pthread_t tid = 0; if (ret == 0) { - int limit = 3; - do { + int trials_remaining = 4; + useconds_t next_delay = 1000; + while (true) { ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread); - } while (ret == EAGAIN && limit-- > 0); + + if (ret != EAGAIN) { + break; + } + + if (--trials_remaining <= 0) { + break; + } + + log_debug(os, thread)("Failed to start native thread (%s), retrying after %dus.", os::errno_name(ret), next_delay); + ::usleep(next_delay); + next_delay *= 2; + } } if (ret == 0) { @@ -905,7 +909,7 @@ jlong os::javaTimeNanos() { } void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; // mread_real_time() is monotonic (see 'os::javaTimeNanos()') info_ptr->may_skip_backward = false; info_ptr->may_skip_forward = false; @@ -1236,33 +1240,6 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) { case PV_8: strncpy(buf, "Power PC 8", buflen); break; - case PV_7: - strncpy(buf, "Power PC 7", buflen); - break; - case PV_6_1: - strncpy(buf, "Power PC 6 DD1.x", buflen); - break; - case PV_6: - strncpy(buf, "Power PC 6", buflen); - break; - case PV_5: - strncpy(buf, "Power PC 5", buflen); - break; - case PV_5_2: - strncpy(buf, "Power PC 5_2", buflen); - break; - case PV_5_3: - strncpy(buf, "Power PC 5_3", buflen); - break; - case PV_5_Compat: - strncpy(buf, "PV_5_Compat", buflen); - break; - case PV_6_Compat: - strncpy(buf, "PV_6_Compat", buflen); - break; - case PV_7_Compat: - strncpy(buf, "PV_7_Compat", buflen); - break; case PV_8_Compat: strncpy(buf, "PV_8_Compat", buflen); break; @@ -1398,7 +1375,7 @@ static struct { } vmem; static void vmembk_add(char* addr, size_t size, size_t pagesize, int type) { - vmembk_t* p = (vmembk_t*) ::malloc(sizeof(vmembk_t)); + vmembk_t* p = (vmembk_t*) permit_forbidden_function::malloc(sizeof(vmembk_t)); assert0(p); if (p) { MiscUtils::AutoCritSect lck(&vmem.cs); @@ -1427,7 +1404,7 @@ static void vmembk_remove(vmembk_t* p0) { for (vmembk_t** pp = &(vmem.first); *pp; pp = &((*pp)->next)) { if (*pp == p0) { *pp = p0->next; - ::free(p0); + permit_forbidden_function::free(p0); return; } } @@ -2570,14 +2547,14 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned } void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index 0b008a197de..8444002b871 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -72,7 +72,7 @@ enum { * Get info for requested PID from /proc//psinfo file */ static bool read_psinfo(const u_longlong_t& pid, psinfo_t& psinfo) { - static size_t BUF_LENGTH = 32 + sizeof(u_longlong_t); + const size_t BUF_LENGTH = 32 + sizeof(u_longlong_t); FILE* fp; char buf[BUF_LENGTH]; @@ -118,7 +118,6 @@ static OSReturn get_lcpu_ticks(perfstat_id_t* lcpu_name, cpu_tick_store_t* ptick * Return CPU load caused by the currently executing process (the jvm). */ 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; perfstat_process_t jvm_stats; @@ -204,8 +203,6 @@ static bool populate_lcpu_names(int ncpus, perfstat_id_t* lcpu_names) { * (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); - u_longlong_t ticks; perfstat_cpu_total_t cpu_stats; @@ -214,7 +211,7 @@ static OSReturn perf_context_switch_rate(double* rate) { } ticks = cpu_stats.user + cpu_stats.sys + cpu_stats.idle + cpu_stats.wait; - *rate = (cpu_stats.pswitch / ticks) * ticks_per_sec; + *rate = (cpu_stats.pswitch / ticks) * os::Posix::clock_tics_per_second(); return OS_OK; } diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index cbc45d3e122..2235d3da686 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -39,6 +39,7 @@ #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include #include #include @@ -250,7 +251,7 @@ bool AixSymbols::get_function_name ( p_name[namelen-1] = '\0'; } if (demangled_name != nullptr) { - ALLOW_C_FUNCTION(::free, ::free(demangled_name)); + permit_forbidden_function::free(demangled_name); } } } else { @@ -1081,7 +1082,7 @@ void* Aix_dlopen(const char* filename, int Flags, int *eno, const char** error_r if (g_handletable_used == max_handletable) { // No place in array anymore; increase array. unsigned new_max = MAX2(max_handletable * 2, init_num_handles); - struct handletableentry* new_tab = (struct handletableentry*)::realloc(p_handletable, new_max * sizeof(struct handletableentry)); + struct handletableentry* new_tab = (struct handletableentry*) permit_forbidden_function::realloc(p_handletable, new_max * sizeof(struct handletableentry)); assert(new_tab != nullptr, "no more memory for handletable"); if (new_tab == nullptr) { *error_report = "dlopen: no more memory for handletable"; diff --git a/src/hotspot/os/bsd/decoder_machO.cpp b/src/hotspot/os/bsd/decoder_machO.cpp index 173e030a7b5..15592d172fe 100644 --- a/src/hotspot/os/bsd/decoder_machO.cpp +++ b/src/hotspot/os/bsd/decoder_machO.cpp @@ -27,6 +27,8 @@ #include "decoder_machO.hpp" #include "jvm.h" #include "memory/allocation.inline.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include #include @@ -42,9 +44,9 @@ bool MachODecoder::demangle(const char* symbol, char *buf, int buflen) { // may use different malloc/realloc mechanism that allocates 'buf'. if ((result = abi::__cxa_demangle(symbol, nullptr, nullptr, &status)) != nullptr) { jio_snprintf(buf, buflen, "%s", result); - // call c library's free - ::free(result); - return true; + // call c library's free + permit_forbidden_function::free(result); + return true; } return false; } diff --git a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp index 86549e878cb..861fda7a71d 100644 --- a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp +++ b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp @@ -77,7 +77,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) _initialized(false) { // Reserve address space for backing memory - _base = (uintptr_t)os::reserve_memory(max_capacity, false, mtJavaHeap); + _base = (uintptr_t)os::reserve_memory(max_capacity, mtJavaHeap); if (_base == 0) { // Failed ZInitialize::error("Failed to reserve address space for backing memory"); diff --git a/src/hotspot/os/bsd/memMapPrinter_macosx.cpp b/src/hotspot/os/bsd/memMapPrinter_macosx.cpp index 477803001cb..154d2887c53 100644 --- a/src/hotspot/os/bsd/memMapPrinter_macosx.cpp +++ b/src/hotspot/os/bsd/memMapPrinter_macosx.cpp @@ -29,6 +29,7 @@ #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" #include "utilities/powerOfTwo.hpp" #include @@ -303,7 +304,7 @@ class ProcSmapsPrinter { st->print_cr("vminfo: VM information (requires NMT)"); st->print_cr("file: file mapped, if mapping is not anonymous"); { - streamIndentor si(st, 16); + StreamIndentor si(st, 16); _session.print_nmt_flag_legend(); } st->print_cr("file: file mapped, if mapping is not anonymous"); diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 193c7cb0689..3535d027dbc 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -53,9 +53,7 @@ #include "runtime/perfMemory.hpp" #include "runtime/semaphore.hpp" #include "runtime/sharedRuntime.hpp" -#include "runtime/statSampler.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/threadCritical.hpp" #include "runtime/threads.hpp" #include "runtime/timer.hpp" #include "services/attachListener.hpp" @@ -114,9 +112,6 @@ #define MAX_PATH (2 * K) -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) - //////////////////////////////////////////////////////////////////////////////// // global variables julong os::Bsd::_physical_memory = 0; @@ -146,7 +141,9 @@ julong os::free_memory() { return Bsd::available_memory(); } -// available here means free +// Available here means free. Note that this number is of no much use. As an estimate +// for future memory pressure it is far too conservative, since MacOS will use a lot +// of unused memory for caches, and return it willingly in case of needs. julong os::Bsd::available_memory() { uint64_t available = physical_memory() >> 2; #ifdef __APPLE__ @@ -647,10 +644,23 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, ResourceMark rm; pthread_t tid; int ret = 0; - int limit = 3; - do { + int trials_remaining = 4; + useconds_t next_delay = 1000; + while (true) { ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread); - } while (ret == EAGAIN && limit-- > 0); + + if (ret != EAGAIN) { + break; + } + + if (--trials_remaining <= 0) { + break; + } + + log_debug(os, thread)("Failed to start native thread (%s), retrying after %dus.", os::errno_name(ret), next_delay); + ::usleep(next_delay); + next_delay *= 2; + } char buf[64]; if (ret == 0) { @@ -815,7 +825,7 @@ jlong os::javaTimeNanos() { } void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; info_ptr->may_skip_backward = false; // not subject to resetting or drifting info_ptr->may_skip_forward = false; // not subject to resetting or drifting info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time @@ -2423,14 +2433,14 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned } void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 94cc87d5f9f..068914d7049 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -297,6 +297,7 @@ bool CgroupSubsystemFactory::determine_type(CgroupInfo* cg_infos, } else { log_debug(os, container)("Can't read %s, %s", controllers_file, os::strerror(errno)); *flags = INVALID_CGROUPS_V2; + fclose(controllers); return false; } for (int i = 0; i < CG_INFO_LENGTH; i++) { diff --git a/src/hotspot/os/linux/decoder_linux.cpp b/src/hotspot/os/linux/decoder_linux.cpp index 26b435f69e1..bfe5c537864 100644 --- a/src/hotspot/os/linux/decoder_linux.cpp +++ b/src/hotspot/os/linux/decoder_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ #include "utilities/decoder_elf.hpp" #include "utilities/elfFile.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include @@ -46,9 +47,9 @@ bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { // may use different malloc/realloc mechanism that allocates 'buf'. if ((result = abi::__cxa_demangle(symbol, nullptr, nullptr, &status)) != nullptr) { jio_snprintf(buf, buflen, "%s", result); - // call c library's free - ALLOW_C_FUNCTION(::free, ::free(result);) - return true; + // call c library's free + permit_forbidden_function::free(result); + return true; } return false; } diff --git a/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp b/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp index 60ce39179ff..92c5cb713ac 100644 --- a/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zMountPoint_linux.cpp @@ -28,6 +28,7 @@ #include "runtime/globals.hpp" #include "runtime/os.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include #include @@ -62,11 +63,11 @@ char* ZMountPoint::get_mountpoint(const char* line, const char* filesystem) cons strcmp(line_filesystem, filesystem) != 0 || access(line_mountpoint, R_OK|W_OK|X_OK) != 0) { // Not a matching or accessible filesystem - ALLOW_C_FUNCTION(::free, ::free(line_mountpoint);) + permit_forbidden_function::free(line_mountpoint); line_mountpoint = nullptr; } - ALLOW_C_FUNCTION(::free, ::free(line_filesystem);) + permit_forbidden_function::free(line_filesystem); return line_mountpoint; } @@ -90,14 +91,14 @@ void ZMountPoint::get_mountpoints(const char* filesystem, ZArray* mountpo } // readline will return malloced memory. Need raw ::free, not os::free. - ALLOW_C_FUNCTION(::free, ::free(line);) + permit_forbidden_function::free(line); fclose(fd); } void ZMountPoint::free_mountpoints(ZArray* mountpoints) const { ZArrayIterator iter(mountpoints); for (char* mountpoint; iter.next(&mountpoint);) { - ALLOW_C_FUNCTION(::free, ::free(mountpoint);) // *not* os::free + permit_forbidden_function::free(mountpoint); // *not* os::free } mountpoints->clear(); } diff --git a/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp b/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp index 1e1becf5a14..e5978c8d93a 100644 --- a/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp +++ b/src/hotspot/os/linux/gc/z/zSyscall_linux.hpp @@ -35,6 +35,10 @@ #define MPOL_F_ADDR (1<<1) #endif +#ifndef MAP_FIXED_NOREPLACE +#define MAP_FIXED_NOREPLACE 0x100000 +#endif + class ZSyscall : public AllStatic { public: static int memfd_create(const char* name, unsigned int flags); diff --git a/src/hotspot/os/linux/mallocInfoDcmd.cpp b/src/hotspot/os/linux/mallocInfoDcmd.cpp index ad98d5edece..1a2368b1e50 100644 --- a/src/hotspot/os/linux/mallocInfoDcmd.cpp +++ b/src/hotspot/os/linux/mallocInfoDcmd.cpp @@ -26,6 +26,7 @@ #include "os_linux.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include @@ -35,7 +36,7 @@ void MallocInfoDcmd::execute(DCmdSource source, TRAPS) { #ifdef __GLIBC__ char* buf; size_t size; - ALLOW_C_FUNCTION(::open_memstream, FILE* stream = ::open_memstream(&buf, &size);) + FILE* stream = ::open_memstream(&buf, &size); if (stream == nullptr) { _output->print_cr("Error: Could not call malloc_info(3)"); return; @@ -43,7 +44,7 @@ void MallocInfoDcmd::execute(DCmdSource source, TRAPS) { int err = os::Linux::malloc_info(stream); if (err == 0) { - ALLOW_C_FUNCTION(::fflush, fflush(stream);) + fflush(stream); _output->print_raw(buf); _output->cr(); } else if (err == -1) { @@ -53,8 +54,8 @@ void MallocInfoDcmd::execute(DCmdSource source, TRAPS) { } else { ShouldNotReachHere(); } - ALLOW_C_FUNCTION(::fclose, ::fclose(stream);) - ALLOW_C_FUNCTION(::free, ::free(buf);) + ::fclose(stream); + permit_forbidden_function::free(buf); #else _output->print_cr(malloc_info_unavailable); #endif // __GLIBC__ diff --git a/src/hotspot/os/linux/memMapPrinter_linux.cpp b/src/hotspot/os/linux/memMapPrinter_linux.cpp index b84921dd3bb..91fd552eec5 100644 --- a/src/hotspot/os/linux/memMapPrinter_linux.cpp +++ b/src/hotspot/os/linux/memMapPrinter_linux.cpp @@ -28,6 +28,7 @@ #include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" #include "utilities/powerOfTwo.hpp" #include @@ -139,7 +140,7 @@ class ProcSmapsPrinter { st->print_cr(" huge: mapping uses hugetlb pages"); st->print_cr("vm info: VM information (requires NMT)"); { - streamIndentor si(st, 16); + StreamIndentor si(st, 16); _session.print_nmt_flag_legend(); } st->print_cr("file: file mapped, if mapping is not anonymous"); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 1afece719cb..807014e7b0c 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -56,9 +56,7 @@ #include "runtime/osThread.hpp" #include "runtime/perfMemory.hpp" #include "runtime/sharedRuntime.hpp" -#include "runtime/statSampler.hpp" #include "runtime/stubRoutines.hpp" -#include "runtime/threadCritical.hpp" #include "runtime/threads.hpp" #include "runtime/threadSMR.hpp" #include "runtime/timer.hpp" @@ -139,9 +137,6 @@ #define MAX_PATH (2 * K) -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) - #ifdef MUSL_LIBC // dlvsym is not a part of POSIX // and musl libc doesn't implement it. @@ -213,8 +208,6 @@ typedef int (*malloc_info_func_t)(int options, FILE *stream); static malloc_info_func_t g_malloc_info = nullptr; #endif // __GLIBC__ -static int clock_tics_per_sec = 100; - // If the VM might have been created on the primordial thread, we need to resolve the // primordial thread stack bounds and check if the current thread might be the // primordial thread in places. If we know that the primordial thread is never used, @@ -1062,10 +1055,23 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, ResourceMark rm; pthread_t tid; int ret = 0; - int limit = 3; - do { + int trials_remaining = 4; + useconds_t next_delay = 1000; + while (true) { ret = pthread_create(&tid, &attr, (void* (*)(void*)) thread_native_entry, thread); - } while (ret == EAGAIN && limit-- > 0); + + if (ret != EAGAIN) { + break; + } + + if (--trials_remaining <= 0) { + break; + } + + log_debug(os, thread)("Failed to start native thread (%s), retrying after %dus.", os::errno_name(ret), next_delay); + ::usleep(next_delay); + next_delay *= 2; + } char buf[64]; if (ret == 0) { @@ -1667,7 +1673,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { } ThreadInVMfromNative tiv(jt); - debug_only(VMNativeEntryWrapper vew;) + DEBUG_ONLY(VMNativeEntryWrapper vew;) VM_LinuxDllLoad op(filename, ebuf, ebuflen); VMThread::execute(&op); @@ -4381,8 +4387,6 @@ static void check_pax(void) { // this is called _before_ most of the global arguments have been parsed void os::init(void) { char dummy; // used to get a guess on initial stack address - - clock_tics_per_sec = checked_cast(sysconf(_SC_CLK_TCK)); int sys_pg_size = checked_cast(sysconf(_SC_PAGESIZE)); if (sys_pg_size < 0) { fatal("os_linux.cpp: os::init: sysconf failed (%s)", @@ -4575,7 +4579,7 @@ static void workaround_expand_exec_shield_cs_limit() { */ char* hint = (char*)(os::Linux::initial_thread_stack_bottom() - (StackOverflow::stack_guard_zone_size() + page_size)); - char* codebuf = os::attempt_reserve_memory_at(hint, page_size, false, mtThread); + char* codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread); if (codebuf == nullptr) { // JDK-8197429: There may be a stack gap of one megabyte between @@ -4583,7 +4587,7 @@ static void workaround_expand_exec_shield_cs_limit() { // Linux kernel workaround for CVE-2017-1000364. If we failed to // map our codebuf, try again at an address one megabyte lower. hint -= 1 * M; - codebuf = os::attempt_reserve_memory_at(hint, page_size, false, mtThread); + codebuf = os::attempt_reserve_memory_at(hint, page_size, mtThread); } if ((codebuf == nullptr) || (!os::commit_memory(codebuf, page_size, true))) { @@ -5135,21 +5139,21 @@ static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { &user_time, &sys_time); if (count != 13) return -1; if (user_sys_cpu_time) { - return ((jlong)sys_time + (jlong)user_time) * (1000000000 / clock_tics_per_sec); + return ((jlong)sys_time + (jlong)user_time) * (1000000000 / os::Posix::clock_tics_per_second()); } else { - return (jlong)user_time * (1000000000 / clock_tics_per_sec); + return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); } } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned } void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits + info_ptr->max_value = all_bits_jlong; // will not wrap in less than 64 bits info_ptr->may_skip_backward = false; // elapsed time not wall time info_ptr->may_skip_forward = false; // elapsed time not wall time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned diff --git a/src/hotspot/os/posix/forbiddenFunctions_posix.hpp b/src/hotspot/os/posix/forbiddenFunctions_posix.hpp new file mode 100644 index 00000000000..9f9881202c7 --- /dev/null +++ b/src/hotspot/os/posix/forbiddenFunctions_posix.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_POSIX_FORBIDDENFUNCTIONS_POSIX_HPP +#define OS_POSIX_FORBIDDENFUNCTIONS_POSIX_HPP + +#include "utilities/compilerWarnings.hpp" + +// For types used in the signatures. +#include + +// Workaround for noreturn functions: _exit - see the clang +// definition of FORBIDDEN_FUNCTION_NORETURN_ATTRIBUTE. +#ifdef __clang__ +#include +#endif + +// If needed, add os::strndup and use that instead. +FORBID_C_FUNCTION(char* strndup(const char*, size_t), "don't use"); + +// These are unimplementable for Windows, and they aren't useful for a +// POSIX implementation of NMT either. +// https://stackoverflow.com/questions/62962839/stdaligned-alloc-missing-from-visual-studio-2019 +FORBID_C_FUNCTION(int posix_memalign(void**, size_t, size_t), "don't use"); +FORBID_C_FUNCTION(void* aligned_alloc(size_t, size_t), "don't use"); + +// realpath with a null second argument mallocs a string for the result. +// With a non-null second argument, there is a risk of buffer overrun. +PRAGMA_DIAG_PUSH +FORBIDDEN_FUNCTION_IGNORE_CLANG_FORTIFY_WARNING +FORBID_C_FUNCTION(char* realpath(const char*, char*), "use os::realpath"); +PRAGMA_DIAG_POP + +// Returns a malloc'ed string. +FORBID_C_FUNCTION(char* get_current_dir_name(), "use os::get_current_directory"); + +// Problematic API that should never be used. +FORBID_C_FUNCTION(char* getwd(char*), "use os::get_current_directory"); + +// BSD utility that is subtly different from realloc. +FORBID_C_FUNCTION(void* reallocf(void*, size_t), "use os::realloc"); + +#endif // OS_POSIX_FORBIDDENFUNCTIONS_POSIX_HPP diff --git a/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp b/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp index 4eea35c8a2e..89bde0557ec 100644 --- a/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp +++ b/src/hotspot/os/posix/gc/z/zVirtualMemoryManager_posix.cpp @@ -24,6 +24,9 @@ #include "gc/z/zAddress.inline.hpp" #include "gc/z/zVirtualMemoryManager.hpp" #include "logging/log.hpp" +#ifdef LINUX +#include "gc/z/zSyscall_linux.hpp" +#endif #include @@ -32,7 +35,9 @@ void ZVirtualMemoryReserver::pd_register_callbacks(ZVirtualMemoryRegistry* regis } bool ZVirtualMemoryReserver::pd_reserve(zaddress_unsafe addr, size_t size) { - void* const res = mmap((void*)untype(addr), size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0); + const int flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE LINUX_ONLY(|MAP_FIXED_NOREPLACE); + + void* const res = mmap((void*)untype(addr), size, PROT_NONE, flags, -1, 0); if (res == MAP_FAILED) { // Failed to reserve memory return false; diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index a36d6b87641..448ebce620a 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -23,6 +23,7 @@ */ #include "classfile/classLoader.hpp" +#include "interpreter/interpreter.hpp" #include "jvm.h" #include "jvmtifiles/jvmti.h" #include "logging/log.hpp" @@ -49,6 +50,7 @@ #include "utilities/formatBuffer.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/vmError.hpp" #if INCLUDE_JFR #include "jfr/support/jfrNativeLibraryLoadEvent.hpp" @@ -491,9 +493,9 @@ static char* chop_extra_memory(size_t size, size_t alignment, char* extra_base, // Multiple threads can race in this code, and can remap over each other with MAP_FIXED, // so on posix, unmap the section at the start and at the end of the chunk that we mapped // rather than unmapping and remapping the whole chunk to get requested alignment. -char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) { +char* os::reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool exec) { size_t extra_size = calculate_aligned_extra_size(size, alignment); - char* extra_base = os::reserve_memory(extra_size, exec); + char* extra_base = os::reserve_memory(extra_size, mem_tag, exec); if (extra_base == nullptr) { return nullptr; } @@ -930,11 +932,11 @@ ssize_t os::connect(int fd, struct sockaddr* him, socklen_t len) { } void os::exit(int num) { - ALLOW_C_FUNCTION(::exit, ::exit(num);) + permit_forbidden_function::exit(num); } void os::_exit(int num) { - ALLOW_C_FUNCTION(::_exit, ::_exit(num);) + permit_forbidden_function::_exit(num); } void os::naked_yield() { @@ -991,7 +993,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { // This assumes platform realpath() is implemented according to POSIX.1-2008. // POSIX.1-2008 allows to specify null for the output buffer, in which case // output buffer is dynamically allocated and must be ::free()'d by the caller. - ALLOW_C_FUNCTION(::realpath, char* p = ::realpath(filename, nullptr);) + char* p = permit_forbidden_function::realpath(filename, nullptr); if (p != nullptr) { if (strlen(p) < outbuflen) { strcpy(outbuf, p); @@ -999,7 +1001,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } - ALLOW_C_FUNCTION(::free, ::free(p);) // *not* os::free + permit_forbidden_function::free(p); // *not* os::free } else { // Fallback for platforms struggling with modern Posix standards (AIX 5.3, 6.1). If realpath // returns EINVAL, this may indicate that realpath is not POSIX.1-2008 compatible and @@ -1008,7 +1010,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { // a memory overwrite. if (errno == EINVAL) { outbuf[outbuflen - 1] = '\0'; - ALLOW_C_FUNCTION(::realpath, p = ::realpath(filename, outbuf);) + p = permit_forbidden_function::realpath(filename, outbuf); if (p != nullptr) { guarantee(outbuf[outbuflen - 1] == '\0', "realpath buffer overwrite detected."); result = p; @@ -1325,6 +1327,19 @@ void os::Posix::init_2(void) { _use_clock_monotonic_condattr ? "CLOCK_MONOTONIC" : "the default clock"); } +int os::Posix::clock_tics_per_second() { + return clock_tics_per_sec; +} + +#ifdef ASSERT +bool os::Posix::ucontext_is_interpreter(const ucontext_t* uc) { + assert(uc != nullptr, "invariant"); + address pc = os::Posix::ucontext_get_pc(uc); + assert(pc != nullptr, "invariant"); + return Interpreter::contains(pc); +} +#endif + // Utility to convert the given timeout to an absolute timespec // (based on the appropriate clock) to use with pthread_cond_timewait, // and sem_timedwait(). @@ -1472,12 +1487,9 @@ jlong os::javaTimeNanos() { return result; } -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) - void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { // CLOCK_MONOTONIC - amount of time since some arbitrary point in the past - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; info_ptr->may_skip_backward = false; // not subject to resetting or drifting info_ptr->may_skip_forward = false; // not subject to resetting or drifting info_ptr->kind = JVMTI_TIMER_ELAPSED; // elapsed not CPU time diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index 248a30d04ad..4b8b75ea07e 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -89,8 +89,13 @@ class os::Posix { static address ucontext_get_pc(const ucontext_t* ctx); static void ucontext_set_pc(ucontext_t* ctx, address pc); + DEBUG_ONLY(static bool ucontext_is_interpreter(const ucontext_t* ctx);) + static void to_RTC_abstime(timespec* abstime, int64_t millis); + // clock ticks per second of the system + static int clock_tics_per_second(); + static bool handle_stack_overflow(JavaThread* thread, address addr, address pc, const void* ucVoid, address* stub); diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index 4d6fc1e4b8c..cbbecea3a6a 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -64,7 +64,7 @@ static char* backing_store_file_name = nullptr; // name of the backing store static char* create_standard_memory(size_t size) { // allocate an aligned chuck of memory - char* mapAddress = os::reserve_memory(size); + char* mapAddress = os::reserve_memory(size, mtInternal); if (mapAddress == nullptr) { return nullptr; diff --git a/src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp b/src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp new file mode 100644 index 00000000000..3ff8c383a31 --- /dev/null +++ b/src/hotspot/os/posix/permitForbiddenFunctions_posix.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_POSIX_PERMITFORBIDDENFUNCTIONS_POSIX_HPP +#define OS_POSIX_PERMITFORBIDDENFUNCTIONS_POSIX_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/globalDefinitions.hpp" + +// Provide wrappers for some functions otherwise forbidden from use in HotSpot. +// See forbiddenFunctions.hpp for details. + +namespace permit_forbidden_function { +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS + +// Used by the POSIX implementation of os::realpath. +inline char* realpath(const char* path, char* resolved_path) { + return ::realpath(path, resolved_path); +} + +END_ALLOW_FORBIDDEN_FUNCTIONS +} // namespace permit_forbidden_function + +#endif // OS_POSIX_PERMITFORBIDDENFUNCTIONS_POSIX_HPP diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 555ac832aae..0157d354f40 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -147,7 +147,7 @@ class SavedSignalHandlers { }; -debug_only(static bool signal_sets_initialized = false); +DEBUG_ONLY(static bool signal_sets_initialized = false); static sigset_t unblocked_sigs, vm_sigs, preinstalled_sigs; // Our own signal handlers should never ever get replaced by a third party one. @@ -1505,6 +1505,14 @@ bool PosixSignals::is_sig_ignored(int sig) { } } +void* PosixSignals::get_signal_handler_for_signal(int sig) { + struct sigaction oact; + if (sigaction(sig, (struct sigaction*)nullptr, &oact) == -1) { + return nullptr; + } + return get_signal_handler(&oact); +} + static void signal_sets_init() { sigemptyset(&preinstalled_sigs); @@ -1547,7 +1555,7 @@ static void signal_sets_init() { if (!ReduceSignalUsage) { sigaddset(&vm_sigs, BREAK_SIGNAL); } - debug_only(signal_sets_initialized = true); + DEBUG_ONLY(signal_sets_initialized = true); } // These are signals that are unblocked while a thread is running Java. diff --git a/src/hotspot/os/posix/signals_posix.hpp b/src/hotspot/os/posix/signals_posix.hpp index 9deade4db18..c1cb70df153 100644 --- a/src/hotspot/os/posix/signals_posix.hpp +++ b/src/hotspot/os/posix/signals_posix.hpp @@ -52,6 +52,8 @@ class PosixSignals : public AllStatic { static bool is_sig_ignored(int sig); + static void* get_signal_handler_for_signal(int sig); + static void hotspot_sigmask(Thread* thread); static void print_signal_handler(outputStream* st, int sig, char* buf, size_t buflen); diff --git a/src/hotspot/os/posix/threadCritical_posix.cpp b/src/hotspot/os/posix/threadCritical_posix.cpp deleted file mode 100644 index 47fe98c7429..00000000000 --- a/src/hotspot/os/posix/threadCritical_posix.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2001, 2025, 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. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 "runtime/javaThread.hpp" -#include "runtime/threadCritical.hpp" -#include "utilities/compilerWarnings.hpp" - -// put OS-includes here -# include - -// -// See threadCritical.hpp for details of this class. -// - -static pthread_t tc_owner = 0; - -PRAGMA_DIAG_PUSH -PRAGMA_ZERO_AS_NULL_POINTER_CONSTANT_IGNORED -static pthread_mutex_t tc_mutex = PTHREAD_MUTEX_INITIALIZER; -PRAGMA_DIAG_POP - -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/windows/attachListener_windows.cpp b/src/hotspot/os/windows/attachListener_windows.cpp index 2cc9d192ce5..10873a652f4 100644 --- a/src/hotspot/os/windows/attachListener_windows.cpp +++ b/src/hotspot/os/windows/attachListener_windows.cpp @@ -64,6 +64,11 @@ class PipeChannel : public AttachOperation::RequestReader, public AttachOperation::ReplyWriter { private: HANDLE _hPipe; + void close_impl() { + FlushFileBuffers(_hPipe); + CloseHandle(_hPipe); + _hPipe = INVALID_HANDLE_VALUE; + } public: PipeChannel() : _hPipe(INVALID_HANDLE_VALUE) {} ~PipeChannel() { @@ -92,10 +97,14 @@ class PipeChannel : public AttachOperation::RequestReader, public AttachOperatio void close() { if (opened()) { - ThreadBlockInVM tbivm(JavaThread::current()); - FlushFileBuffers(_hPipe); - CloseHandle(_hPipe); - _hPipe = INVALID_HANDLE_VALUE; + JavaThread* current = JavaThread::current(); + // if we fail to read/parse request from Win32AttachListener::dequeue, current thread is already blocked + if (current->thread_state() == _thread_blocked) { + close_impl(); + } else { + ThreadBlockInVM tbivm(current); + close_impl(); + } } } diff --git a/src/hotspot/os/windows/forbiddenFunctions_windows.hpp b/src/hotspot/os/windows/forbiddenFunctions_windows.hpp new file mode 100644 index 00000000000..81599522ed4 --- /dev/null +++ b/src/hotspot/os/windows/forbiddenFunctions_windows.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_WINDOWS_FORBIDDENFUNCTIONS_WINDOWS_HPP +#define OS_WINDOWS_FORBIDDENFUNCTIONS_WINDOWS_HPP + +#include "utilities/compilerWarnings.hpp" + +#include // for size_t + +// _fullpath with a null first argument mallocs a string for the result. +FORBID_IMPORTED_C_FUNCTION(char* _fullpath(char*, const char*, size_t), "use os::realpath"); + +// _snprintf does NOT null terminate if the output would exceed the buffer size. +FORBID_C_FUNCTION(int _snprintf(char*, size_t, const char*, ...), "use os::snprintf"); + +#endif // OS_WINDOWS_FORBIDDENFUNCTIONS_WINDOWS_HPP diff --git a/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp b/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp index d6174de7d88..3d20fa5a924 100644 --- a/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp +++ b/src/hotspot/os/windows/gc/z/zSyscall_windows.hpp @@ -27,7 +27,6 @@ #include "utilities/globalDefinitions.hpp" #include -#include class ZSyscall { private: diff --git a/src/hotspot/os/windows/memMapPrinter_windows.cpp b/src/hotspot/os/windows/memMapPrinter_windows.cpp index 075a64f5863..9388d20ab56 100644 --- a/src/hotspot/os/windows/memMapPrinter_windows.cpp +++ b/src/hotspot/os/windows/memMapPrinter_windows.cpp @@ -26,6 +26,7 @@ #include "nmt/memMapPrinter.hpp" #include "os_windows.hpp" #include "runtime/vm_version.hpp" +#include "utilities/ostream.hpp" #include #include @@ -200,7 +201,7 @@ class MappingInfoPrinter { st->print_cr("vminfo: VM information (requires NMT)"); st->print_cr("file: file mapped, if mapping is not anonymous"); { - streamIndentor si(st, 16); + StreamIndentor si(st, 16); _session.print_nmt_flag_legend(); } } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 84e89334feb..9e536d2df97 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -60,10 +60,8 @@ #include "runtime/safepointMechanism.hpp" #include "runtime/semaphore.inline.hpp" #include "runtime/sharedRuntime.hpp" -#include "runtime/statSampler.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/suspendedThreadTask.hpp" -#include "runtime/threadCritical.hpp" #include "runtime/threads.hpp" #include "runtime/timer.hpp" #include "runtime/vm_version.hpp" @@ -76,6 +74,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/macros.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "utilities/population_count.hpp" #include "utilities/vmError.hpp" #include "windbghelp.hpp" @@ -111,9 +110,6 @@ #include #include -// for timer info max values which include all bits -#define ALL_64_BITS CONST64(-1) - // For DLL loading/load error detection // Values of PE COFF #define IMAGE_FILE_PTR_TO_SIGNATURE 0x3c @@ -760,8 +756,9 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, const unsigned initflag = CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION; HANDLE thread_handle; - int limit = 3; - do { + int trials_remaining = 4; + DWORD next_delay_ms = 1; + while (true) { thread_handle = (HANDLE)_beginthreadex(nullptr, (unsigned)stack_size, @@ -769,7 +766,23 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, thread, initflag, &thread_id); - } while (thread_handle == nullptr && errno == EAGAIN && limit-- > 0); + + if (thread_handle != nullptr) { + break; + } + + if (errno != EAGAIN) { + break; + } + + if (--trials_remaining <= 0) { + break; + } + + log_debug(os, thread)("Failed to start native thread (%s), retrying after %dms.", os::errno_name(errno), next_delay_ms); + Sleep(next_delay_ms); + next_delay_ms *= 2; + } ResourceMark rm; char buf[64]; @@ -1224,16 +1237,16 @@ void os::javaTimeNanos_info(jvmtiTimerInfo *info_ptr) { if (freq < NANOSECS_PER_SEC) { // the performance counter is 64 bits and we will // be multiplying it -- so no wrap in 64 bits - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; } else if (freq > NANOSECS_PER_SEC) { // use the max value the counter can reach to // determine the max value which could be returned - julong max_counter = (julong)ALL_64_BITS; + julong max_counter = (julong)all_bits_jlong; info_ptr->max_value = (jlong)(max_counter / (freq / NANOSECS_PER_SEC)); } else { // the performance counter is 64 bits and we will // be using it directly -- so no wrap in 64 bits - info_ptr->max_value = ALL_64_BITS; + info_ptr->max_value = all_bits_jlong; } // using a counter, so no skipping @@ -3019,7 +3032,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, PAGE_READWRITE); // If reservation failed, return null if (p_buf == nullptr) return nullptr; - MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)p_buf, size_of_reserve, CALLER_PC, mtNone); os::release_memory(p_buf, bytes + chunk_size); // we still need to round up to a page boundary (in case we are using large pages) @@ -3080,7 +3093,7 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, // need to create a dummy 'reserve' record to match // the release. MemTracker::record_virtual_memory_reserve((address)p_buf, - bytes_to_release, CALLER_PC); + bytes_to_release, CALLER_PC, mtNone); os::release_memory(p_buf, bytes_to_release); } #ifdef ASSERT @@ -3098,9 +3111,9 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, // Although the memory is allocated individually, it is returned as one. // NMT records it as one block. if ((flags & MEM_COMMIT) != 0) { - MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)p_buf, bytes, CALLER_PC, mtNone); } else { - MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve((address)p_buf, bytes, CALLER_PC, mtNone); } // made it this far, success @@ -3240,7 +3253,7 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in // Multiple threads can race in this code but it's not possible to unmap small sections of // virtual space to get requested alignment, like posix-like os's. // Windows prevents multiple thread from remapping over each other so this loop is thread-safe. -static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag = mtNone) { +static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc, MemTag mem_tag) { assert(is_aligned(alignment, os::vm_allocation_granularity()), "Alignment must be a multiple of allocation granularity (page size)"); assert(is_aligned(size, os::vm_allocation_granularity()), @@ -3254,7 +3267,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi for (int attempt = 0; attempt < max_attempts && aligned_base == nullptr; attempt ++) { char* extra_base = file_desc != -1 ? os::map_memory_to_file(extra_size, file_desc, mem_tag) : - os::reserve_memory(extra_size, false, mem_tag); + os::reserve_memory(extra_size, mem_tag); if (extra_base == nullptr) { return nullptr; } @@ -3271,7 +3284,7 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi // Attempt to map, into the just vacated space, the slightly smaller aligned area. // Which may fail, hence the loop. aligned_base = file_desc != -1 ? os::attempt_map_memory_to_file_at(aligned_base, size, file_desc, mem_tag) : - os::attempt_reserve_memory_at(aligned_base, size, false, mem_tag); + os::attempt_reserve_memory_at(aligned_base, size, mem_tag); } assert(aligned_base != nullptr, @@ -3280,9 +3293,9 @@ static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fi return aligned_base; } -char* os::reserve_memory_aligned(size_t size, size_t alignment, bool exec) { +char* os::reserve_memory_aligned(size_t size, size_t alignment, MemTag mem_tag, bool exec) { // exec can be ignored - return map_or_reserve_memory_aligned(size, alignment, -1 /* file_desc */); + return map_or_reserve_memory_aligned(size, alignment, -1/* file_desc */, mem_tag); } char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd, MemTag mem_tag) { @@ -4358,9 +4371,9 @@ static void exit_process_or_thread(Ept what, int exit_code) { if (what == EPT_THREAD) { _endthreadex((unsigned)exit_code); } else if (what == EPT_PROCESS) { - ALLOW_C_FUNCTION(::exit, ::exit(exit_code);) + permit_forbidden_function::exit(exit_code); } else { // EPT_PROCESS_DIE - ALLOW_C_FUNCTION(::_exit, ::_exit(exit_code);) + permit_forbidden_function::_exit(exit_code); } // Should not reach here @@ -4612,6 +4625,63 @@ static void set_path_prefix(char* buf, LPCWSTR* prefix, int* prefix_off, bool* n } } +// This method checks if a wide path is actually a symbolic link +static bool is_symbolic_link(const wchar_t* wide_path) { + WIN32_FIND_DATAW fd; + HANDLE f = ::FindFirstFileW(wide_path, &fd); + if (f != INVALID_HANDLE_VALUE) { + const bool result = fd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT && fd.dwReserved0 == IO_REPARSE_TAG_SYMLINK; + if (::FindClose(f) == 0) { + errno = ::GetLastError(); + log_debug(os)("is_symbolic_link() failed to FindClose: GetLastError->%ld.", errno); + } + return result; + } else { + errno = ::GetLastError(); + log_debug(os)("is_symbolic_link() failed to FindFirstFileW: GetLastError->%ld.", errno); + return false; + } +} + +// This method dereferences a symbolic link +static WCHAR* get_path_to_target(const wchar_t* wide_path) { + HANDLE hFile = CreateFileW(wide_path, GENERIC_READ, FILE_SHARE_READ, nullptr, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile == INVALID_HANDLE_VALUE) { + errno = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to CreateFileW: GetLastError->%ld.", errno); + return nullptr; + } + + // Returned value includes the terminating null character. + const size_t target_path_size = ::GetFinalPathNameByHandleW(hFile, nullptr, 0, + FILE_NAME_NORMALIZED); + if (target_path_size == 0) { + errno = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%ld.", errno); + return nullptr; + } + + WCHAR* path_to_target = NEW_C_HEAP_ARRAY(WCHAR, target_path_size, mtInternal); + + // The returned size is the length excluding the terminating null character. + const size_t res = ::GetFinalPathNameByHandleW(hFile, path_to_target, static_cast(target_path_size), + FILE_NAME_NORMALIZED); + if (res != target_path_size - 1) { + errno = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to GetFinalPathNameByHandleW: GetLastError->%ld.", errno); + return nullptr; + } + + if (::CloseHandle(hFile) == 0) { + errno = ::GetLastError(); + log_debug(os)("get_path_to_target() failed to CloseHandle: GetLastError->%ld.", errno); + return nullptr; + } + + return path_to_target; +} + // Returns the given path as an absolute wide path in unc format. The returned path is null // on error (with err being set accordingly) and should be freed via os::free() otherwise. // additional_space is the size of space, in wchar_t, the function will additionally add to @@ -4680,15 +4750,35 @@ int os::stat(const char *path, struct stat *sbuf) { return -1; } + const bool is_symlink = is_symbolic_link(wide_path); + WCHAR* path_to_target = nullptr; + + if (is_symlink) { + path_to_target = get_path_to_target(wide_path); + if (path_to_target == nullptr) { + // it is a symbolic link, but we failed to resolve it, + // errno has been set in the call to get_path_to_target(), + // no need to overwrite it + os::free(wide_path); + return -1; + } + } + WIN32_FILE_ATTRIBUTE_DATA file_data;; - BOOL bret = ::GetFileAttributesExW(wide_path, GetFileExInfoStandard, &file_data); - os::free(wide_path); + BOOL bret = ::GetFileAttributesExW(is_symlink ? path_to_target : wide_path, GetFileExInfoStandard, &file_data); + // if getting attributes failed, GetLastError should be called immediately after that if (!bret) { errno = ::GetLastError(); + log_debug(os)("os::stat() failed to GetFileAttributesExW: GetLastError->%ld.", errno); + os::free(wide_path); + os::free(path_to_target); return -1; } + os::free(wide_path); + os::free(path_to_target); + file_attribute_data_to_stat(sbuf, file_data); return 0; } @@ -4812,14 +4902,14 @@ jlong os::thread_cpu_time(Thread* thread, bool user_sys_cpu_time) { } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // the max value -- all 64 bits + info_ptr->max_value = all_bits_jlong; // the max value -- all 64 bits info_ptr->may_skip_backward = false; // GetThreadTimes returns absolute time info_ptr->may_skip_forward = false; // GetThreadTimes returns absolute time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned } void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { - info_ptr->max_value = ALL_64_BITS; // the max value -- all 64 bits + info_ptr->max_value = all_bits_jlong; // the max value -- all 64 bits info_ptr->may_skip_backward = false; // GetThreadTimes returns absolute time info_ptr->may_skip_forward = false; // GetThreadTimes returns absolute time info_ptr->kind = JVMTI_TIMER_TOTAL_CPU; // user+system time is returned @@ -4873,12 +4963,30 @@ int os::open(const char *path, int oflag, int mode) { errno = err; return -1; } - int fd = ::_wopen(wide_path, oflag | O_BINARY | O_NOINHERIT, mode); - os::free(wide_path); + const bool is_symlink = is_symbolic_link(wide_path); + WCHAR* path_to_target = nullptr; + + if (is_symlink) { + path_to_target = get_path_to_target(wide_path); + if (path_to_target == nullptr) { + // it is a symbolic link, but we failed to resolve it, + // errno has been set in the call to get_path_to_target(), + // no need to overwrite it + os::free(wide_path); + return -1; + } + } + + int fd = ::_wopen(is_symlink ? path_to_target : wide_path, oflag | O_BINARY | O_NOINHERIT, mode); + + // if opening files failed, GetLastError should be called immediately after that if (fd == -1) { errno = ::GetLastError(); + log_debug(os)("os::open() failed to _wopen: GetLastError->%ld.", errno); } + os::free(wide_path); + os::free(path_to_target); return fd; } @@ -5131,7 +5239,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } char* result = nullptr; - ALLOW_C_FUNCTION(::_fullpath, char* p = ::_fullpath(nullptr, filename, 0);) + char* p = permit_forbidden_function::_fullpath(nullptr, filename, 0); if (p != nullptr) { if (strlen(p) < outbuflen) { strcpy(outbuf, p); @@ -5139,7 +5247,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } - ALLOW_C_FUNCTION(::free, ::free(p);) // *not* os::free + permit_forbidden_function::free(p); // *not* os::free } return result; } @@ -5187,7 +5295,7 @@ char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, } // Record virtual memory allocation - MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC); + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, CALLER_PC, mtNone); DWORD bytes_read; OVERLAPPED overlapped; @@ -5731,61 +5839,34 @@ ssize_t os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { return ::send(fd, buf, (int)nBytes, flags); } -// returns true if thread could be suspended, -// false otherwise -static bool do_suspend(HANDLE* h) { - if (h != nullptr) { - if (SuspendThread(*h) != ~0) { - return true; - } - } - return false; -} - -// resume the thread -// calling resume on an active thread is a no-op -static void do_resume(HANDLE* h) { - if (h != nullptr) { - ResumeThread(*h); - } -} +// WINDOWS CONTEXT Flags for THREAD_SAMPLING +#if defined(AMD64) || defined(_M_ARM64) + #define sampling_context_flags (CONTEXT_FULL | CONTEXT_FLOATING_POINT) +#endif -// retrieve a suspend/resume context capable handle -// from the tid. Caller validates handle return value. -void get_thread_handle_for_extended_context(HANDLE* h, - DWORD tid) { - if (h != nullptr) { - *h = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, tid); - } +// Retrieve a suspend/resume context capable handle for the tid. +// Caller validates handle return value. +static inline HANDLE get_thread_handle_for_extended_context(DWORD tid) { + return OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, tid); } // Thread sampling implementation // void SuspendedThreadTask::internal_do_task() { - CONTEXT ctxt; - HANDLE h = nullptr; - - // get context capable handle for thread - get_thread_handle_for_extended_context(&h, _thread->osthread()->thread_id()); - - // sanity - if (h == nullptr || h == INVALID_HANDLE_VALUE) { + const HANDLE h = get_thread_handle_for_extended_context(_thread->osthread()->thread_id()); + if (h == nullptr) { return; } - - // suspend the thread - if (do_suspend(&h)) { - ctxt.ContextFlags = (CONTEXT_FULL | CONTEXT_FLOATING_POINT); - // get thread context - GetThreadContext(h, &ctxt); - SuspendedThreadTaskContext context(_thread, &ctxt); - // pass context to Thread Sampling impl - do_task(context); - // resume thread - do_resume(&h); + CONTEXT ctxt; + ctxt.ContextFlags = sampling_context_flags; + if (SuspendThread(h) != OS_ERR) { + if (GetThreadContext(h, &ctxt)) { + const SuspendedThreadTaskContext context(_thread, &ctxt); + // Pass context to Thread Sampling implementation. + do_task(context); + } + ResumeThread(h); } - - // close handle CloseHandle(h); } diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index dda0acde793..273814f6572 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -54,7 +54,7 @@ typedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)( static char* create_standard_memory(size_t size) { // allocate an aligned chuck of memory - char* mapAddress = os::reserve_memory(size); + char* mapAddress = os::reserve_memory(size, mtInternal); if (mapAddress == nullptr) { return nullptr; @@ -1606,10 +1606,8 @@ static void open_file_mapping(int vmid, char** addrp, size_t* sizep, TRAPS) { // using resource arrays for these names prevents the leaks // that would otherwise occur. // - char* rfilename = NEW_RESOURCE_ARRAY(char, strlen(filename) + 1); - char* robjectname = NEW_RESOURCE_ARRAY(char, strlen(objectname) + 1); - strcpy(rfilename, filename); - strcpy(robjectname, objectname); + char* rfilename = ResourceArea::strdup(THREAD, filename); + char* robjectname = ResourceArea::strdup(THREAD, objectname); // free the c heap resources that are no longer needed FREE_C_HEAP_ARRAY(char, luser); diff --git a/src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp b/src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp new file mode 100644 index 00000000000..99e77464fbd --- /dev/null +++ b/src/hotspot/os/windows/permitForbiddenFunctions_windows.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef OS_WINDOWS_PERMITFORBIDDENFUNCTIONS_WINDOWS_HPP +#define OS_WINDOWS_PERMITFORBIDDENFUNCTIONS_WINDOWS_HPP + +#include "utilities/compilerWarnings.hpp" +#include "utilities/globalDefinitions.hpp" + +// Provide wrappers for some functions otherwise forbidden from use in HotSpot. +// See forbiddenFunctions.hpp for details. + +namespace permit_forbidden_function { +BEGIN_ALLOW_FORBIDDEN_FUNCTIONS + +// Used by the Windows implementation of os::realpath. +inline char* _fullpath(char* absPath, const char* relPath, size_t maxLength) { + return ::_fullpath(absPath, relPath, maxLength); +} + +END_ALLOW_FORBIDDEN_FUNCTIONS +} // namespace permit_forbidden_function + +#endif // OS_WINDOWS_PERMITFORBIDDENFUNCTIONS_WINDOWS_HPP diff --git a/src/hotspot/os/windows/symbolengine.cpp b/src/hotspot/os/windows/symbolengine.cpp index 83cb930f7bf..8f6f6cf09c6 100644 --- a/src/hotspot/os/windows/symbolengine.cpp +++ b/src/hotspot/os/windows/symbolengine.cpp @@ -26,6 +26,7 @@ #include "symbolengine.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" +#include "utilities/permitForbiddenFunctions.hpp" #include "windbghelp.hpp" #include @@ -102,7 +103,7 @@ class SimpleBufferWithFallback { virtual void initialize () { assert(_p == nullptr && _capacity == 0, "Only call once."); const size_t bytes = OPTIMAL_CAPACITY * sizeof(T); - T* q = (T*) ::malloc(bytes); + T* q = (T*) permit_forbidden_function::malloc(bytes); if (q != nullptr) { _p = q; _capacity = OPTIMAL_CAPACITY; @@ -118,7 +119,7 @@ class SimpleBufferWithFallback { // case, where two buffers need to be of identical capacity. void reset_to_fallback_capacity() { if (_p != _fallback_buffer) { - ::free(_p); + permit_forbidden_function::free(_p); } _p = _fallback_buffer; _capacity = (int)(sizeof(_fallback_buffer) / sizeof(T)); diff --git a/src/hotspot/os/windows/threadCritical_windows.cpp b/src/hotspot/os/windows/threadCritical_windows.cpp deleted file mode 100644 index 35aa0839089..00000000000 --- a/src/hotspot/os/windows/threadCritical_windows.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please 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 "runtime/atomic.hpp" -#include "runtime/javaThread.hpp" -#include "runtime/threadCritical.hpp" - -// OS-includes here -# include -# include - -// -// See threadCritical.hpp for details of this class. -// - -static INIT_ONCE initialized = INIT_ONCE_STATIC_INIT; -static int lock_count = 0; -static HANDLE lock_event; -static DWORD lock_owner = 0; - -// -// Note that Microsoft's critical region code contains a race -// condition, and is not suitable for use. A thread holding the -// critical section cannot safely suspend a thread attempting -// to enter the critical region. The failure mode is that both -// threads are permanently suspended. -// -// I experiemented with the use of ordinary windows mutex objects -// and found them ~30 times slower than the critical region code. -// - -static BOOL WINAPI initialize(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) { - lock_event = CreateEvent(nullptr, false, true, nullptr); - assert(lock_event != nullptr, "unexpected return value from CreateEvent"); - return true; -} - -ThreadCritical::ThreadCritical() { - InitOnceExecuteOnce(&initialized, &initialize, nullptr, nullptr); - - DWORD current_thread = GetCurrentThreadId(); - if (lock_owner != current_thread) { - // Grab the lock before doing anything. - DWORD ret = WaitForSingleObject(lock_event, INFINITE); - assert(ret != WAIT_FAILED, "WaitForSingleObject failed with error code: %lu", GetLastError()); - assert(ret == WAIT_OBJECT_0, "WaitForSingleObject failed with return value: %lu", ret); - lock_owner = current_thread; - } - // Atomicity isn't required. Bump the recursion count. - lock_count++; -} - -ThreadCritical::~ThreadCritical() { - assert(lock_owner == GetCurrentThreadId(), "unlock attempt by wrong thread"); - assert(lock_count >= 0, "Attempt to unlock when already unlocked"); - - lock_count--; - if (lock_count == 0) { - // We're going to unlock - lock_owner = 0; - // No lost wakeups, lock_event stays signaled until reset. - DWORD ret = SetEvent(lock_event); - assert(ret != 0, "unexpected return value from SetEvent"); - } -} diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index 3d11bfe037a..3dbb8adddd6 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -138,6 +138,13 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { return frame(sp, lr, frame::kind::unknown); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + assert(ucVoid != nullptr, "invariant"); + const ucontext_t* uc = (const ucontext_t*)ucVoid; + assert(os::Posix::ucontext_is_interpreter(uc), "invariant"); + return reinterpret_cast(uc->uc_mcontext.jmp_context.gpr[14]); // R14_bcp +} + frame os::get_sender_for_C_frame(frame* fr) { if (*fr->sp() == (intptr_t) nullptr) { // fr is the last C frame diff --git a/src/hotspot/os_cpu/bsd_aarch64/icache_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/icache_bsd_aarch64.hpp index 7e9ca43efcf..8b942730ae2 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/icache_bsd_aarch64.hpp +++ b/src/hotspot/os_cpu/bsd_aarch64/icache_bsd_aarch64.hpp @@ -33,7 +33,7 @@ class ICache : public AbstractICache { public: - static void initialize(); + static void initialize(int phase); static void invalidate_word(address addr) { __clear_cache((char *)addr, (char *)(addr + 4)); } diff --git a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp index 7b35317882d..ad32ee150e8 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp @@ -81,14 +81,12 @@ #endif #define SPELL_REG_SP "sp" -#define SPELL_REG_FP "fp" #ifdef __APPLE__ // see darwin-xnu/osfmk/mach/arm/_structs.h // 10.5 UNIX03 member name prefixes #define DU3_PREFIX(s, m) __ ## s.__ ## m -#endif #define context_x uc_mcontext->DU3_PREFIX(ss,x) #define context_fp uc_mcontext->DU3_PREFIX(ss,fp) @@ -97,6 +95,33 @@ #define context_pc uc_mcontext->DU3_PREFIX(ss,pc) #define context_cpsr uc_mcontext->DU3_PREFIX(ss,cpsr) #define context_esr uc_mcontext->DU3_PREFIX(es,esr) +#endif + +#ifdef __FreeBSD__ +# define context_x uc_mcontext.mc_gpregs.gp_x +# define context_fp context_x[REG_FP] +# define context_lr uc_mcontext.mc_gpregs.gp_lr +# define context_sp uc_mcontext.mc_gpregs.gp_sp +# define context_pc uc_mcontext.mc_gpregs.gp_elr +#endif + +#ifdef __NetBSD__ +# define context_x uc_mcontext.__gregs +# define context_fp uc_mcontext.__gregs[_REG_FP] +# define context_lr uc_mcontext.__gregs[_REG_LR] +# define context_sp uc_mcontext.__gregs[_REG_SP] +# define context_pc uc_mcontext.__gregs[_REG_ELR] +#endif + +#ifdef __OpenBSD__ +# define context_x sc_x +# define context_fp sc_x[REG_FP] +# define context_lr sc_lr +# define context_sp sc_sp +# define context_pc sc_elr +#endif + +#define REG_BCP context_x[22] address os::current_stack_pointer() { #if defined(__clang__) || defined(__llvm__) @@ -179,6 +204,13 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { return frame(sp, fp, pc); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + assert(ucVoid != nullptr, "invariant"); + const ucontext_t* uc = (const ucontext_t*)ucVoid; + assert(os::Posix::ucontext_is_interpreter(uc), "invariant"); + return reinterpret_cast(uc->REG_BCP); +} + // JVM compiled with -fno-omit-frame-pointer, so RFP is saved on the stack. frame os::get_sender_for_C_frame(frame* fr) { return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); @@ -271,11 +303,8 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, stub = SharedRuntime::handle_unsafe_access(thread, next_pc); } } else if (sig == SIGILL && nativeInstruction_at(pc)->is_stop()) { - // Pull a pointer to the error message out of the instruction - // stream. - const uint64_t *detail_msg_ptr - = (uint64_t*)(pc + NativeInstruction::instruction_size); - const char *detail_msg = (const char *)*detail_msg_ptr; + // A pointer to the message will have been placed in r0 + const char *detail_msg = (const char *)(uc->uc_mcontext->DU3_PREFIX(ss,x[0])); const char *msg = "stop"; if (TraceTraps) { tty->print_cr("trap: %s: (SIGILL)", msg); @@ -491,9 +520,11 @@ int os::extra_bang_size_in_bytes() { return 0; } +#ifdef __APPLE__ void os::current_thread_enable_wx(WXMode mode) { pthread_jit_write_protect_np(mode == WXExec); } +#endif static inline void atomic_copy64(const volatile void *src, volatile void *dst) { *(jlong *) dst = *(const jlong *) src; diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp index d11e7d8b90b..1a7063198e3 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -89,6 +89,7 @@ #ifdef AMD64 #define SPELL_REG_SP "rsp" #define SPELL_REG_FP "rbp" +#define REG_BCP context_r13 #else #define SPELL_REG_SP "esp" #define SPELL_REG_FP "ebp" @@ -349,6 +350,13 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { return frame(fr.sp() + 1, fr.fp(), (address)*(fr.sp())); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + assert(ucVoid != nullptr, "invariant"); + const ucontext_t* uc = (const ucontext_t*)ucVoid; + assert(os::Posix::ucontext_is_interpreter(uc), "invariant"); + return reinterpret_cast(uc->REG_BCP); +} + // By default, gcc always save frame pointer (%ebp/%rbp) on stack. It may get // turned off by -fomit-frame-pointer, frame os::get_sender_for_C_frame(frame* fr) { diff --git a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp index 29efae1adc8..3fefbdbe56c 100644 --- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp @@ -109,6 +109,11 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + ShouldNotCallThis(); + return nullptr; +} + bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ucontext_t* uc, JavaThread* thread) { diff --git a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp index 75ca68e43fb..957be266702 100644 --- a/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/icache_linux_aarch64.hpp @@ -32,7 +32,7 @@ class ICache : public AbstractICache { public: - static void initialize(); + static void initialize(int phase); static void invalidate_word(address addr) { __builtin___clear_cache((char *)addr, (char *)(addr + 4)); } 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 7728c62682c..6900283418d 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -75,6 +75,7 @@ #define REG_FP 29 #define REG_LR 30 +#define REG_BCP 22 NOINLINE address os::current_stack_pointer() { return (address)__builtin_frame_address(0); @@ -148,6 +149,13 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { return frame(sp, fp, pc); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + assert(ucVoid != nullptr, "invariant"); + const ucontext_t* uc = (const ucontext_t*)ucVoid; + assert(os::Posix::ucontext_is_interpreter(uc), "invariant"); + return reinterpret_cast(uc->uc_mcontext.regs[REG_BCP]); +} + // By default, gcc always saves frame pointer rfp on this stack. This // may get turned off by -fomit-frame-pointer. // The "Procedure Call Standard for the Arm 64-bit Architecture" doesn't @@ -248,11 +256,8 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, stub = SharedRuntime::handle_unsafe_access(thread, next_pc); } } else if (sig == SIGILL && nativeInstruction_at(pc)->is_stop()) { - // Pull a pointer to the error message out of the instruction - // stream. - const uint64_t *detail_msg_ptr - = (uint64_t*)(pc + NativeInstruction::instruction_size); - const char *detail_msg = (const char *)*detail_msg_ptr; + // A pointer to the message will have been placed in r0 + const char *detail_msg = (const char *)(uc->uc_mcontext.regs[0]); const char *msg = "stop"; if (TraceTraps) { tty->print_cr("trap: %s: (SIGILL)", msg); 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 dabc69403f3..9725c6cd6c0 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 @@ -75,6 +75,14 @@ #define HWCAP_PACA (1 << 30) #endif +#ifndef HWCAP_FPHP +#define HWCAP_FPHP (1<<9) +#endif + +#ifndef HWCAP_ASIMDHP +#define HWCAP_ASIMDHP (1<<10) +#endif + #ifndef HWCAP2_SVE2 #define HWCAP2_SVE2 (1 << 1) #endif @@ -119,6 +127,8 @@ void VM_Version::get_os_cpu_info() { 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"); + static_assert(CPU_FPHP == HWCAP_FPHP, "Flag CPU_FPHP must follow Linux HWCAP"); + static_assert(CPU_ASIMDHP == HWCAP_ASIMDHP, "Flag CPU_ASIMDHP must follow Linux HWCAP"); _features = auxv & ( HWCAP_FP | HWCAP_ASIMD | @@ -133,7 +143,9 @@ void VM_Version::get_os_cpu_info() { HWCAP_SHA3 | HWCAP_SHA512 | HWCAP_SVE | - HWCAP_PACA); + HWCAP_PACA | + HWCAP_FPHP | + HWCAP_ASIMDHP); if (auxv2 & HWCAP2_SVE2) _features |= CPU_SVE2; if (auxv2 & HWCAP2_SVEBITPERM) _features |= CPU_SVEBITPERM; diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp index 5723e86f859..6c245f8f1a6 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -208,6 +208,11 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { return frame(sp, fp, pc); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + Unimplemented(); + return nullptr; +} + frame os::get_sender_for_C_frame(frame* fr) { #ifdef __thumb__ // We can't reliably get anything from a thumb C frame. diff --git a/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp index 41f1d85a2f2..1e4eb37cdac 100644 --- a/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp +++ b/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp @@ -246,53 +246,30 @@ inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest, // specified otherwise (see atomic.hpp). // Using 32 bit internally. - volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3); - -#ifdef VM_LITTLE_ENDIAN - const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8; -#else - const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8; -#endif - const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value), - masked_exchange_val = ((unsigned int)(unsigned char)exchange_value), - xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount; - - unsigned int old_value, value32; - + unsigned int old_value, loaded_value; pre_membar(order); __asm__ __volatile__ ( - /* simple guard */ - " lbz %[old_value], 0(%[dest]) \n" - " cmpw %[masked_compare_val], %[old_value] \n" - " bne- 2f \n" /* atomic loop */ "1: \n" - " lwarx %[value32], 0, %[dest_base] \n" + " lbarx %[old_value], 0, %[dest] \n" /* extract byte and compare */ - " srd %[old_value], %[value32], %[shift_amount] \n" - " clrldi %[old_value], %[old_value], 56 \n" - " cmpw %[masked_compare_val], %[old_value] \n" + " cmpw %[compare_value], %[old_value] \n" " bne- 2f \n" /* replace byte and try to store */ - " xor %[value32], %[xor_value], %[value32] \n" - " stwcx. %[value32], 0, %[dest_base] \n" + " stbcx. %[exchange_value], 0, %[dest] \n" " bne- 1b \n" /* exit */ "2: \n" /* out */ : [old_value] "=&r" (old_value), - [value32] "=&r" (value32), - "=m" (*dest), - "=m" (*dest_base) + [loaded_value] "=&r" (loaded_value), + "=m" (*dest) /* in */ - : [dest] "b" (dest), - [dest_base] "b" (dest_base), - [shift_amount] "r" (shift_amount), - [masked_compare_val] "r" (masked_compare_val), - [xor_value] "r" (xor_value), - "m" (*dest), - "m" (*dest_base) + : [dest] "b" (dest), + [compare_value] "r" (compare_value), + [exchange_value] "r" (exchange_value), + "m" (*dest) /* clobber */ : "cc", "memory" diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp index 81fede02956..5fe37be0d20 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp @@ -170,6 +170,13 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { return frame(sp, lr, frame::kind::unknown); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + assert(ucVoid != nullptr, "invariant"); + const ucontext_t* uc = (const ucontext_t*)ucVoid; + assert(os::Posix::ucontext_is_interpreter(uc), "invariant"); + return reinterpret_cast(uc->uc_mcontext.regs->gpr[14]); // R14_bcp +} + frame os::get_sender_for_C_frame(frame* fr) { if (*fr->sp() == 0) { // fr is the last C frame diff --git a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp index 945280bca10..8366a7249fa 100644 --- a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp @@ -77,6 +77,7 @@ #define REG_LR 1 #define REG_FP 8 +#define REG_BCP 22 NOINLINE address os::current_stack_pointer() { return (address)__builtin_frame_address(0); @@ -157,6 +158,13 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(frame_sp, frame_fp, epc); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + assert(ucVoid != nullptr, "invariant"); + const ucontext_t* uc = (const ucontext_t*)ucVoid; + assert(os::Posix::ucontext_is_interpreter(uc), "invariant"); + return reinterpret_cast(uc->uc_mcontext.__gregs[REG_BCP]); +} + // By default, gcc always saves frame pointer rfp on this stack. This // may get turned off by -fomit-frame-pointer. frame os::get_sender_for_C_frame(frame* fr) { diff --git a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp index 06d6aaf109f..d19128cafc2 100644 --- a/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp +++ b/src/hotspot/os_cpu/linux_riscv/riscv_hwprobe.cpp @@ -233,10 +233,13 @@ void RiscvHwprobe::add_features_from_query_result() { if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZACAS)) { VM_Version::ext_Zacas.enable_feature(); } -#endif + // Currently tests shows that cmove using Zicond instructions will bring + // performance regression, but to get a test coverage all the time, will + // still prefer to enabling it in debug version. if (is_set(RISCV_HWPROBE_KEY_IMA_EXT_0, RISCV_HWPROBE_EXT_ZICOND)) { VM_Version::ext_Zicond.enable_feature(); } +#endif if (is_valid(RISCV_HWPROBE_KEY_CPUPERF_0)) { VM_Version::unaligned_access.enable_feature( query[RISCV_HWPROBE_KEY_CPUPERF_0].value & RISCV_HWPROBE_MISALIGNED_MASK); diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index b6095c279cb..506c78cacca 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -129,6 +129,9 @@ void VM_Version::setup_cpu_available_features() { snprintf(buf, sizeof(buf)/2, "%s ", uarch); } os::free((void*) uarch); + + int features_offset = strnlen(buf, sizeof(buf)); + strcat(buf, "rv64"); int i = 0; while (_feature_list[i] != nullptr) { @@ -191,7 +194,9 @@ void VM_Version::setup_cpu_available_features() { } } - _features_string = os::strdup(buf); + _cpu_info_string = os::strdup(buf); + + _features_string = _cpu_info_string + features_offset; } void VM_Version::os_aux_features() { diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index 192bfb6d537..7e4d72fc066 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -155,6 +155,11 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { return frame(sp, lr); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + Unimplemented(); + return nullptr; +} + frame os::get_sender_for_C_frame(frame* fr) { if (*fr->sp() == 0) { // fr is the last C frame. 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 3eb91412d8c..9c648f78118 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -80,6 +80,7 @@ #define REG_SP REG_RSP #define REG_PC REG_RIP #define REG_FP REG_RBP +#define REG_BCP REG_R13 #define SPELL_REG_SP "rsp" #define SPELL_REG_FP "rbp" #else @@ -157,6 +158,13 @@ frame os::fetch_compiled_frame_from_context(const void* ucVoid) { return frame(sp + 1, fp, (address)*sp); } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + assert(ucVoid != nullptr, "invariant"); + const ucontext_t* uc = (const ucontext_t*)ucVoid; + assert(os::Posix::ucontext_is_interpreter(uc), "invariant"); + return reinterpret_cast(uc->uc_mcontext.gregs[REG_BCP]); +} + // By default, gcc always save frame pointer (%ebp/%rbp) on stack. It may get // turned off by -fomit-frame-pointer, frame os::get_sender_for_C_frame(frame* fr) { diff --git a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp index 01e207b73c8..c9ac461851a 100644 --- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp +++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp @@ -211,6 +211,11 @@ frame os::fetch_frame_from_context(const void* ucVoid) { } } +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + ShouldNotCallThis(); + return nullptr; +} + bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ucontext_t* uc, JavaThread* thread) { diff --git a/src/hotspot/os_cpu/windows_aarch64/icache_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/icache_windows_aarch64.hpp index bf36b77d98e..e12caebf0e2 100644 --- a/src/hotspot/os_cpu/windows_aarch64/icache_windows_aarch64.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/icache_windows_aarch64.hpp @@ -32,7 +32,7 @@ class ICache : public AbstractICache { public: - static void initialize(); + static void initialize(int phase); static void invalidate_word(address addr) { invalidate_range(addr, 4); } diff --git a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp index df77502b860..01105e6d51e 100644 --- a/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp +++ b/src/hotspot/os_cpu/windows_aarch64/os_windows_aarch64.cpp @@ -58,6 +58,8 @@ # include # include +#define REG_BCP X22 + void os::os_exception_wrapper(java_call_t f, JavaValue* value, const methodHandle& method, JavaCallArguments* args, JavaThread* thread) { f(value, method, args, thread); } @@ -97,6 +99,22 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(sp, fp, epc); } +#ifdef ASSERT +static bool is_interpreter(const CONTEXT* uc) { + assert(uc != nullptr, "invariant"); + address pc = reinterpret_cast
          (uc->Pc); + assert(pc != nullptr, "invariant"); + return Interpreter::contains(pc); +} +#endif + +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + assert(ucVoid != nullptr, "invariant"); + CONTEXT* uc = (CONTEXT*)ucVoid; + assert(is_interpreter(uc), "invariant"); + return reinterpret_cast(uc->REG_BCP); +} + bool os::win32::get_frame_at_stack_banging_point(JavaThread* thread, struct _EXCEPTION_POINTERS* exceptionInfo, address pc, frame* fr) { PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord; diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp index 6414bb9eaf6..c188919595c 100644 --- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp @@ -58,6 +58,7 @@ #define REG_SP Rsp #define REG_FP Rbp #define REG_PC Rip +#define REG_BCP R13 JNIEXPORT extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* ); @@ -320,6 +321,22 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(sp, fp, epc); } +#ifdef ASSERT +static bool is_interpreter(const CONTEXT* uc) { + assert(uc != nullptr, "invariant"); + address pc = reinterpret_cast
          (uc->REG_PC); + assert(pc != nullptr, "invariant"); + return Interpreter::contains(pc); +} +#endif + +intptr_t* os::fetch_bcp_from_context(const void* ucVoid) { + assert(ucVoid != nullptr, "invariant"); + const CONTEXT* const uc = (CONTEXT*)ucVoid; + assert(is_interpreter(uc), "invariant"); + return reinterpret_cast(uc->REG_BCP); +} + // Returns the current stack pointer. Accurate value needed for // os::verify_stack_alignment(). address os::current_stack_pointer() { diff --git a/src/hotspot/share/adlc/dfa.cpp b/src/hotspot/share/adlc/dfa.cpp index 9c3d76cba55..d23ffb06c01 100644 --- a/src/hotspot/share/adlc/dfa.cpp +++ b/src/hotspot/share/adlc/dfa.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -582,7 +582,7 @@ static bool is_vector_unary_op_name(const char* op_name) { static const char* vector_unary_op_list[] = { "AbsVB", "AbsVS", "AbsVI", "AbsVL", "AbsVF", "AbsVD", "NegVI", "NegVL", "NegVF", "NegVD", - "SqrtVF", "SqrtVD", + "SqrtVHF", "SqrtVF", "SqrtVD", "PopCountVI", "PopCountVL", "CountLeadingZerosV", "CountTrailingZerosV", "ReverseV", "ReverseBytesV", diff --git a/src/hotspot/share/adlc/output_h.cpp b/src/hotspot/share/adlc/output_h.cpp index a4ab29008f0..b62bc43791f 100644 --- a/src/hotspot/share/adlc/output_h.cpp +++ b/src/hotspot/share/adlc/output_h.cpp @@ -870,7 +870,8 @@ void ArchDesc::declare_pipe_classes(FILE *fp_hpp) { fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " void step(uint cycles) {\n"); fprintf(fp_hpp, " _used = 0;\n"); - fprintf(fp_hpp, " _mask <<= cycles;\n"); + fprintf(fp_hpp, " uint max_shift = 8 * sizeof(_mask) - 1;\n"); + fprintf(fp_hpp, " _mask <<= (cycles < max_shift) ? cycles : max_shift;\n"); fprintf(fp_hpp, " }\n\n"); fprintf(fp_hpp, " friend class Pipeline_Use;\n"); fprintf(fp_hpp, "};\n\n"); @@ -1961,7 +1962,7 @@ void ArchDesc::declareClasses(FILE *fp) { else if( instr->is_ideal_box() ) { // BoxNode provides the address of a stack slot. // Define its bottom type to be TypeRawPtr::BOTTOM instead of TypePtr::BOTTOM - // This prevent s insert_anti_dependencies from complaining. It will + // This prevents raise_above_anti_dependences from complaining. It will // complain if it sees that the pointer base is TypePtr::BOTTOM since // it doesn't understand what that might alias. fprintf(fp," const Type *bottom_type() const { return TypeRawPtr::BOTTOM; } // Box?\n"); diff --git a/src/hotspot/share/asm/assembler.hpp b/src/hotspot/share/asm/assembler.hpp index 9abd3eb7171..961b5fab700 100644 --- a/src/hotspot/share/asm/assembler.hpp +++ b/src/hotspot/share/asm/assembler.hpp @@ -73,7 +73,7 @@ class Label; */ class Label { private: - enum { PatchCacheSize = 4 debug_only( +4 ) }; + enum { PatchCacheSize = 4 DEBUG_ONLY( +4 ) }; // _loc encodes both the binding state (via its sign) // and the binding locator (via its value) of a label. diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 917569e2be6..81bfc932147 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -23,11 +23,13 @@ */ #include "asm/codeBuffer.hpp" +#include "code/aotCodeCache.hpp" #include "code/compiledIC.hpp" #include "code/oopRecorder.inline.hpp" #include "compiler/disassembler.hpp" #include "logging/log.hpp" #include "oops/klass.inline.hpp" +#include "oops/methodCounters.hpp" #include "oops/methodData.hpp" #include "oops/oop.inline.hpp" #include "runtime/icache.hpp" @@ -92,7 +94,7 @@ CodeBuffer::CodeBuffer(CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this) // Provide code buffer with meaningful name initialize_misc(blob->name()); initialize(blob->content_begin(), blob->content_size()); - debug_only(verify_section_allocation();) + DEBUG_ONLY(verify_section_allocation();) } void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) { @@ -120,7 +122,7 @@ void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) { _insts.initialize_locs(locs_size / sizeof(relocInfo)); } - debug_only(verify_section_allocation();) + DEBUG_ONLY(verify_section_allocation();) } @@ -494,7 +496,7 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const { prev_cs = cs; } - debug_only(dest_cs->_start = nullptr); // defeat double-initialization assert + DEBUG_ONLY(dest_cs->_start = nullptr); // defeat double-initialization assert dest_cs->initialize(buf+buf_offset, csize); dest_cs->set_end(buf+buf_offset+csize); assert(dest_cs->is_allocated(), "must always be allocated"); @@ -505,7 +507,7 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const { // Done calculating sections; did it come out to the right end? assert(buf_offset == total_content_size(), "sanity"); - debug_only(dest->verify_section_allocation();) + DEBUG_ONLY(dest->verify_section_allocation();) } // Append an oop reference that keeps the class alive. @@ -536,6 +538,9 @@ void CodeBuffer::finalize_oop_references(const methodHandle& mh) { if (m->is_methodData()) { m = ((MethodData*)m)->method(); } + if (m->is_methodCounters()) { + m = ((MethodCounters*)m)->method(); + } if (m->is_method()) { m = ((Method*)m)->method_holder(); } @@ -560,6 +565,9 @@ void CodeBuffer::finalize_oop_references(const methodHandle& mh) { if (m->is_methodData()) { m = ((MethodData*)m)->method(); } + if (m->is_methodCounters()) { + m = ((MethodCounters*)m)->method(); + } if (m->is_method()) { m = ((Method*)m)->method_holder(); } @@ -722,7 +730,7 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) { #ifndef PRODUCT if (PrintNMethods && (WizardMode || Verbose)) { tty->print("done with CodeBuffer:"); - ((CodeBuffer*)this)->print(); + ((CodeBuffer*)this)->print_on(tty); } #endif //PRODUCT @@ -861,7 +869,7 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { #ifndef PRODUCT if (PrintNMethods && (WizardMode || Verbose)) { tty->print("expanding CodeBuffer:"); - this->print(); + this->print_on(tty); } if (StressCodeBuffers && blob() != nullptr) { @@ -939,17 +947,17 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { cb.set_blob(nullptr); // Zap the old code buffer contents, to avoid mistakenly using them. - debug_only(Copy::fill_to_bytes(bxp->_total_start, bxp->_total_size, + DEBUG_ONLY(Copy::fill_to_bytes(bxp->_total_start, bxp->_total_size, badCodeHeapFreeVal);) // Make certain that the new sections are all snugly inside the new blob. - debug_only(verify_section_allocation();) + DEBUG_ONLY(verify_section_allocation();) #ifndef PRODUCT _decode_begin = nullptr; // sanity if (PrintNMethods && (WizardMode || Verbose)) { tty->print("expanded CodeBuffer:"); - this->print(); + this->print_on(tty); } #endif //PRODUCT } @@ -1042,6 +1050,9 @@ void CodeBuffer::shared_stub_to_interp_for(ciMethod* callee, csize_t call_offset #ifndef PRODUCT void CodeBuffer::block_comment(ptrdiff_t offset, const char* comment) { + if (insts()->scratch_emit()) { + return; + } if (_collect_comments) { const char* str = _asm_remarks.insert(offset, comment); postcond(str != comment); @@ -1049,6 +1060,9 @@ void CodeBuffer::block_comment(ptrdiff_t offset, const char* comment) { } const char* CodeBuffer::code_string(const char* str) { + if (insts()->scratch_emit()) { + return str; + } const char* tmp = _dbg_strings.insert(str); postcond(tmp != str); return tmp; @@ -1060,125 +1074,31 @@ void CodeBuffer::decode() { _decode_begin = insts_end(); } -void CodeSection::print(const char* name) { +void CodeSection::print_on(outputStream* st, const char* name) { csize_t locs_size = locs_end() - locs_start(); - tty->print_cr(" %7s.code = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d)", + st->print_cr(" %7s.code = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d)", name, p2i(start()), p2i(end()), p2i(limit()), size(), capacity()); - tty->print_cr(" %7s.locs = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d) point=%d", + st->print_cr(" %7s.locs = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d) point=%d", name, p2i(locs_start()), p2i(locs_end()), p2i(locs_limit()), locs_size, locs_capacity(), locs_point_off()); if (PrintRelocations && (locs_size != 0)) { RelocIterator iter(this); - iter.print(); + iter.print_on(st); } } -void CodeBuffer::print() { - tty->print_cr("CodeBuffer:"); +void CodeBuffer::print_on(outputStream* st) { + st->print_cr("CodeBuffer:%s", name()); for (int n = 0; n < (int)SECT_LIMIT; n++) { // print each section CodeSection* cs = code_section(n); - cs->print(code_section_name(n)); + cs->print_on(st, code_section_name(n)); } } -// ----- CHeapString ----------------------------------------------------------- - -class CHeapString : public CHeapObj { - public: - CHeapString(const char* str) : _string(os::strdup(str)) {} - ~CHeapString() { - os::free((void*)_string); - _string = nullptr; - } - const char* string() const { return _string; } - - private: - const char* _string; -}; - -// ----- AsmRemarkCollection --------------------------------------------------- - -class AsmRemarkCollection : public CHeapObj { - public: - AsmRemarkCollection() : _ref_cnt(1), _remarks(nullptr), _next(nullptr) {} - ~AsmRemarkCollection() { - assert(is_empty(), "Must 'clear()' before deleting!"); - assert(_ref_cnt == 0, "No uses must remain when deleting!"); - } - AsmRemarkCollection* reuse() { - precond(_ref_cnt > 0); - return _ref_cnt++, this; - } - - const char* insert(uint offset, const char* remark); - const char* lookup(uint offset) const; - const char* next(uint offset) const; - - bool is_empty() const { return _remarks == nullptr; } - uint clear(); - - private: - struct Cell : CHeapString { - Cell(const char* remark, uint offset) : - CHeapString(remark), offset(offset), prev(nullptr), next(nullptr) {} - void push_back(Cell* cell) { - Cell* head = this; - Cell* tail = prev; - tail->next = cell; - cell->next = head; - cell->prev = tail; - prev = cell; - } - uint offset; - Cell* prev; - Cell* next; - }; - uint _ref_cnt; - Cell* _remarks; - // Using a 'mutable' iteration pointer to allow 'const' on lookup/next (that - // does not change the state of the list per se), supportig a simplistic - // iteration scheme. - mutable Cell* _next; -}; - -// ----- DbgStringCollection --------------------------------------------------- - -class DbgStringCollection : public CHeapObj { - public: - DbgStringCollection() : _ref_cnt(1), _strings(nullptr) {} - ~DbgStringCollection() { - assert(is_empty(), "Must 'clear()' before deleting!"); - assert(_ref_cnt == 0, "No uses must remain when deleting!"); - } - DbgStringCollection* reuse() { - precond(_ref_cnt > 0); - return _ref_cnt++, this; - } - - const char* insert(const char* str); - const char* lookup(const char* str) const; - - bool is_empty() const { return _strings == nullptr; } - uint clear(); - - private: - struct Cell : CHeapString { - Cell(const char* dbgstr) : - CHeapString(dbgstr), prev(nullptr), next(nullptr) {} - void push_back(Cell* cell) { - Cell* head = this; - Cell* tail = prev; - tail->next = cell; - cell->next = head; - cell->prev = tail; - prev = cell; - } - Cell* prev; - Cell* next; - }; - uint _ref_cnt; - Cell* _strings; -}; +CHeapString::~CHeapString() { + os::free((void*)_string); + _string = nullptr; +} // ----- AsmRemarks ------------------------------------------------------------ // @@ -1186,7 +1106,8 @@ class DbgStringCollection : public CHeapObj { // offset is a byte offset into an instruction stream (CodeBuffer, CodeBlob or // other memory buffer) and remark is a string (comment). // -AsmRemarks::AsmRemarks() : _remarks(new AsmRemarkCollection()) { +AsmRemarks::AsmRemarks() { + init(); assert(_remarks != nullptr, "Allocation failure!"); } @@ -1194,6 +1115,10 @@ AsmRemarks::~AsmRemarks() { assert(_remarks == nullptr, "Must 'clear()' before deleting!"); } +void AsmRemarks::init() { + _remarks = new AsmRemarkCollection(); +} + const char* AsmRemarks::insert(uint offset, const char* remstr) { precond(remstr != nullptr); return _remarks->insert(offset, remstr); @@ -1204,13 +1129,13 @@ bool AsmRemarks::is_empty() const { } void AsmRemarks::share(const AsmRemarks &src) { - precond(is_empty()); + precond(_remarks == nullptr || is_empty()); clear(); _remarks = src._remarks->reuse(); } void AsmRemarks::clear() { - if (_remarks->clear() == 0) { + if (_remarks != nullptr && _remarks->clear() == 0) { delete _remarks; } _remarks = nullptr; @@ -1238,7 +1163,8 @@ uint AsmRemarks::print(uint offset, outputStream* strm) const { // Acting as interface to reference counted collection of (debug) strings used // in the code generated, and thus requiring a fixed address. // -DbgStrings::DbgStrings() : _strings(new DbgStringCollection()) { +DbgStrings::DbgStrings() { + init(); assert(_strings != nullptr, "Allocation failure!"); } @@ -1246,6 +1172,10 @@ DbgStrings::~DbgStrings() { assert(_strings == nullptr, "Must 'clear()' before deleting!"); } +void DbgStrings::init() { + _strings = new DbgStringCollection(); +} + const char* DbgStrings::insert(const char* dbgstr) { const char* str = _strings->lookup(dbgstr); return str != nullptr ? str : _strings->insert(dbgstr); @@ -1256,13 +1186,13 @@ bool DbgStrings::is_empty() const { } void DbgStrings::share(const DbgStrings &src) { - precond(is_empty()); + precond(_strings == nullptr || is_empty()); clear(); _strings = src._strings->reuse(); } void DbgStrings::clear() { - if (_strings->clear() == 0) { + if (_strings != nullptr && _strings->clear() == 0) { delete _strings; } _strings = nullptr; diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index f855d41b181..96e9a77a923 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -28,6 +28,7 @@ #include "code/oopRecorder.hpp" #include "code/relocInfo.hpp" #include "compiler/compiler_globals.hpp" +#include "runtime/os.hpp" #include "utilities/align.hpp" #include "utilities/debug.hpp" #include "utilities/growableArray.hpp" @@ -89,6 +90,7 @@ class CodeOffsets: public StackObj { // They are filled concurrently, and concatenated at the end. class CodeSection { friend class CodeBuffer; + friend class AOTCodeReader; public: typedef int csize_t; // code size type; would be size_t except for history @@ -121,8 +123,8 @@ class CodeSection { _locs_own = false; _scratch_emit = false; _skipped_instructions_size = 0; - debug_only(_index = -1); - debug_only(_outer = (CodeBuffer*)badAddress); + DEBUG_ONLY(_index = -1); + DEBUG_ONLY(_outer = (CodeBuffer*)badAddress); } void initialize_outer(CodeBuffer* outer, int8_t index) { @@ -283,15 +285,136 @@ class CodeSection { #ifndef PRODUCT void decode(); - void print(const char* name); + void print_on(outputStream* st, const char* name); #endif //PRODUCT }; #ifndef PRODUCT -class AsmRemarkCollection; -class DbgStringCollection; +// ----- CHeapString ----------------------------------------------------------- + +class CHeapString : public CHeapObj { + public: + CHeapString(const char* str) : _string(os::strdup(str)) {} + ~CHeapString(); + const char* string() const { return _string; } + + private: + const char* _string; +}; + +// ----- AsmRemarkCollection --------------------------------------------------- + +class AsmRemarkCollection : public CHeapObj { + public: + AsmRemarkCollection() : _ref_cnt(1), _remarks(nullptr), _next(nullptr) {} + ~AsmRemarkCollection() { + assert(is_empty(), "Must 'clear()' before deleting!"); + assert(_ref_cnt == 0, "No uses must remain when deleting!"); + } + AsmRemarkCollection* reuse() { + precond(_ref_cnt > 0); + return _ref_cnt++, this; + } + + const char* insert(uint offset, const char* remark); + const char* lookup(uint offset) const; + const char* next(uint offset) const; + + bool is_empty() const { return _remarks == nullptr; } + uint clear(); + + template + bool iterate(Function function) const { // lambda enabled API + if (_remarks != nullptr) { + Cell* tmp = _remarks; + do { + if(!function(tmp->offset, tmp->string())) { + return false; + } + tmp = tmp->next; + } while (tmp != _remarks); + } + return true; + } + + private: + struct Cell : CHeapString { + Cell(const char* remark, uint offset) : + CHeapString(remark), offset(offset), prev(nullptr), next(nullptr) {} + void push_back(Cell* cell) { + Cell* head = this; + Cell* tail = prev; + tail->next = cell; + cell->next = head; + cell->prev = tail; + prev = cell; + } + uint offset; + Cell* prev; + Cell* next; + }; + uint _ref_cnt; + Cell* _remarks; + // Using a 'mutable' iteration pointer to allow 'const' on lookup/next (that + // does not change the state of the list per se), supportig a simplistic + // iteration scheme. + mutable Cell* _next; +}; + +// ----- DbgStringCollection --------------------------------------------------- + +class DbgStringCollection : public CHeapObj { + public: + DbgStringCollection() : _ref_cnt(1), _strings(nullptr) {} + ~DbgStringCollection() { + assert(is_empty(), "Must 'clear()' before deleting!"); + assert(_ref_cnt == 0, "No uses must remain when deleting!"); + } + DbgStringCollection* reuse() { + precond(_ref_cnt > 0); + return _ref_cnt++, this; + } + + const char* insert(const char* str); + const char* lookup(const char* str) const; + + bool is_empty() const { return _strings == nullptr; } + uint clear(); + + template + bool iterate(Function function) const { // lambda enabled API + if (_strings != nullptr) { + Cell* tmp = _strings; + do { + if (!function(tmp->string())) { + return false; + } + tmp = tmp->next; + } while (tmp != _strings); + } + return true; + } + + private: + struct Cell : CHeapString { + Cell(const char* dbgstr) : + CHeapString(dbgstr), prev(nullptr), next(nullptr) {} + void push_back(Cell* cell) { + Cell* head = this; + Cell* tail = prev; + tail->next = cell; + cell->next = head; + cell->prev = tail; + prev = cell; + } + Cell* prev; + Cell* next; + }; + uint _ref_cnt; + Cell* _strings; +}; // The assumption made here is that most code remarks (or comments) added to // the generated assembly code are unique, i.e. there is very little gain in @@ -303,6 +426,8 @@ class AsmRemarks { AsmRemarks(); ~AsmRemarks(); + void init(); + const char* insert(uint offset, const char* remstr); bool is_empty() const; @@ -314,6 +439,9 @@ class AsmRemarks { // For testing purposes only. const AsmRemarkCollection* ref() const { return _remarks; } + template + inline bool iterate(Function function) const { return _remarks->iterate(function); } + private: AsmRemarkCollection* _remarks; }; @@ -326,6 +454,8 @@ class DbgStrings { DbgStrings(); ~DbgStrings(); + void init(); + const char* insert(const char* dbgstr); bool is_empty() const; @@ -336,6 +466,9 @@ class DbgStrings { // For testing purposes only. const DbgStringCollection* ref() const { return _strings; } + template + bool iterate(Function function) const { return _strings->iterate(function); } + private: DbgStringCollection* _strings; }; @@ -386,6 +519,7 @@ typedef GrowableArray SharedStubToInterpRequests; class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { friend class CodeSection; friend class StubCodeGenerator; + friend class AOTCodeReader; private: // CodeBuffers must be allocated on the stack except for a single @@ -535,7 +669,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { assert(code_start != nullptr, "sanity"); initialize_misc("static buffer"); initialize(code_start, code_size); - debug_only(verify_section_allocation();) + DEBUG_ONLY(verify_section_allocation();) } // (2) CodeBuffer referring to pre-allocated CodeBlob. @@ -742,7 +876,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { // Printing / Decoding // decodes from decode_begin() to code_end() and sets decode_begin to end void decode(); - void print(); + void print_on(outputStream* st); #endif // Directly disassemble code buffer. void decode(address start, address end); diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp index 53a97ce1042..cf1f7e50086 100644 --- a/src/hotspot/share/c1/c1_Compilation.cpp +++ b/src/hotspot/share/c1/c1_Compilation.cpp @@ -33,6 +33,7 @@ #include "c1/c1_ValueStack.hpp" #include "code/debugInfoRec.hpp" #include "compiler/compilationFailureInfo.hpp" +#include "compiler/compilationLog.hpp" #include "compiler/compilationMemoryStatistic.hpp" #include "compiler/compileLog.hpp" #include "compiler/compiler_globals.hpp" @@ -646,6 +647,13 @@ void Compilation::notice_inlined_method(ciMethod* method) { void Compilation::bailout(const char* msg) { assert(msg != nullptr, "bailout message must exist"); + // record the bailout for hserr envlog + if (CompilationLog::log() != nullptr) { + CompilerThread* thread = CompilerThread::current(); + CompileTask* task = thread->task(); + CompilationLog::log()->log_failure(thread, task, msg, nullptr); + } + if (!bailed_out()) { // keep first bailout message if (PrintCompilation || PrintBailouts) tty->print_cr("compilation bailout: %s", msg); diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp index dd13b84edf5..b5fa7dcf247 100644 --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -168,6 +168,7 @@ bool Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_dtan: #if defined(AMD64) case vmIntrinsics::_dtanh: + case vmIntrinsics::_dcbrt: #endif case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: diff --git a/src/hotspot/share/c1/c1_FrameMap.hpp b/src/hotspot/share/c1/c1_FrameMap.hpp index 4e4fde0cb4a..f10c4d3f226 100644 --- a/src/hotspot/share/c1/c1_FrameMap.hpp +++ b/src/hotspot/share/c1/c1_FrameMap.hpp @@ -109,19 +109,19 @@ class FrameMap : public CompilationResourceObj { static Register cpu_rnr2reg (int rnr) { assert(_init_done, "tables not initialized"); - debug_only(cpu_range_check(rnr);) + DEBUG_ONLY(cpu_range_check(rnr);) return _cpu_rnr2reg[rnr]; } static int cpu_reg2rnr (Register reg) { assert(_init_done, "tables not initialized"); - debug_only(cpu_range_check(reg->encoding());) + DEBUG_ONLY(cpu_range_check(reg->encoding());) return _cpu_reg2rnr[reg->encoding()]; } static void map_register(int rnr, Register reg) { - debug_only(cpu_range_check(rnr);) - debug_only(cpu_range_check(reg->encoding());) + DEBUG_ONLY(cpu_range_check(rnr);) + DEBUG_ONLY(cpu_range_check(reg->encoding());) _cpu_rnr2reg[rnr] = reg; _cpu_reg2rnr[reg->encoding()] = rnr; } diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 201ee695f69..8658bebdaee 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -3298,6 +3298,7 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) case vmIntrinsics::_dcos : // fall through case vmIntrinsics::_dtan : // fall through case vmIntrinsics::_dtanh : // fall through + case vmIntrinsics::_dcbrt : // fall through case vmIntrinsics::_dlog : // fall through case vmIntrinsics::_dlog10 : // fall through case vmIntrinsics::_dexp : // fall through diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index e6ba03554cb..c1c94244fcc 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -1444,7 +1444,7 @@ void LIR_List::checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass, ciMethod* profiled_method, int profiled_bci) { LIR_OpTypeCheck* c = new LIR_OpTypeCheck(lir_checkcast, result, object, klass, tmp1, tmp2, tmp3, fast_check, info_for_exception, info_for_patch, stub); - if (profiled_method != nullptr) { + if (profiled_method != nullptr && TypeProfileCasts) { c->set_profiled_method(profiled_method); c->set_profiled_bci(profiled_bci); c->set_should_profile(true); @@ -1454,7 +1454,7 @@ void LIR_List::checkcast (LIR_Opr result, LIR_Opr object, ciKlass* klass, void LIR_List::instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, bool fast_check, CodeEmitInfo* info_for_patch, ciMethod* profiled_method, int profiled_bci) { LIR_OpTypeCheck* c = new LIR_OpTypeCheck(lir_instanceof, result, object, klass, tmp1, tmp2, tmp3, fast_check, nullptr, info_for_patch, nullptr); - if (profiled_method != nullptr) { + if (profiled_method != nullptr && TypeProfileCasts) { c->set_profiled_method(profiled_method); c->set_profiled_bci(profiled_bci); c->set_should_profile(true); @@ -1466,7 +1466,7 @@ void LIR_List::instanceof(LIR_Opr result, LIR_Opr object, ciKlass* klass, LIR_Op void LIR_List::store_check(LIR_Opr object, LIR_Opr array, LIR_Opr tmp1, LIR_Opr tmp2, LIR_Opr tmp3, CodeEmitInfo* info_for_exception, ciMethod* profiled_method, int profiled_bci) { LIR_OpTypeCheck* c = new LIR_OpTypeCheck(lir_store_check, object, array, tmp1, tmp2, tmp3, info_for_exception); - if (profiled_method != nullptr) { + if (profiled_method != nullptr && TypeProfileCasts) { c->set_profiled_method(profiled_method); c->set_profiled_bci(profiled_bci); c->set_should_profile(true); diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 214da537993..341de0ac0c2 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -2870,6 +2870,7 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { case vmIntrinsics::_dtanh: // fall through case vmIntrinsics::_dsin : // fall through case vmIntrinsics::_dcos : // fall through + case vmIntrinsics::_dcbrt : // fall through case vmIntrinsics::_dexp : // fall through case vmIntrinsics::_dpow : do_MathIntrinsic(x); break; case vmIntrinsics::_arraycopy: do_ArrayCopy(x); break; diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 9d4b35024ed..e2760689daa 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -31,6 +31,7 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" +#include "code/aotCodeCache.hpp" #include "code/codeBlob.hpp" #include "code/compiledIC.hpp" #include "code/scopeDesc.hpp" @@ -198,6 +199,13 @@ class C1StubIdStubAssemblerCodeGenClosure: public StubAssemblerCodeGenClosure { }; CodeBlob* Runtime1::generate_blob(BufferBlob* buffer_blob, C1StubId id, const char* name, bool expect_oop_map, StubAssemblerCodeGenClosure* cl) { + if ((int)id >= 0) { + CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::C1Blob, (uint)id, name, 0, nullptr); + if (blob != nullptr) { + return blob; + } + } + ResourceMark rm; // create code buffer for code storage CodeBuffer code(buffer_blob); @@ -231,6 +239,9 @@ CodeBlob* Runtime1::generate_blob(BufferBlob* buffer_blob, C1StubId id, const ch oop_maps, must_gc_arguments, false /* alloc_fail_is_fatal */ ); + if (blob != nullptr && (int)id >= 0) { + AOTCodeCache::store_code_blob(*blob, AOTCodeEntry::C1Blob, (uint)id, name, 0, nullptr); + } return blob; } @@ -265,7 +276,13 @@ bool Runtime1::initialize(BufferBlob* blob) { initialize_pd(); // generate stubs int limit = (int)C1StubId::NUM_STUBIDS; - for (int id = 0; id < limit; id++) { + for (int id = 0; id <= (int)C1StubId::forward_exception_id; id++) { + if (!generate_blob_for(blob, (C1StubId) id)) { + return false; + } + } + AOTCodeCache::init_early_c1_table(); + for (int id = (int)C1StubId::forward_exception_id+1; id < limit; id++) { if (!generate_blob_for(blob, (C1StubId) id)) { return false; } @@ -348,6 +365,7 @@ const char* Runtime1::name_for_address(address entry) { FUNCTION_CASE(entry, StubRoutines::dcos()); FUNCTION_CASE(entry, StubRoutines::dtan()); FUNCTION_CASE(entry, StubRoutines::dtanh()); + FUNCTION_CASE(entry, StubRoutines::dcbrt()); #undef FUNCTION_CASE @@ -491,7 +509,7 @@ static nmethod* counter_overflow_helper(JavaThread* current, int branch_bci, Met JRT_BLOCK_ENTRY(address, Runtime1::counter_overflow(JavaThread* current, int bci, Method* method)) nmethod* osr_nm; - JRT_BLOCK + JRT_BLOCK_NO_ASYNC osr_nm = counter_overflow_helper(current, bci, method); if (osr_nm != nullptr) { RegisterMap map(current, @@ -800,7 +818,7 @@ JRT_ENTRY(void, Runtime1::deoptimize(JavaThread* current, jint trap_request)) Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(trap_request); if (action == Deoptimization::Action_make_not_entrant) { - if (nm->make_not_entrant("C1 deoptimize")) { + if (nm->make_not_entrant(nmethod::ChangeReason::C1_deoptimize)) { if (reason == Deoptimization::Reason_tenured) { MethodData* trap_mdo = Deoptimization::get_method_data(current, method, true /*create_if_missing*/); if (trap_mdo != nullptr) { @@ -1092,7 +1110,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* current, C1StubId stub_id )) // safepoint, but if it's still alive then make it not_entrant. nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); if (nm != nullptr) { - nm->make_not_entrant("C1 code patch"); + nm->make_not_entrant(nmethod::ChangeReason::C1_codepatch); } Deoptimization::deoptimize_frame(current, caller_frame.id()); @@ -1340,7 +1358,7 @@ void Runtime1::patch_code(JavaThread* current, C1StubId stub_id) { // Make sure the nmethod is invalidated, i.e. made not entrant. nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); if (nm != nullptr) { - nm->make_not_entrant("C1 deoptimize for patching"); + nm->make_not_entrant(nmethod::ChangeReason::C1_deoptimize_for_patching); } } @@ -1363,7 +1381,7 @@ int Runtime1::move_klass_patching(JavaThread* current) { // // NOTE: we are still in Java // - debug_only(NoHandleMark nhm;) + DEBUG_ONLY(NoHandleMark nhm;) { // Enter VM mode ResetNoHandleMark rnhm; @@ -1380,7 +1398,7 @@ int Runtime1::move_mirror_patching(JavaThread* current) { // // NOTE: we are still in Java // - debug_only(NoHandleMark nhm;) + DEBUG_ONLY(NoHandleMark nhm;) { // Enter VM mode ResetNoHandleMark rnhm; @@ -1397,7 +1415,7 @@ int Runtime1::move_appendix_patching(JavaThread* current) { // // NOTE: we are still in Java // - debug_only(NoHandleMark nhm;) + DEBUG_ONLY(NoHandleMark nhm;) { // Enter VM mode ResetNoHandleMark rnhm; @@ -1468,7 +1486,7 @@ JRT_ENTRY(void, Runtime1::predicate_failed_trap(JavaThread* current)) nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); assert (nm != nullptr, "no more nmethod?"); - nm->make_not_entrant("C1 predicate failed trap"); + nm->make_not_entrant(nmethod::ChangeReason::C1_predicate_failed_trap); methodHandle m(current, nm->method()); MethodData* mdo = m->method_data(); diff --git a/src/hotspot/share/c1/c1_Runtime1.hpp b/src/hotspot/share/c1/c1_Runtime1.hpp index c09de00ce55..9912b6b515e 100644 --- a/src/hotspot/share/c1/c1_Runtime1.hpp +++ b/src/hotspot/share/c1/c1_Runtime1.hpp @@ -54,6 +54,7 @@ enum class C1StubId :int { class Runtime1: public AllStatic { friend class ArrayCopyStub; + friend class AOTCodeAddressTable; public: // statistics diff --git a/src/hotspot/share/cds/aotArtifactFinder.cpp b/src/hotspot/share/cds/aotArtifactFinder.cpp index 95d242c2089..d8999774a53 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.cpp +++ b/src/hotspot/share/cds/aotArtifactFinder.cpp @@ -22,9 +22,11 @@ * */ -#include "cds/aotClassLinker.hpp" #include "cds/aotArtifactFinder.hpp" #include "cds/aotClassInitializer.hpp" +#include "cds/aotClassLinker.hpp" +#include "cds/aotLogging.hpp" +#include "cds/aotReferenceObjSupport.hpp" #include "cds/dumpTimeClassInfo.inline.hpp" #include "cds/heapShared.hpp" #include "cds/lambdaProxyClassDictionary.hpp" @@ -33,6 +35,7 @@ #include "memory/metaspaceClosure.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayKlass.hpp" +#include "oops/trainingData.hpp" #include "utilities/resourceHash.hpp" // All the classes that should be included in the AOT cache (in at least the "allocated" state) @@ -73,6 +76,7 @@ void AOTArtifactFinder::find_artifacts() { // Note, if a class is not excluded, it does NOT mean it will be automatically included // into the AOT cache -- that will be decided by the code below. SystemDictionaryShared::finish_exclusion_checks(); + AOTReferenceObjSupport::init_keep_alive_objs_table(); start_scanning_for_oops(); @@ -95,7 +99,7 @@ void AOTArtifactFinder::find_artifacts() { oop orig_mirror = Universe::java_mirror(bt); oop scratch_mirror = HeapShared::scratch_java_mirror(bt); HeapShared::scan_java_mirror(orig_mirror); - log_trace(cds, heap, mirror)( + log_trace(aot, heap, mirror)( "Archived %s mirror object from " PTR_FORMAT, type2name(bt), p2i(scratch_mirror)); Universe::set_archived_basic_type_mirror_index(bt, HeapShared::append_root(scratch_mirror)); @@ -153,15 +157,17 @@ void AOTArtifactFinder::find_artifacts() { if (!info.is_excluded() && _seen_classes->get(k) == nullptr) { info.set_excluded(); info.set_has_checked_exclusion(); - if (log_is_enabled(Debug, cds)) { + if (aot_log_is_enabled(Debug, aot)) { ResourceMark rm; - log_debug(cds)("Skipping %s: %s class", k->name()->as_C_string(), + aot_log_debug(aot)("Skipping %s: %s class", k->name()->as_C_string(), k->is_hidden() ? "Unreferenced hidden" : "AOT tooling"); } } }); end_scanning_for_oops(); + + TrainingData::cleanup_training_data(); } void AOTArtifactFinder::start_scanning_for_oops() { @@ -207,12 +213,37 @@ void AOTArtifactFinder::add_aot_inited_class(InstanceKlass* ik) { } } +void AOTArtifactFinder::append_to_all_cached_classes(Klass* k) { + precond(!SystemDictionaryShared::should_be_excluded(k)); + _all_cached_classes->append(k); +} + void AOTArtifactFinder::add_cached_instance_class(InstanceKlass* ik) { + if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared()) { + // This class is already included in the base archive. No need to cache + // it again in the dynamic archive. + return; + } + bool created; _seen_classes->put_if_absent(ik, &created); if (created) { - _all_cached_classes->append(ik); - if (CDSConfig::is_dumping_final_static_archive() && ik->is_shared_unregistered_class()) { + append_to_all_cached_classes(ik); + + // All super types must be added. + InstanceKlass* s = ik->java_super(); + if (s != nullptr) { + add_cached_instance_class(s); + } + + Array* interfaces = ik->local_interfaces(); + int len = interfaces->length(); + for (int i = 0; i < len; i++) { + InstanceKlass* intf = interfaces->at(i); + add_cached_instance_class(intf); + } + + if (CDSConfig::is_dumping_final_static_archive() && ik->defined_by_other_loaders()) { // The following are not appliable to unregistered classes return; } @@ -229,7 +260,7 @@ void AOTArtifactFinder::add_cached_type_array_class(TypeArrayKlass* tak) { bool created; _seen_classes->put_if_absent(tak, &created); if (created) { - _all_cached_classes->append(tak); + append_to_all_cached_classes(tak); scan_oops_in_array_class(tak); } } diff --git a/src/hotspot/share/cds/aotArtifactFinder.hpp b/src/hotspot/share/cds/aotArtifactFinder.hpp index d890d874af9..5d293f20af0 100644 --- a/src/hotspot/share/cds/aotArtifactFinder.hpp +++ b/src/hotspot/share/cds/aotArtifactFinder.hpp @@ -79,6 +79,7 @@ class AOTArtifactFinder : AllStatic { static void scan_oops_in_array_class(ArrayKlass* ak); static void add_cached_type_array_class(TypeArrayKlass* tak); static void add_cached_instance_class(InstanceKlass* ik); + static void append_to_all_cached_classes(Klass* k); public: static void initialize(); static void find_artifacts(); diff --git a/src/hotspot/share/cds/aotCacheAccess.cpp b/src/hotspot/share/cds/aotCacheAccess.cpp new file mode 100644 index 00000000000..b6c4a201da5 --- /dev/null +++ b/src/hotspot/share/cds/aotCacheAccess.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "cds/aotCacheAccess.hpp" +#include "cds/archiveBuilder.hpp" +#include "cds/cdsConfig.hpp" +#include "cds/filemap.hpp" +#include "cds/heapShared.hpp" +#include "cds/metaspaceShared.hpp" +#include "classfile/stringTable.hpp" +#include "logging/log.hpp" +#include "logging/logStream.hpp" +#include "memory/resourceArea.hpp" +#include "memory/universe.hpp" +#include "memory/virtualspace.hpp" +#include "oops/instanceKlass.hpp" + +void* AOTCacheAccess::allocate_aot_code_region(size_t size) { + assert(CDSConfig::is_dumping_final_static_archive(), "must be"); + return (void*)ArchiveBuilder::ac_region_alloc(size); +} + +size_t AOTCacheAccess::get_aot_code_region_size() { + assert(CDSConfig::is_using_archive(), "must be"); + FileMapInfo* mapinfo = FileMapInfo::current_info(); + assert(mapinfo != nullptr, "must be"); + return mapinfo->region_at(MetaspaceShared::ac)->used_aligned(); +} + +bool AOTCacheAccess::map_aot_code_region(ReservedSpace rs) { + FileMapInfo* static_mapinfo = FileMapInfo::current_info(); + assert(UseSharedSpaces && static_mapinfo != nullptr, "must be"); + return static_mapinfo->map_aot_code_region(rs); +} diff --git a/src/hotspot/share/cds/aotCacheAccess.hpp b/src/hotspot/share/cds/aotCacheAccess.hpp new file mode 100644 index 00000000000..31fb9da534d --- /dev/null +++ b/src/hotspot/share/cds/aotCacheAccess.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_CDS_AOTCACHEACCESS_HPP +#define SHARE_CDS_AOTCACHEACCESS_HPP + +#include "cds/archiveBuilder.hpp" +#include "cds/archiveUtils.hpp" +#include "memory/allStatic.hpp" +#include "oops/oopsHierarchy.hpp" +#include "utilities/globalDefinitions.hpp" + +class ReservedSpace; + +// AOT Cache API for AOT compiler + +class AOTCacheAccess : AllStatic { +public: + static void* allocate_aot_code_region(size_t size) NOT_CDS_RETURN_(nullptr); + + static size_t get_aot_code_region_size() NOT_CDS_RETURN_(0); + + static bool map_aot_code_region(ReservedSpace rs) NOT_CDS_RETURN_(false); +}; + +#endif // SHARE_CDS_AOTCACHEACCESS_HPP diff --git a/src/hotspot/share/cds/aotClassInitializer.cpp b/src/hotspot/share/cds/aotClassInitializer.cpp index 297f8109eb4..46a118c42e9 100644 --- a/src/hotspot/share/cds/aotClassInitializer.cpp +++ b/src/hotspot/share/cds/aotClassInitializer.cpp @@ -219,7 +219,7 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) { // // Then run the following: // java -XX:AOTMode=record -XX:AOTConfiguration=jc.aotconfig com.sun.tools.javac.Main - // java -XX:AOTMode=create -Xlog:cds -XX:AOTCache=jc.aot -XX:AOTConfiguration=jc.aotconfig + // java -XX:AOTMode=create -Xlog:aot -XX:AOTCache=jc.aot -XX:AOTConfiguration=jc.aotconfig // // You will see an error like this: // @@ -321,6 +321,10 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) { if (is_allowed(indy_specs, ik)) { return true; } + + if (ik->name()->starts_with("java/lang/invoke/MethodHandleImpl")) { + return true; + } } #ifdef ASSERT @@ -338,15 +342,17 @@ bool AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass* ik) { bool AOTClassInitializer::is_runtime_setup_required(InstanceKlass* ik) { return ik == vmClasses::Class_klass() || ik == vmClasses::internal_Unsafe_klass() || - ik == vmClasses::ConcurrentHashMap_klass(); + ik == vmClasses::ConcurrentHashMap_klass() || + ik == vmClasses::MethodHandleImpl_klass() || + ik == vmClasses::Reference_klass(); } void AOTClassInitializer::call_runtime_setup(JavaThread* current, InstanceKlass* ik) { assert(ik->has_aot_initialized_mirror(), "sanity"); if (ik->is_runtime_setup_required()) { - if (log_is_enabled(Info, cds, init)) { + if (log_is_enabled(Info, aot, init)) { ResourceMark rm; - log_info(cds, init)("Calling %s::runtimeSetup()", ik->external_name()); + log_info(aot, init)("Calling %s::runtimeSetup()", ik->external_name()); } JavaValue result(T_VOID); JavaCalls::call_static(&result, ik, @@ -369,7 +375,7 @@ void AOTClassInitializer::init_test_class(TRAPS) { // -XX:AOTInitTestClass is NOT a general mechanism for including user-defined objects into // the AOT cache. Therefore, this option is NOT available in product JVM. if (AOTInitTestClass != nullptr && CDSConfig::is_initing_classes_at_dump_time()) { - log_info(cds)("Debug build only: force initialization of AOTInitTestClass %s", AOTInitTestClass); + log_info(aot)("Debug build only: force initialization of AOTInitTestClass %s", AOTInitTestClass); TempNewSymbol class_name = SymbolTable::new_symbol(AOTInitTestClass); Handle app_loader(THREAD, SystemDictionary::java_system_loader()); Klass* k = SystemDictionary::resolve_or_null(class_name, app_loader, CHECK); diff --git a/src/hotspot/share/cds/aotClassLinker.cpp b/src/hotspot/share/cds/aotClassLinker.cpp index dc539eb3d55..47c7f6e3bf8 100644 --- a/src/hotspot/share/cds/aotClassLinker.cpp +++ b/src/hotspot/share/cds/aotClassLinker.cpp @@ -64,8 +64,6 @@ void AOTClassLinker::initialize() { } assert(is_initialized(), "sanity"); - - AOTConstantPoolResolver::initialize(); } void AOTClassLinker::dispose() { @@ -79,8 +77,6 @@ void AOTClassLinker::dispose() { _sorted_candidates = nullptr; assert(!is_initialized(), "sanity"); - - AOTConstantPoolResolver::dispose(); } bool AOTClassLinker::is_vm_class(InstanceKlass* ik) { @@ -117,9 +113,9 @@ void AOTClassLinker::add_new_candidate(InstanceKlass* ik) { _candidates->put_when_absent(ik, true); _sorted_candidates->append(ik); - if (log_is_enabled(Info, cds, aot, link)) { + if (log_is_enabled(Info, aot, link)) { ResourceMark rm; - log_info(cds, aot, link)("%s %s %p", class_category_name(ik), ik->external_name(), ik); + log_info(aot, link)("%s %s %p", class_category_name(ik), ik->external_name(), ik); } } @@ -141,7 +137,7 @@ bool AOTClassLinker::try_add_candidate(InstanceKlass* ik) { } if (ik->is_hidden()) { - assert(ik->shared_class_loader_type() != ClassLoader::OTHER, "must have been set"); + assert(!ik->defined_by_other_loaders(), "hidden classes are archived only for builtin loaders"); if (!CDSConfig::is_dumping_method_handles()) { return false; } @@ -149,7 +145,7 @@ bool AOTClassLinker::try_add_candidate(InstanceKlass* ik) { InstanceKlass* nest_host = ik->nest_host_not_null(); if (!try_add_candidate(nest_host)) { ResourceMark rm; - log_warning(cds, aot, link)("%s cannot be aot-linked because it nest host is not aot-linked", ik->external_name()); + log_warning(aot, link)("%s cannot be aot-linked because it nest host is not aot-linked", ik->external_name()); return false; } } @@ -232,7 +228,7 @@ Array* AOTClassLinker::write_classes(oop class_loader, bool is_j return nullptr; } else { const char* category = class_category_name(list.at(0)); - log_info(cds, aot, link)("wrote %d class(es) for category %s", list.length(), category); + log_info(aot, link)("wrote %d class(es) for category %s", list.length(), category); return ArchiveUtils::archive_array(&list); } } diff --git a/src/hotspot/share/cds/aotClassLocation.cpp b/src/hotspot/share/cds/aotClassLocation.cpp index 8471d04b572..b662c5a1b47 100644 --- a/src/hotspot/share/cds/aotClassLocation.cpp +++ b/src/hotspot/share/cds/aotClassLocation.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotClassLocation.hpp" +#include "cds/aotLogging.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/dynamicArchive.hpp" @@ -250,7 +251,7 @@ AOTClassLocation* AOTClassLocation::allocate(JavaThread* current, const char* pa // We allow the file to not exist, as long as it also doesn't exist during runtime. type = FileType::NOT_EXIST; } else { - log_error(cds)("Unable to open file %s.", path); + aot_log_error(aot)("Unable to open file %s.", path); MetaspaceShared::unrecoverable_loading_error(); } @@ -359,7 +360,7 @@ char* AOTClassLocation::get_cpattr() const { if (found != nullptr) { // Same behavior as jdk/src/share/classes/java/util/jar/Attributes.java // If duplicated entries are found, the last one is used. - log_warning(cds)("Warning: Duplicate name in Manifest: %s.\n" + log_warning(aot)("Warning: Duplicate name in Manifest: %s.\n" "Ensure that the manifest does not have duplicate entries, and\n" "that blank lines separate individual sections in both your\n" "manifest and in the META-INF/MANIFEST.MF entry in the jar file:\n%s\n", tag, path()); @@ -392,31 +393,31 @@ bool AOTClassLocation::check(const char* runtime_path, bool has_aot_linked_class struct stat st; if (os::stat(runtime_path, &st) != 0) { if (_file_type != FileType::NOT_EXIST) { - log_warning(cds)("Required classpath entry does not exist: %s", runtime_path); + aot_log_warning(aot)("Required classpath entry does not exist: %s", runtime_path); return false; } } else if ((st.st_mode & S_IFMT) == S_IFDIR) { if (_file_type == FileType::NOT_EXIST) { - log_warning(cds)("'%s' must not exist", runtime_path); + aot_log_warning(aot)("'%s' must not exist", runtime_path); return false; } if (_file_type == FileType::NORMAL) { - log_warning(cds)("'%s' must be a file", runtime_path); + aot_log_warning(aot)("'%s' must be a file", runtime_path); return false; } if (!os::dir_is_empty(runtime_path)) { - log_warning(cds)("directory is not empty: '%s'", runtime_path); + aot_log_warning(aot)("directory is not empty: '%s'", runtime_path); return false; } } else { if (_file_type == FileType::NOT_EXIST) { - log_warning(cds)("'%s' must not exist", runtime_path); + aot_log_warning(aot)("'%s' must not exist", runtime_path); if (has_aot_linked_classes) { - log_error(cds)("CDS archive has aot-linked classes. It cannot be used because the " + aot_log_error(aot)("CDS archive has aot-linked classes. It cannot be used because the " "file %s exists", runtime_path); return false; } else { - log_warning(cds)("Archived non-system classes are disabled because the " + aot_log_warning(aot)("Archived non-system classes are disabled because the " "file %s exists", runtime_path); FileMapInfo::current_info()->set_has_platform_or_app_classes(false); if (DynamicArchive::is_mapped()) { @@ -425,13 +426,13 @@ bool AOTClassLocation::check(const char* runtime_path, bool has_aot_linked_class } } if (_file_type == FileType::DIR) { - log_warning(cds)("'%s' must be a directory", runtime_path); + aot_log_warning(aot)("'%s' must be a directory", runtime_path); return false; } bool size_differs = _filesize != st.st_size; bool time_differs = _check_time && (_timestamp != st.st_mtime); if (size_differs || time_differs) { - log_warning(cds)("This file is not the one used while building the shared archive file: '%s'%s%s", + aot_log_warning(aot)("This file is not the one used while building the shared archive file: '%s'%s%s", runtime_path, time_differs ? ", timestamp has changed" : "", size_differs ? ", size has changed" : ""); @@ -463,6 +464,7 @@ void AOTClassLocationConfig::dumptime_init_helper(TRAPS) { AOTClassLocation* jrt = AOTClassLocation::allocate(THREAD, ClassLoader::get_jrt_entry()->name(), 0, Group::MODULES_IMAGE, /*from_cpattr*/false, /*is_jrt*/true); + log_info(class, path)("path [%d] = (modules image)", tmp_array.length()); tmp_array.append(jrt); parse(THREAD, tmp_array, all_css.boot_cp(), Group::BOOT_CLASSPATH, /*parse_manifest*/true); @@ -489,8 +491,8 @@ void AOTClassLocationConfig::dumptime_init_helper(TRAPS) { const char* lcp = find_lcp(all_css.boot_and_app_cp(), _dumptime_lcp_len); if (_dumptime_lcp_len > 0) { - os::free((void*)lcp); log_info(class, path)("Longest common prefix = %s (%zu chars)", lcp, _dumptime_lcp_len); + os::free((void*)lcp); } else { assert(_dumptime_lcp_len == 0, "sanity"); log_info(class, path)("Longest common prefix = (0 chars)"); @@ -572,6 +574,7 @@ void AOTClassLocationConfig::parse(JavaThread* current, GrowableClassLocationArr void AOTClassLocationConfig::add_class_location(JavaThread* current, GrowableClassLocationArray& tmp_array, const char* path, Group group, bool parse_manifest, bool from_cpattr) { AOTClassLocation* cs = AOTClassLocation::allocate(current, path, tmp_array.length(), group, from_cpattr); + log_info(class, path)("path [%d] = %s%s", tmp_array.length(), path, from_cpattr ? " (from cpattr)" : ""); tmp_array.append(cs); if (!parse_manifest) { @@ -689,7 +692,7 @@ void AOTClassLocationConfig::check_nonempty_dirs() const { } if (cs->is_dir()) { if (!os::dir_is_empty(cs->path())) { - log_error(cds)("Error: non-empty directory '%s'", cs->path()); + aot_log_error(aot)("Error: non-empty directory '%s'", cs->path()); has_nonempty_dir = true; } } @@ -714,7 +717,7 @@ bool AOTClassLocationConfig::is_valid_classpath_index(int classpath_index, Insta const char* const file_name = ClassLoader::file_name_for_class_name(class_name, ik->name()->utf8_length()); if (!zip->has_entry(current, file_name)) { - log_warning(cds)("class %s cannot be archived because it was not defined from %s as claimed", + aot_log_warning(aot)("class %s cannot be archived because it was not defined from %s as claimed", class_name, zip->name()); return false; } @@ -725,6 +728,8 @@ bool AOTClassLocationConfig::is_valid_classpath_index(int classpath_index, Insta } AOTClassLocationConfig* AOTClassLocationConfig::write_to_archive() const { + log_locations(CDSConfig::output_archive_path(), /*is_write=*/true); + Array* archived_copy = ArchiveBuilder::new_ro_array(_class_locations->length()); for (int i = 0; i < _class_locations->length(); i++) { archived_copy->at_put(i, _class_locations->at(i)->write_to_archive()); @@ -772,11 +777,11 @@ bool AOTClassLocationConfig::check_classpaths(bool is_boot_classpath, bool has_a effective_dumptime_path = substitute(effective_dumptime_path, _dumptime_lcp_len, runtime_lcp, runtime_lcp_len); } - log_info(class, path)("Checking '%s' %s%s", effective_dumptime_path, cs->file_type_string(), + log_info(class, path)("Checking [%d] '%s' %s%s", i, effective_dumptime_path, cs->file_type_string(), cs->from_cpattr() ? " (from JAR manifest ClassPath attribute)" : ""); if (!cs->from_cpattr() && file_exists(effective_dumptime_path)) { if (!runtime_css.has_next()) { - log_warning(cds)("%s classpath has fewer elements than expected", which); + aot_log_warning(aot)("%s classpath has fewer elements than expected", which); return false; } const char* runtime_path = runtime_css.get_next(); @@ -784,7 +789,7 @@ bool AOTClassLocationConfig::check_classpaths(bool is_boot_classpath, bool has_a runtime_path = runtime_css.get_next(); } if (!os::same_files(effective_dumptime_path, runtime_path)) { - log_warning(cds)("The name of %s classpath [%d] does not match: expected '%s', got '%s'", + aot_log_warning(aot)("The name of %s classpath [%d] does not match: expected '%s', got '%s'", which, runtime_css.current(), effective_dumptime_path, runtime_path); return false; } @@ -800,7 +805,7 @@ bool AOTClassLocationConfig::check_classpaths(bool is_boot_classpath, bool has_a if (is_boot_classpath && runtime_css.has_next() && (need_to_check_app_classpath() || num_module_paths() > 0)) { // the check passes if all the extra runtime boot classpath entries are non-existent if (check_paths_existence(runtime_css)) { - log_warning(cds)("boot classpath is longer than expected"); + aot_log_warning(aot)("boot classpath is longer than expected"); return false; } } @@ -869,7 +874,7 @@ bool AOTClassLocationConfig::check_module_paths(bool has_aot_linked_classes, int while (true) { if (!runtime_css.has_next()) { - log_warning(cds)("module path has fewer elements than expected"); + aot_log_warning(aot)("module path has fewer elements than expected"); *has_extra_module_paths = true; return true; } @@ -960,11 +965,14 @@ bool AOTClassLocationConfig::need_lcp_match_helper(int start, int end, ClassLoca return true; } -bool AOTClassLocationConfig::validate(bool has_aot_linked_classes, bool* has_extra_module_paths) const { +bool AOTClassLocationConfig::validate(const char* cache_filename, bool has_aot_linked_classes, bool* has_extra_module_paths) const { ResourceMark rm; AllClassLocationStreams all_css; + log_locations(cache_filename, /*is_write=*/false); + const char* jrt = ClassLoader::get_jrt_entry()->name(); + log_info(class, path)("Checking [0] (modules image)"); bool success = class_location_at(0)->check(jrt, has_aot_linked_classes); log_info(class, path)("Modules image %s validation: %s", jrt, success ? "passed" : "failed"); if (!success) { @@ -1021,16 +1029,63 @@ bool AOTClassLocationConfig::validate(bool has_aot_linked_classes, bool* has_ext "" : " (hint: enable -Xlog:class+path=info to diagnose the failure)"; if (RequireSharedSpaces && !PrintSharedArchiveAndExit) { if (CDSConfig::is_dumping_final_static_archive()) { - log_error(cds)("class path and/or module path are not compatible with the " + aot_log_error(aot)("class path and/or module path are not compatible with the " "ones specified when the AOTConfiguration file was recorded%s", hint_msg); vm_exit_during_initialization("Unable to use create AOT cache.", nullptr); } else { - log_error(cds)("%s%s", mismatch_msg, hint_msg); + aot_log_error(aot)("%s%s", mismatch_msg, hint_msg); MetaspaceShared::unrecoverable_loading_error(); } } else { - log_warning(cds)("%s%s", mismatch_msg, hint_msg); + MetaspaceShared::report_loading_error("%s%s", mismatch_msg, hint_msg); } } return success; } + +void AOTClassLocationConfig::log_locations(const char* cache_filename, bool is_write) const { + if (log_is_enabled(Info, class, path)) { + LogStreamHandle(Info, class, path) st; + st.print_cr("%s classpath(s) %s %s (size = %d)", + is_write ? "Writing" : "Reading", + is_write ? "into" : "from", + cache_filename, class_locations()->length()); + print_on(&st); + } +} + +void AOTClassLocationConfig::print() { + if (CDSConfig::is_dumping_archive()) { + tty->print_cr("AOTClassLocationConfig::_dumptime_instance = %p", _dumptime_instance); + if (_dumptime_instance != nullptr) { + _dumptime_instance->print_on(tty); + } + } + if (CDSConfig::is_using_archive()) { + tty->print_cr("AOTClassLocationConfig::_runtime_instance = %p", _runtime_instance); + if (_runtime_instance != nullptr) { + _runtime_instance->print_on(tty); + } + } +} + +void AOTClassLocationConfig::print_on(outputStream* st) const { + const char* type = "boot"; + int n = class_locations()->length(); + for (int i = 0; i < n; i++) { + if (i >= boot_cp_end_index()) { + type = "app"; + } + if (i >= app_cp_end_index()) { + type = "module"; + } + const AOTClassLocation* cs = class_location_at(i); + const char* path; + if (i == 0) { + path = ClassLoader::get_jrt_entry()->name(); + } else { + path = cs->path(); + } + st->print_cr("(%-6s) [%d] = %s", type, i, path); + } +} diff --git a/src/hotspot/share/cds/aotClassLocation.hpp b/src/hotspot/share/cds/aotClassLocation.hpp index 47f4dc86c98..460788930a4 100644 --- a/src/hotspot/share/cds/aotClassLocation.hpp +++ b/src/hotspot/share/cds/aotClassLocation.hpp @@ -31,6 +31,7 @@ #include "utilities/growableArray.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include "utilities/ostream.hpp" class AllClassLocationStreams; class ClassLocationStream; @@ -201,6 +202,10 @@ class AOTClassLocationConfig : public CHeapObj { void print_dumptime_classpath(LogStream& ls, int index_start, int index_limit, bool do_substitute, size_t remove_prefix_len, const char* prepend, size_t prepend_len) const; + + void print_on(outputStream* st) const; + void log_locations(const char* cache_filename, bool is_writing) const; + public: static AOTClassLocationConfig* dumptime() { assert(_dumptime_instance != nullptr, "can only be called when dumping an AOT cache"); @@ -265,9 +270,11 @@ class AOTClassLocationConfig : public CHeapObj { AOTClassLocationConfig* write_to_archive() const; // Functions used only during runtime - bool validate(bool has_aot_linked_classes, bool* has_extra_module_paths) const; + bool validate(const char* cache_filename, bool has_aot_linked_classes, bool* has_extra_module_paths) const; bool is_valid_classpath_index(int classpath_index, InstanceKlass* ik); + + static void print(); }; diff --git a/src/hotspot/share/cds/aotConstantPoolResolver.cpp b/src/hotspot/share/cds/aotConstantPoolResolver.cpp index 15ca2b2c2a0..6ab63418e09 100644 --- a/src/hotspot/share/cds/aotConstantPoolResolver.cpp +++ b/src/hotspot/share/cds/aotConstantPoolResolver.cpp @@ -37,19 +37,6 @@ #include "oops/klass.inline.hpp" #include "runtime/handles.inline.hpp" -AOTConstantPoolResolver::ClassesTable* AOTConstantPoolResolver::_processed_classes = nullptr; - -void AOTConstantPoolResolver::initialize() { - assert(_processed_classes == nullptr, "must be"); - _processed_classes = new (mtClass)ClassesTable(); -} - -void AOTConstantPoolResolver::dispose() { - assert(_processed_classes != nullptr, "must be"); - delete _processed_classes; - _processed_classes = nullptr; -} - // Returns true if we CAN PROVE that cp_index will always resolve to // the same information at both dump time and run time. This is a // necessary (but not sufficient) condition for pre-resolving cp_index @@ -144,17 +131,11 @@ bool AOTConstantPoolResolver::is_class_resolution_deterministic(InstanceKlass* c } } -void AOTConstantPoolResolver::dumptime_resolve_constants(InstanceKlass* ik, TRAPS) { +void AOTConstantPoolResolver::preresolve_string_cp_entries(InstanceKlass* ik, TRAPS) { if (!ik->is_linked()) { + // The cp->resolved_referenced() array is not ready yet, so we can't call resolve_string(). return; } - bool first_time; - _processed_classes->put_if_absent(ik, &first_time); - if (!first_time) { - // We have already resolved the constants in class, so no need to do it again. - return; - } - constantPoolHandle cp(THREAD, ik->constants()); for (int cp_index = 1; cp_index < cp->length(); cp_index++) { // Index 0 is unused switch (cp->tag_at(cp_index).value()) { @@ -223,7 +204,7 @@ void AOTConstantPoolResolver::preresolve_class_cp_entries(JavaThread* current, I if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; // just ignore } else { - log_trace(cds, resolve)("Resolved class [%3d] %s -> %s", cp_index, ik->external_name(), + log_trace(aot, resolve)("Resolved class [%3d] %s -> %s", cp_index, ik->external_name(), resolved_klass->external_name()); } } @@ -311,12 +292,12 @@ void AOTConstantPoolResolver::maybe_resolve_fmi_ref(InstanceKlass* ik, Method* m ShouldNotReachHere(); } - if (log_is_enabled(Trace, cds, resolve)) { + if (log_is_enabled(Trace, aot, resolve)) { ResourceMark rm(THREAD); bool resolved = cp->is_resolved(raw_index, bc); Symbol* name = cp->name_ref_at(raw_index, bc); Symbol* signature = cp->signature_ref_at(raw_index, bc); - log_trace(cds, resolve)("%s %s [%3d] %s -> %s.%s:%s", + log_trace(aot, resolve)("%s %s [%3d] %s -> %s.%s:%s", (resolved ? "Resolved" : "Failed to resolve"), Bytecodes::name(bc), cp_index, ik->external_name(), resolved_klass->external_name(), @@ -345,9 +326,9 @@ void AOTConstantPoolResolver::preresolve_indy_cp_entries(JavaThread* current, In CLEAR_PENDING_EXCEPTION; // just ignore } } - if (log_is_enabled(Trace, cds, resolve)) { + if (log_is_enabled(Trace, aot, resolve)) { ResourceMark rm(THREAD); - log_trace(cds, resolve)("%s indy [%3d] %s", + log_trace(aot, resolve)("%s indy [%3d] %s", rie->is_resolved() ? "Resolved" : "Failed to resolve", cp_index, ik->external_name()); } @@ -369,9 +350,9 @@ bool AOTConstantPoolResolver::check_methodtype_signature(ConstantPool* cp, Symbo } if (SystemDictionaryShared::should_be_excluded(k)) { - if (log_is_enabled(Warning, cds, resolve)) { + if (log_is_enabled(Warning, aot, resolve)) { ResourceMark rm; - log_warning(cds, resolve)("Cannot aot-resolve Lambda proxy because %s is excluded", k->external_name()); + log_warning(aot, resolve)("Cannot aot-resolve Lambda proxy because %s is excluded", k->external_name()); } return false; } @@ -402,9 +383,9 @@ bool AOTConstantPoolResolver::check_lambda_metafactory_signature(ConstantPool* c // as can have side effects ==> exclude such cases. InstanceKlass* intf = InstanceKlass::cast(k); bool exclude = intf->interface_needs_clinit_execution_as_super(); - if (log_is_enabled(Debug, cds, resolve)) { + if (log_is_enabled(Debug, aot, resolve)) { ResourceMark rm; - log_debug(cds, resolve)("%s aot-resolve Lambda proxy of interface type %s", + log_debug(aot, resolve)("%s aot-resolve Lambda proxy of interface type %s", exclude ? "Cannot" : "Can", k->external_name()); } return !exclude; @@ -418,9 +399,9 @@ bool AOTConstantPoolResolver::check_lambda_metafactory_methodtype_arg(ConstantPo } Symbol* sig = cp->method_type_signature_at(mt_index); - if (log_is_enabled(Debug, cds, resolve)) { + if (log_is_enabled(Debug, aot, resolve)) { ResourceMark rm; - log_debug(cds, resolve)("Checking MethodType for LambdaMetafactory BSM arg %d: %s", arg_i, sig->as_C_string()); + log_debug(aot, resolve)("Checking MethodType for LambdaMetafactory BSM arg %d: %s", arg_i, sig->as_C_string()); } return check_methodtype_signature(cp, sig); @@ -434,9 +415,9 @@ bool AOTConstantPoolResolver::check_lambda_metafactory_methodhandle_arg(Constant } Symbol* sig = cp->method_handle_signature_ref_at(mh_index); - if (log_is_enabled(Debug, cds, resolve)) { + if (log_is_enabled(Debug, aot, resolve)) { ResourceMark rm; - log_debug(cds, resolve)("Checking MethodType of MethodHandle for LambdaMetafactory BSM arg %d: %s", arg_i, sig->as_C_string()); + log_debug(aot, resolve)("Checking MethodType of MethodHandle for LambdaMetafactory BSM arg %d: %s", arg_i, sig->as_C_string()); } return check_methodtype_signature(cp, sig); } @@ -471,9 +452,9 @@ bool AOTConstantPoolResolver::is_indy_resolution_deterministic(ConstantPool* cp, "[Ljava/lang/Object;" ")Ljava/lang/invoke/CallSite;")) { Symbol* factory_type_sig = cp->uncached_signature_ref_at(cp_index); - if (log_is_enabled(Debug, cds, resolve)) { + if (log_is_enabled(Debug, aot, resolve)) { ResourceMark rm; - log_debug(cds, resolve)("Checking StringConcatFactory callsite signature [%d]: %s", cp_index, factory_type_sig->as_C_string()); + log_debug(aot, resolve)("Checking StringConcatFactory callsite signature [%d]: %s", cp_index, factory_type_sig->as_C_string()); } Klass* k; @@ -523,9 +504,9 @@ bool AOTConstantPoolResolver::is_indy_resolution_deterministic(ConstantPool* cp, * {@code interfaceMethodType}. */ Symbol* factory_type_sig = cp->uncached_signature_ref_at(cp_index); - if (log_is_enabled(Debug, cds, resolve)) { + if (log_is_enabled(Debug, aot, resolve)) { ResourceMark rm; - log_debug(cds, resolve)("Checking indy callsite signature [%d]: %s", cp_index, factory_type_sig->as_C_string()); + log_debug(aot, resolve)("Checking lambda callsite signature [%d]: %s", cp_index, factory_type_sig->as_C_string()); } if (!check_lambda_metafactory_signature(cp, factory_type_sig)) { diff --git a/src/hotspot/share/cds/aotConstantPoolResolver.hpp b/src/hotspot/share/cds/aotConstantPoolResolver.hpp index 2f65849fbb4..89d9d5c2476 100644 --- a/src/hotspot/share/cds/aotConstantPoolResolver.hpp +++ b/src/hotspot/share/cds/aotConstantPoolResolver.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,17 +80,10 @@ class AOTConstantPoolResolver : AllStatic { static bool check_lambda_metafactory_methodhandle_arg(ConstantPool* cp, int bsms_attribute_index, int arg_i); public: - static void initialize(); - static void dispose(); - static void preresolve_class_cp_entries(JavaThread* current, InstanceKlass* ik, GrowableArray* preresolve_list); static void preresolve_field_and_method_cp_entries(JavaThread* current, InstanceKlass* ik, GrowableArray* preresolve_list); static void preresolve_indy_cp_entries(JavaThread* current, InstanceKlass* ik, GrowableArray* preresolve_list); - - - // Resolve all constant pool entries that are safe to be stored in the - // CDS archive. - static void dumptime_resolve_constants(InstanceKlass* ik, TRAPS); + static void preresolve_string_cp_entries(InstanceKlass* ik, TRAPS); static bool is_resolution_deterministic(ConstantPool* cp, int cp_index); }; diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp index 31d95024e3b..39236975782 100644 --- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp +++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.cpp @@ -32,10 +32,12 @@ #include "classfile/systemDictionary.hpp" #include "classfile/systemDictionaryShared.hpp" #include "classfile/vmClasses.hpp" +#include "compiler/compilationPolicy.hpp" #include "gc/shared/gcVMOperations.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" +#include "oops/trainingData.hpp" #include "runtime/handles.inline.hpp" #include "runtime/java.hpp" @@ -48,6 +50,17 @@ void AOTLinkedClassBulkLoader::serialize(SerializeClosure* soc, bool is_static_a AOTLinkedClassTable::get(is_static_archive)->serialize(soc); } +bool AOTLinkedClassBulkLoader::class_preloading_finished() { + if (!CDSConfig::is_using_aot_linked_classes()) { + return true; + } else { + // The ConstantPools of preloaded classes have references to other preloaded classes. We don't + // want any Java code (including JVMCI compiler) to use these classes until all of them + // are loaded. + return Atomic::load_acquire(&_all_completed); + } +} + void AOTLinkedClassBulkLoader::load_javabase_classes(JavaThread* current) { assert(CDSConfig::is_using_aot_linked_classes(), "sanity"); load_classes_in_loader(current, AOTLinkedClassCategory::BOOT1, nullptr); // only java.base classes @@ -70,8 +83,14 @@ void AOTLinkedClassBulkLoader::load_non_javabase_classes(JavaThread* current) { _platform_completed = true; load_classes_in_loader(current, AOTLinkedClassCategory::APP, SystemDictionary::java_system_loader()); + + if (AOTPrintTrainingInfo) { + tty->print_cr("==================== archived_training_data ** after all classes preloaded ===================="); + TrainingData::print_archived_training_data_on(tty); + } + _app_completed = true; - _all_completed = true; + Atomic::release_store(&_all_completed, true); } void AOTLinkedClassBulkLoader::load_classes_in_loader(JavaThread* current, AOTLinkedClassCategory class_category, oop class_loader_oop) { @@ -87,10 +106,10 @@ void AOTLinkedClassBulkLoader::exit_on_exception(JavaThread* current) { assert(current->has_pending_exception(), "precondition"); ResourceMark rm(current); if (current->pending_exception()->is_a(vmClasses::OutOfMemoryError_klass())) { - log_error(cds)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " + log_error(aot)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " "%zuM", MaxHeapSize/M); } else { - log_error(cds)("%s: %s", current->pending_exception()->klass()->external_name(), + log_error(aot)("%s: %s", current->pending_exception()->klass()->external_name(), java_lang_String::as_utf8_string(java_lang_Throwable::message(current->pending_exception()))); } vm_exit_during_initialization("Unexpected exception when loading aot-linked classes."); @@ -179,11 +198,11 @@ void AOTLinkedClassBulkLoader::load_classes_impl(AOTLinkedClassCategory class_ca for (int i = 0; i < classes->length(); i++) { InstanceKlass* ik = classes->at(i); - if (log_is_enabled(Info, cds, aot, load)) { + if (log_is_enabled(Info, aot, load)) { ResourceMark rm(THREAD); - log_info(cds, aot, load)("%-5s %s%s%s", category_name, ik->external_name(), - ik->is_loaded() ? " (already loaded)" : "", - ik->is_hidden() ? " (hidden)" : ""); + log_info(aot, load)("%-5s %s%s%s", category_name, ik->external_name(), + ik->is_loaded() ? " (already loaded)" : "", + ik->is_hidden() ? " (hidden)" : ""); } if (!ik->is_loaded()) { @@ -199,9 +218,9 @@ void AOTLinkedClassBulkLoader::load_classes_impl(AOTLinkedClassCategory class_ca if (actual != ik) { ResourceMark rm(THREAD); - log_error(cds)("Unable to resolve %s class from CDS archive: %s", category_name, ik->external_name()); - log_error(cds)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual)); - log_error(cds)("JVMTI class retransformation is not supported when archive was generated with -XX:+AOTClassLinking."); + log_error(aot)("Unable to resolve %s class from %s: %s", category_name, CDSConfig::type_of_archive_being_loaded(), ik->external_name()); + log_error(aot)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual)); + log_error(aot)("JVMTI class retransformation is not supported when archive was generated with -XX:+AOTClassLinking."); MetaspaceShared::unrecoverable_loading_error(); } assert(actual->is_loaded(), "must be"); @@ -236,11 +255,11 @@ void AOTLinkedClassBulkLoader::initiate_loading(JavaThread* current, const char* assert(ik->class_loader() == nullptr || ik->class_loader() == SystemDictionary::java_platform_loader(), "must be"); if (ik->is_public() && !ik->is_hidden()) { - if (log_is_enabled(Info, cds, aot, load)) { + if (log_is_enabled(Info, aot, load)) { ResourceMark rm(current); const char* defining_loader = (ik->class_loader() == nullptr ? "boot" : "plat"); - log_info(cds, aot, load)("%s %s (initiated, defined by %s)", category_name, ik->external_name(), - defining_loader); + log_info(aot, load)("%s %s (initiated, defined by %s)", category_name, ik->external_name(), + defining_loader); } SystemDictionary::add_to_initiating_loader(current, ik, loader_data); } @@ -372,7 +391,7 @@ bool AOTLinkedClassBulkLoader::is_pending_aot_linked_class(Klass* k) { // the four AOTLinkedClassCategory of classes that can be aot-linked. InstanceKlass* ik = InstanceKlass::cast(k); - if (ik->is_shared_boot_class()) { + if (ik->defined_by_boot_loader()) { if (ik->module() != nullptr && ik->in_javabase_module()) { // AOTLinkedClassCategory::BOOT1 -- all aot-linked classes in // java.base must have been loaded before a GC can ever happen. @@ -382,11 +401,11 @@ bool AOTLinkedClassBulkLoader::is_pending_aot_linked_class(Klass* k) { // module system is ready. return !_boot2_completed; } - } else if (ik->is_shared_platform_class()) { + } else if (ik->defined_by_platform_loader()) { // AOTLinkedClassCategory::PLATFORM classes cannot be loaded until // the platform class loader is initialized. return !_platform_completed; - } else if (ik->is_shared_app_class()) { + } else if (ik->defined_by_app_loader()) { // AOTLinkedClassCategory::APP cannot be loaded until the app class loader // is initialized. return !_app_completed; @@ -394,3 +413,25 @@ bool AOTLinkedClassBulkLoader::is_pending_aot_linked_class(Klass* k) { return false; } } + +void AOTLinkedClassBulkLoader::replay_training_at_init(Array* classes, TRAPS) { + if (classes != nullptr) { + for (int i = 0; i < classes->length(); i++) { + InstanceKlass* ik = classes->at(i); + if (ik->has_aot_initialized_mirror() && ik->is_initialized() && !ik->has_init_deps_processed()) { + CompilationPolicy::replay_training_at_init(ik, CHECK); + } + } + } +} + +void AOTLinkedClassBulkLoader::replay_training_at_init_for_preloaded_classes(TRAPS) { + if (CDSConfig::is_using_aot_linked_classes() && TrainingData::have_data()) { + // Only static archive can have training data. + AOTLinkedClassTable* table = AOTLinkedClassTable::for_static_archive(); + replay_training_at_init(table->boot(), CHECK); + replay_training_at_init(table->boot2(), CHECK); + replay_training_at_init(table->platform(), CHECK); + replay_training_at_init(table->app(), CHECK); + } +} \ No newline at end of file diff --git a/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp b/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp index a8e6365b899..86fb5017eb8 100644 --- a/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp +++ b/src/hotspot/share/cds/aotLinkedClassBulkLoader.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,7 @@ class AOTLinkedClassBulkLoader : AllStatic { const char* category_name, Handle loader, TRAPS); static void load_hidden_class(ClassLoaderData* loader_data, InstanceKlass* ik, TRAPS); static void init_required_classes_for_loader(Handle class_loader, Array* classes, TRAPS); + static void replay_training_at_init(Array* classes, TRAPS) NOT_CDS_RETURN; public: static void serialize(SerializeClosure* soc, bool is_static_archive) NOT_CDS_RETURN; @@ -63,6 +64,8 @@ class AOTLinkedClassBulkLoader : AllStatic { static void finish_loading_javabase_classes(TRAPS) NOT_CDS_RETURN; static void exit_on_exception(JavaThread* current); + static void replay_training_at_init_for_preloaded_classes(TRAPS) NOT_CDS_RETURN; + static bool class_preloading_finished(); static bool is_pending_aot_linked_class(Klass* k) NOT_CDS_RETURN_(false); }; diff --git a/src/hotspot/share/cds/aotLogging.hpp b/src/hotspot/share/cds/aotLogging.hpp new file mode 100644 index 00000000000..f9515341d72 --- /dev/null +++ b/src/hotspot/share/cds/aotLogging.hpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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_CDS_AOTLOGGING_HPP +#define SHARE_CDS_AOTLOGGING_HPP + +#include "cds/cds_globals.hpp" +#include "cds/cdsConfig.hpp" +#include "logging/log.hpp" + +// UL Logging for AOT +// ================== +// +// The old "CDS" feature is rebranded as "AOT" in JEP 483. Therefore, UL logging +// related to the AOT features should be using the [aot] tag. +// +// However, some old scripts may be using -Xlog:cds for diagnostic purposes. To +// provide a fair amount of backwards compatibility for such scripts, some AOT +// logs that are likely to be used by such scripts are printed using the macros +// in this header file. +// +// NOTE: MOST of the AOT logs will be using the usual macros such as log_info(aot)(...). +// The information below does NOT apply to such logs. +// +// CDS Compatibility Logs & Compatibility Macros +// ============================================= +// +// A subset of the original CDS logs (the "CDS Compatibility Logs") have been +// chosen in JDK 25. These logs are guarded using the aot_log_xxx compatibility +// macros. Before JDK 25, such code looked like this: +// +// log_info(cds)("trying to map %s%s", info, _full_path); +// log_warning(cds)("Unable to read the file header."); +// +// New code since JDK 25: +// +// aot_log_info(aot)("trying to map %s%s", info, _full_path); +// aot_log_warning(aot)("Unable to read the file header."); +// +// The messages printed with the log_aot_xxx() macros work as if they are +// using the [cds] tag when running with the "classic" CDS workflow (i.e., +// new -XX:AOTxxx flags are not used). +// +// $ java -Xlog:cds -XX:SharedArchiveFile=bad.jsa ... +// [0.020s][info][cds] trying to map bad.jsa +// [0.020s][warning][cds] Unable to read the file header +// +// However, when running new AOT flags such as-XX:AOTCache, these messages are +// under the [aot] tag: +// +// $ java -Xlog:aot -XX:AOTCache=bad.aot ... +// [0.020s][info][aot] trying to map bad.aot +// [0.020s][warning][aot] Unable to read the file header +// +// Rules on selection and printing +// +// [1] When using AOT cache +// - These logs are selected via the aot tag, and not the cds tag. +// They are always printed with [aot] decoration +// +// [2] When using CDS archives +// - These logs are selected via the cds tag, and not the aot tag. +// They are always printed with [cds] decoration +// +// Deprecation Process +// =================== +// +// This is modeled after the deprecate/obsolete/expire process of VM options in arguments.cpp +// +// JDK 25 - When no -XX:AOTxxx flags are used, the CDS Compatibility Logs must be selected +// with -Xlog:cds +// +// JDK 26 - Same as above, except that when -Xlog:cds is specified in the command-line, a warning +// message is printed to indicate that -Xlog:cds is deprecated. +// +// JDK 27 - The CDS Compatibility Logs must be selected with -Xlog:aot. +// +// When -Xlog:cds is specified in the command-line, a warning message is printed to +// indicate that -Xlog:cds is obsolete. +// +// JDK 28 - When -Xlog:cds is specified in the command-line, the VM will exit with an error message: +// +// [0.002s][error][logging] Invalid tag 'cds' in log selection. +// Invalid -Xlog option '-Xlog:cds', see error log for details. +// + +// The following macros are inspired by the same macros (without the aot_ prefix) in logging/log.hpp + +#define aot_log_is_enabled(level, ...) (AOTLogImpl::is_level(LogLevel::level)) + +#define aot_log_error(...) (!aot_log_is_enabled(Error, __VA_ARGS__)) ? (void)0 : AOTLogImpl::write +#define aot_log_warning(...) (!aot_log_is_enabled(Warning, __VA_ARGS__)) ? (void)0 : AOTLogImpl::write +#define aot_log_info(...) (!aot_log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : AOTLogImpl::write +#define aot_log_debug(...) (!aot_log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : AOTLogImpl::write +#define aot_log_trace(...) (!aot_log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : AOTLogImpl::write + +template +class AOTLogImpl { + public: + // Make sure no more than the maximum number of tags have been given. + // The GuardTag allows this to be detected if/when it happens. If the GuardTag + // is not __NO_TAG, the number of tags given exceeds the maximum allowed. + STATIC_ASSERT(GuardTag == LogTag::__NO_TAG); // Number of logging tags exceeds maximum supported! + + // Empty constructor to avoid warnings on MSVC about unused variables + // when the log instance is only used for static functions. + AOTLogImpl() { + } + + static bool is_level(LogLevelType level) { + if (CDSConfig::new_aot_flags_used()) { + return LogTagSetMapping::tagset().is_level(level); + } else { + return LogTagSetMapping::tagset().is_level(level); + } + } + + ATTRIBUTE_PRINTF(2, 3) + static void write(LogLevelType level, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vwrite(level, fmt, args); + va_end(args); + } + + template + ATTRIBUTE_PRINTF(1, 2) + static void write(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + vwrite(Level, fmt, args); + va_end(args); + } + + ATTRIBUTE_PRINTF(2, 0) + static void vwrite(LogLevelType level, const char* fmt, va_list args) { + if (CDSConfig::new_aot_flags_used()) { + LogTagSetMapping::tagset().vwrite(level, fmt, args); + } else { + LogTagSetMapping::tagset().vwrite(level, fmt, args); + } + } +}; + +#endif diff --git a/src/hotspot/share/cds/aotReferenceObjSupport.cpp b/src/hotspot/share/cds/aotReferenceObjSupport.cpp new file mode 100644 index 00000000000..a62e9c7735a --- /dev/null +++ b/src/hotspot/share/cds/aotReferenceObjSupport.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "cds/aotReferenceObjSupport.hpp" +#include "cds/heapShared.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/symbolTable.hpp" +#include "classfile/systemDictionary.hpp" +#include "classfile/vmSymbols.hpp" +#include "logging/log.hpp" +#include "memory/resourceArea.hpp" +#include "memory/universe.hpp" +#include "oops/oop.inline.hpp" +#include "oops/oopHandle.inline.hpp" +#include "runtime/fieldDescriptor.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "utilities/resourceHash.hpp" + +// Handling of java.lang.ref.Reference objects in the AOT cache +// ============================================================ +// +// When AOTArtifactFinder finds an oop which is a instance of java.lang.ref.Reference: +// +// - We check if the oop is eligible to be stored in the AOT cache. If not, the AOT cache +// creation fails -- see AOTReferenceObjSupport::check_if_ref_obj() +// +// - Otherwise, we store the oop into the AOT cache, but we unconditionally reset its +// "next" and "discovered" fields to null. Otherwise, if AOTArtifactFinder follows these +// fields, it may found unrelated objects that we don't intend to cache. +// +// Eligibility +// =========== +// +// [1] A reference that does not require special clean up (i.e., Reference::queue == ReferenceQueue.NULL_QUEUE) +// is eligible. +// +// [2] A reference that REQUIRE specials clean up (i.e., Reference::queue != ReferenceQueue.NULL_QUEUE) +// is eligible ONLY if its referent is not null. +// +// As of this version, the only oops in group [2] that can be found by AOTArtifactFinder are +// the keys used by ReferencedKeyMap in the implementation of MethodType::internTable. +// stabilize_cached_reference_objects() ensures that all keys found by AOTArtifactFinder are eligible. +// +// The purpose of the error check in check_if_ref_obj() is to guard against changes in the JDK core +// libs that might introduce new types of oops in group [2] into the AOT cache. +// +// Reasons for the eligibility restrictions +// ======================================== +// +// Reference handling is complex. In this version, we implement only enough functionality to support +// the use of Weak/Soft references used by java.lang.invoke. +// +// We intend to evolve the implementation in the future by +// -- implementing more assemblySetup() operations for other use cases, and/or +// -- relaxing the eligibility restrictions. +// +// +// null referents for group [1] +// ============================ +// +// Any cached reference R1 of group [1] is allowed to have a null referent. +// This can happen in the following situations: +// (a) R1.clear() was called by Java code during the assembly phase. +// (b) The referent has been collected, and R1 is in the "pending" state. +// In case (b), the "next" and "discovered" fields of the cached copy of R1 will +// be set to null. During the production run: +// - It would appear to the Java program as if immediately during VM start-up, the referent +// was collected and ReferenceThread completed processing of R1. +// - It would appear to the GC as if immediately during VM start-up, the Java program called +// R1.clear(). + +#if INCLUDE_CDS_JAVA_HEAP + +class KeepAliveObjectsTable : public ResourceHashtable {}; + +static KeepAliveObjectsTable* _keep_alive_objs_table; +static OopHandle _keep_alive_objs_array; +static OopHandle _null_queue; + +bool AOTReferenceObjSupport::is_enabled() { + // For simplicity, AOTReferenceObjSupport is enabled only when dumping method handles. + // Otherwise we won't see Reference objects in the AOT cache. Let's be conservative now. + return CDSConfig::is_dumping_method_handles(); +} + +void AOTReferenceObjSupport::initialize(TRAPS) { + if (!AOTReferenceObjSupport::is_enabled()) { + return; + } + + TempNewSymbol class_name = SymbolTable::new_symbol("java/lang/ref/ReferenceQueue"); + Klass* k = SystemDictionary::resolve_or_fail(class_name, true, CHECK); + InstanceKlass* ik = InstanceKlass::cast(k); + ik->initialize(CHECK); + + TempNewSymbol field_name = SymbolTable::new_symbol("NULL_QUEUE"); + fieldDescriptor fd; + bool found = ik->find_local_field(field_name, vmSymbols::referencequeue_signature(), &fd); + precond(found); + precond(fd.is_static()); + + _null_queue = OopHandle(Universe::vm_global(), ik->java_mirror()->obj_field(fd.offset())); +} + +// Ensure that all group [2] references found by AOTArtifactFinder are eligible. +void AOTReferenceObjSupport::stabilize_cached_reference_objects(TRAPS) { + if (AOTReferenceObjSupport::is_enabled()) { + // This assert means that the MethodType and MethodTypeForm tables won't be + // updated concurrently, so we can remove GC'ed entries ... + assert(CDSConfig::allow_only_single_java_thread(), "Required"); + + { + TempNewSymbol method_name = SymbolTable::new_symbol("assemblySetup"); + JavaValue result(T_VOID); + JavaCalls::call_static(&result, vmClasses::MethodType_klass(), + method_name, + vmSymbols::void_method_signature(), + CHECK); + } + + { + Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS(); + Klass* cds_klass = SystemDictionary::resolve_or_fail(cds_name, true /*throw error*/, CHECK); + TempNewSymbol method_name = SymbolTable::new_symbol("getKeepAliveObjects"); + TempNewSymbol method_sig = SymbolTable::new_symbol("()[Ljava/lang/Object;"); + JavaValue result(T_OBJECT); + JavaCalls::call_static(&result, cds_klass, method_name, method_sig, CHECK); + + _keep_alive_objs_array = OopHandle(Universe::vm_global(), result.get_oop()); + } + } +} + +void AOTReferenceObjSupport::init_keep_alive_objs_table() { + assert_at_safepoint(); // _keep_alive_objs_table uses raw oops + oop a = _keep_alive_objs_array.resolve(); + if (a != nullptr) { + precond(a->is_objArray()); + precond(AOTReferenceObjSupport::is_enabled()); + objArrayOop array = objArrayOop(a); + + _keep_alive_objs_table = new (mtClass)KeepAliveObjectsTable(); + for (int i = 0; i < array->length(); i++) { + oop obj = array->obj_at(i); + _keep_alive_objs_table->put(obj, true); // The array may have duplicated entries but that's OK. + } + } +} + +// Returns true IFF obj is an instance of java.lang.ref.Reference. If so, perform extra eligibility checks. +bool AOTReferenceObjSupport::check_if_ref_obj(oop obj) { + // We have a single Java thread. This means java.lang.ref.Reference$ReferenceHandler thread + // is not running. Otherwise the checks for next/discovered may not work. + precond(CDSConfig::allow_only_single_java_thread()); + assert_at_safepoint(); // _keep_alive_objs_table uses raw oops + + if (obj->klass()->is_subclass_of(vmClasses::Reference_klass())) { + precond(AOTReferenceObjSupport::is_enabled()); + precond(JavaClasses::is_supported_for_archiving(obj)); + precond(_keep_alive_objs_table != nullptr); + + // GC needs to know about this load, It will keep referent alive until the current safepoint ends. + oop referent = HeapAccess::oop_load_at(obj, java_lang_ref_Reference::referent_offset()); + + oop queue = obj->obj_field(java_lang_ref_Reference::queue_offset()); + oop next = java_lang_ref_Reference::next(obj); + oop discovered = java_lang_ref_Reference::discovered(obj); + bool needs_special_cleanup = (queue != _null_queue.resolve()); + + // If you see the errors below, you probably modified the implementation of java.lang.invoke. + // Please check the comments at the top of this file. + if (needs_special_cleanup && (referent == nullptr || !_keep_alive_objs_table->contains(referent))) { + ResourceMark rm; + + log_error(aot, heap)("Cannot archive reference object " PTR_FORMAT " of class %s", + p2i(obj), obj->klass()->external_name()); + log_error(aot, heap)("referent = " PTR_FORMAT + ", queue = " PTR_FORMAT + ", next = " PTR_FORMAT + ", discovered = " PTR_FORMAT, + p2i(referent), p2i(queue), p2i(next), p2i(discovered)); + log_error(aot, heap)("This object requires special clean up as its queue is not ReferenceQueue::N" "ULL (" + PTR_FORMAT ")", p2i(_null_queue.resolve())); + log_error(aot, heap)("%s", (referent == nullptr) ? + "referent cannot be null" : "referent is not registered with CDS.keepAlive()"); + HeapShared::debug_trace(); + MetaspaceShared::unrecoverable_writing_error(); + } + + if (log_is_enabled(Info, aot, ref)) { + ResourceMark rm; + log_info(aot, ref)("Reference obj:" + " r=" PTR_FORMAT + " q=" PTR_FORMAT + " n=" PTR_FORMAT + " d=" PTR_FORMAT + " %s", + p2i(referent), + p2i(queue), + p2i(next), + p2i(discovered), + obj->klass()->external_name()); + } + return true; + } else { + return false; + } +} + +bool AOTReferenceObjSupport::skip_field(int field_offset) { + return (field_offset == java_lang_ref_Reference::next_offset() || + field_offset == java_lang_ref_Reference::discovered_offset()); +} + +#endif // INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/cds/aotReferenceObjSupport.hpp b/src/hotspot/share/cds/aotReferenceObjSupport.hpp new file mode 100644 index 00000000000..3d645c2df17 --- /dev/null +++ b/src/hotspot/share/cds/aotReferenceObjSupport.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_CDS_AOTREFERENCEOBJSUPPORT_HPP +#define SHARE_CDS_AOTREFERENCEOBJSUPPORT_HPP + +#include "memory/allStatic.hpp" +#include "oops/oopsHierarchy.hpp" +#include "utilities/exceptions.hpp" + +// Support for ahead-of-time allocated instances of java.lang.ref.Reference + +class AOTReferenceObjSupport : AllStatic { + +public: + static void initialize(TRAPS); + static void stabilize_cached_reference_objects(TRAPS); + static void init_keep_alive_objs_table() NOT_CDS_JAVA_HEAP_RETURN; + static bool check_if_ref_obj(oop obj); + static bool skip_field(int field_offset); + static bool is_enabled(); +}; + +#endif // SHARE_CDS_AOTREFERENCEOBJSUPPORT_HPP diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index c309de17b4c..5f197f70ecc 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -25,6 +25,7 @@ #include "cds/aotArtifactFinder.hpp" #include "cds/aotClassLinker.hpp" #include "cds/aotLinkedClassBulkLoader.hpp" +#include "cds/aotLogging.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.hpp" @@ -42,6 +43,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionaryShared.hpp" #include "classfile/vmClasses.hpp" +#include "code/aotCodeCache.hpp" #include "interpreter/abstractInterpreter.hpp" #include "jvm.h" #include "logging/log.hpp" @@ -52,9 +54,12 @@ #include "memory/resourceArea.hpp" #include "oops/compressedKlass.inline.hpp" #include "oops/instanceKlass.hpp" +#include "oops/methodCounters.hpp" +#include "oops/methodData.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oopHandle.inline.hpp" +#include "oops/trainingData.hpp" #include "runtime/arguments.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/globals_extension.hpp" @@ -129,13 +134,27 @@ class RelocateEmbeddedPointers : public BitMapClosure { size_t field_offset = size_t(bit_offset - _start_idx) * sizeof(address); address* ptr_loc = (address*)(_buffered_obj + field_offset); - address old_p = *ptr_loc; + address old_p_with_tags = *ptr_loc; + assert(old_p_with_tags != nullptr, "null ptrs shouldn't have been marked"); + + address old_p = MetaspaceClosure::strip_tags(old_p_with_tags); + uintx tags = MetaspaceClosure::decode_tags(old_p_with_tags); address new_p = _builder->get_buffered_addr(old_p); - log_trace(cds)("Ref: [" PTR_FORMAT "] -> " PTR_FORMAT " => " PTR_FORMAT, - p2i(ptr_loc), p2i(old_p), p2i(new_p)); + bool nulled; + if (new_p == nullptr) { + // old_p had a FollowMode of set_to_null + nulled = true; + } else { + new_p = MetaspaceClosure::add_tags(new_p, tags); + nulled = false; + } + + log_trace(aot)("Ref: [" PTR_FORMAT "] -> " PTR_FORMAT " => " PTR_FORMAT " %zu", + p2i(ptr_loc), p2i(old_p) + tags, p2i(new_p), tags); ArchivePtrMarker::set_and_mark_pointer(ptr_loc, new_p); + ArchiveBuilder::current()->count_relocated_pointer(tags != 0, nulled); return true; // keep iterating the bitmap } }; @@ -163,6 +182,7 @@ ArchiveBuilder::ArchiveBuilder() : _pz_region("pz", MAX_SHARED_DELTA), // protection zone -- used only during dumping; does NOT exist in cds archive. _rw_region("rw", MAX_SHARED_DELTA), _ro_region("ro", MAX_SHARED_DELTA), + _ac_region("ac", MAX_SHARED_DELTA), _ptrmap(mtClassShared), _rw_ptrmap(mtClassShared), _ro_ptrmap(mtClassShared), @@ -175,6 +195,9 @@ ArchiveBuilder::ArchiveBuilder() : _klasses = new (mtClassShared) GrowableArray(4 * K, mtClassShared); _symbols = new (mtClassShared) GrowableArray(256 * K, mtClassShared); _entropy_seed = 0x12345678; + _relocated_ptr_info._num_ptrs = 0; + _relocated_ptr_info._num_tagged_ptrs = 0; + _relocated_ptr_info._num_nulled_ptrs = 0; assert(_current == nullptr, "must be"); _current = this; } @@ -249,7 +272,7 @@ void ArchiveBuilder::gather_klasses_and_symbols() { AOTArtifactFinder::initialize(); AOTArtifactFinder::find_artifacts(); - log_info(cds)("Gathering classes and symbols ... "); + aot_log_info(aot)("Gathering classes and symbols ... "); GatherKlassesAndSymbols doit(this); iterate_roots(&doit); #if INCLUDE_CDS_JAVA_HEAP @@ -279,7 +302,7 @@ void ArchiveBuilder::gather_klasses_and_symbols() { // TODO: in the future, if we want to produce deterministic contents in the // dynamic archive, we might need to sort the symbols alphabetically (also see // DynamicArchiveBuilder::sort_methods()). - log_info(cds)("Sorting symbols ... "); + aot_log_info(aot)("Sorting symbols ... "); _symbols->sort(compare_symbols_by_address); sort_klasses(); } @@ -301,24 +324,26 @@ int ArchiveBuilder::compare_klass_by_name(Klass** a, Klass** b) { } void ArchiveBuilder::sort_klasses() { - log_info(cds)("Sorting classes ... "); + aot_log_info(aot)("Sorting classes ... "); _klasses->sort(compare_klass_by_name); } address ArchiveBuilder::reserve_buffer() { - size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M); + // AOTCodeCache::max_aot_code_size() accounts for aot code region. + size_t buffer_size = LP64_ONLY(CompressedClassSpaceSize) NOT_LP64(256 * M) + AOTCodeCache::max_aot_code_size(); ReservedSpace rs = MemoryReserver::reserve(buffer_size, MetaspaceShared::core_region_alignment(), - os::vm_page_size()); + os::vm_page_size(), + mtNone); if (!rs.is_reserved()) { - log_error(cds)("Failed to reserve %zu bytes of output buffer.", buffer_size); + aot_log_error(aot)("Failed to reserve %zu bytes of output buffer.", buffer_size); MetaspaceShared::unrecoverable_writing_error(); } // buffer_bottom is the lowest address of the 2 core regions (rw, ro) when // we are copying the class metadata into the buffer. address buffer_bottom = (address)rs.base(); - log_info(cds)("Reserved output buffer space at " PTR_FORMAT " [%zu bytes]", + aot_log_info(aot)("Reserved output buffer space at " PTR_FORMAT " [%zu bytes]", p2i(buffer_bottom), buffer_size); _shared_rs = rs; @@ -360,9 +385,9 @@ address ArchiveBuilder::reserve_buffer() { if (my_archive_requested_bottom < _requested_static_archive_bottom || my_archive_requested_top <= _requested_static_archive_bottom) { // Size overflow. - log_error(cds)("my_archive_requested_bottom = " INTPTR_FORMAT, p2i(my_archive_requested_bottom)); - log_error(cds)("my_archive_requested_top = " INTPTR_FORMAT, p2i(my_archive_requested_top)); - log_error(cds)("SharedBaseAddress (" INTPTR_FORMAT ") is too high. " + aot_log_error(aot)("my_archive_requested_bottom = " INTPTR_FORMAT, p2i(my_archive_requested_bottom)); + aot_log_error(aot)("my_archive_requested_top = " INTPTR_FORMAT, p2i(my_archive_requested_top)); + aot_log_error(aot)("SharedBaseAddress (" INTPTR_FORMAT ") is too high. " "Please rerun java -Xshare:dump with a lower value", p2i(_requested_static_archive_bottom)); MetaspaceShared::unrecoverable_writing_error(); } @@ -420,7 +445,7 @@ bool ArchiveBuilder::gather_one_source_obj(MetaspaceClosure::Ref* ref, bool read SourceObjInfo* p = _src_obj_table.put_if_absent(src_obj, src_info, &created); if (created) { if (_src_obj_table.maybe_grow()) { - log_info(cds, hashtables)("Expanded _src_obj_table table to %d", _src_obj_table.table_size()); + log_info(aot, hashtables)("Expanded _src_obj_table table to %d", _src_obj_table.table_size()); } } @@ -432,6 +457,11 @@ bool ArchiveBuilder::gather_one_source_obj(MetaspaceClosure::Ref* ref, bool read } #endif + if (ref->msotype() == MetaspaceObj::MethodDataType) { + MethodData* md = (MethodData*)ref->obj(); + md->clean_method_data(false /* always_clean */); + } + assert(p->read_only() == src_info.read_only(), "must be"); if (created && src_info.should_copy()) { @@ -499,7 +529,7 @@ void ArchiveBuilder::remember_embedded_pointer_in_enclosing_obj(MetaspaceClosure void ArchiveBuilder::gather_source_objs() { ResourceMark rm; - log_info(cds)("Gathering all archivable objects ... "); + aot_log_info(aot)("Gathering all archivable objects ... "); gather_klasses_and_symbols(); GatherSortedSourceObjs doit(this); iterate_sorted_roots(&doit); @@ -529,8 +559,18 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref // Don't dump existing shared metadata again. return point_to_it; } else if (ref->msotype() == MetaspaceObj::MethodDataType || - ref->msotype() == MetaspaceObj::MethodCountersType) { - return set_to_null; + ref->msotype() == MetaspaceObj::MethodCountersType || + ref->msotype() == MetaspaceObj::KlassTrainingDataType || + ref->msotype() == MetaspaceObj::MethodTrainingDataType || + ref->msotype() == MetaspaceObj::CompileTrainingDataType) { + return (TrainingData::need_data() || TrainingData::assembling_data()) ? make_a_copy : set_to_null; + } else if (ref->msotype() == MetaspaceObj::AdapterHandlerEntryType) { + if (CDSConfig::is_dumping_adapters()) { + AdapterHandlerEntry* entry = (AdapterHandlerEntry*)ref->obj(); + return AdapterHandlerLibrary::is_abstract_method_adapter(entry) ? set_to_null : make_a_copy; + } else { + return set_to_null; + } } else { if (ref->msotype() == MetaspaceObj::ClassType) { Klass* klass = (Klass*)ref->obj(); @@ -579,7 +619,7 @@ void ArchiveBuilder::sort_metadata_objs() { void ArchiveBuilder::dump_rw_metadata() { ResourceMark rm; - log_info(cds)("Allocating RW objects ... "); + aot_log_info(aot)("Allocating RW objects ... "); make_shallow_copies(&_rw_region, &_rw_src_objs); #if INCLUDE_CDS_JAVA_HEAP @@ -594,7 +634,7 @@ void ArchiveBuilder::dump_rw_metadata() { void ArchiveBuilder::dump_ro_metadata() { ResourceMark rm; - log_info(cds)("Allocating RO objects ... "); + aot_log_info(aot)("Allocating RO objects ... "); start_dump_region(&_ro_region); make_shallow_copies(&_ro_region, &_ro_src_objs); @@ -615,7 +655,7 @@ void ArchiveBuilder::make_shallow_copies(DumpRegion *dump_region, for (int i = 0; i < src_objs->objs()->length(); i++) { make_shallow_copy(dump_region, src_objs->objs()->at(i)); } - log_info(cds)("done (%d objects)", src_objs->objs()->length()); + aot_log_info(aot)("done (%d objects)", src_objs->objs()->length()); } void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* src_info) { @@ -665,7 +705,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s _buffered_to_src_table.put_if_absent((address)dest, src, &created); assert(created, "must be"); if (_buffered_to_src_table.maybe_grow()) { - log_info(cds, hashtables)("Expanded _buffered_to_src_table table to %d", _buffered_to_src_table.table_size()); + log_info(aot, hashtables)("Expanded _buffered_to_src_table table to %d", _buffered_to_src_table.table_size()); } } @@ -675,7 +715,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s ArchivePtrMarker::mark_pointer((address*)dest); } - log_trace(cds)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(src), p2i(dest), bytes); + log_trace(aot)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(src), p2i(dest), bytes); src_info->set_buffered_addr((address)dest); _alloc_stats.record(src_info->msotype(), int(newtop - oldtop), src_info->read_only()); @@ -704,6 +744,11 @@ void ArchiveBuilder::mark_and_relocate_to_buffered_addr(address* ptr_location) { ArchivePtrMarker::mark_pointer(ptr_location); } +bool ArchiveBuilder::has_been_archived(address src_addr) const { + SourceObjInfo* p = _src_obj_table.get(src_addr); + return (p != nullptr); +} + bool ArchiveBuilder::has_been_buffered(address src_addr) const { if (RegeneratedClasses::has_been_regenerated(src_addr) || _src_obj_table.get(src_addr) == nullptr || @@ -736,9 +781,13 @@ void ArchiveBuilder::relocate_embedded_pointers(ArchiveBuilder::SourceObjList* s } void ArchiveBuilder::relocate_metaspaceobj_embedded_pointers() { - log_info(cds)("Relocating embedded pointers in core regions ... "); + aot_log_info(aot)("Relocating embedded pointers in core regions ... "); relocate_embedded_pointers(&_rw_src_objs); relocate_embedded_pointers(&_ro_src_objs); + log_info(cds)("Relocating %zu pointers, %zu tagged, %zu nulled", + _relocated_ptr_info._num_ptrs, + _relocated_ptr_info._num_tagged_ptrs, + _relocated_ptr_info._num_nulled_ptrs); } #define ADD_COUNT(x) \ @@ -817,10 +866,6 @@ void ArchiveBuilder::make_klasses_shareable() { bool aotlinked = AOTClassLinker::is_candidate(src_ik); inited = ik->has_aot_initialized_mirror(); ADD_COUNT(num_instance_klasses); - if (CDSConfig::is_dumping_dynamic_archive()) { - // For static dump, class loader type are already set. - ik->assign_class_loader_type(); - } if (ik->is_hidden()) { ADD_COUNT(num_hidden_klasses); hidden = " hidden"; @@ -844,17 +889,17 @@ void ArchiveBuilder::make_klasses_shareable() { // Legacy CDS support for lambda proxies CDS_JAVA_HEAP_ONLY(assert(HeapShared::is_lambda_proxy_klass(ik), "sanity");) } - } else if (ik->is_shared_boot_class()) { + } else if (ik->defined_by_boot_loader()) { type = "boot"; ADD_COUNT(num_boot_klasses); - } else if (ik->is_shared_platform_class()) { + } else if (ik->defined_by_platform_loader()) { type = "plat"; ADD_COUNT(num_platform_klasses); - } else if (ik->is_shared_app_class()) { + } else if (ik->defined_by_app_loader()) { type = "app"; ADD_COUNT(num_app_klasses); } else { - assert(ik->is_shared_unregistered_class(), "must be"); + assert(ik->defined_by_other_loaders(), "must be"); type = "unreg"; ADD_COUNT(num_unregistered_klasses); } @@ -866,11 +911,11 @@ void ArchiveBuilder::make_klasses_shareable() { if (!ik->is_linked()) { num_unlinked_klasses ++; unlinked = " unlinked"; - if (ik->is_shared_boot_class()) { + if (ik->defined_by_boot_loader()) { boot_unlinked ++; - } else if (ik->is_shared_platform_class()) { + } else if (ik->defined_by_platform_loader()) { platform_unlinked ++; - } else if (ik->is_shared_app_class()) { + } else if (ik->defined_by_app_loader()) { app_unlinked ++; } else { unreg_unlinked ++; @@ -907,9 +952,9 @@ void ArchiveBuilder::make_klasses_shareable() { ik->remove_unshareable_info(); } - if (log_is_enabled(Debug, cds, class)) { + if (aot_log_is_enabled(Debug, aot, class)) { ResourceMark rm; - log_debug(cds, class)("klasses[%5d] = " PTR_FORMAT " %-5s %s%s%s%s%s%s%s%s", i, + aot_log_debug(aot, class)("klasses[%5d] = " PTR_FORMAT " %-5s %s%s%s%s%s%s%s%s", i, p2i(to_requested(k)), type, k->external_name(), kind, hidden, old, unlinked, generated, aotlinked_msg, inited_msg); } @@ -918,21 +963,21 @@ void ArchiveBuilder::make_klasses_shareable() { #define STATS_FORMAT "= %5d, aot-linked = %5d, inited = %5d" #define STATS_PARAMS(x) num_ ## x, num_ ## x ## _a, num_ ## x ## _i - log_info(cds)("Number of classes %d", num_instance_klasses + num_obj_array_klasses + num_type_array_klasses); - log_info(cds)(" instance classes " STATS_FORMAT, STATS_PARAMS(instance_klasses)); - log_info(cds)(" boot " STATS_FORMAT, STATS_PARAMS(boot_klasses)); - log_info(cds)(" vm " STATS_FORMAT, STATS_PARAMS(vm_klasses)); - log_info(cds)(" platform " STATS_FORMAT, STATS_PARAMS(platform_klasses)); - log_info(cds)(" app " STATS_FORMAT, STATS_PARAMS(app_klasses)); - log_info(cds)(" unregistered " STATS_FORMAT, STATS_PARAMS(unregistered_klasses)); - log_info(cds)(" (enum) " STATS_FORMAT, STATS_PARAMS(enum_klasses)); - log_info(cds)(" (hidden) " STATS_FORMAT, STATS_PARAMS(hidden_klasses)); - log_info(cds)(" (old) " STATS_FORMAT, STATS_PARAMS(old_klasses)); - log_info(cds)(" (unlinked) = %5d, boot = %d, plat = %d, app = %d, unreg = %d", + aot_log_info(aot)("Number of classes %d", num_instance_klasses + num_obj_array_klasses + num_type_array_klasses); + aot_log_info(aot)(" instance classes " STATS_FORMAT, STATS_PARAMS(instance_klasses)); + aot_log_info(aot)(" boot " STATS_FORMAT, STATS_PARAMS(boot_klasses)); + aot_log_info(aot)(" vm " STATS_FORMAT, STATS_PARAMS(vm_klasses)); + aot_log_info(aot)(" platform " STATS_FORMAT, STATS_PARAMS(platform_klasses)); + aot_log_info(aot)(" app " STATS_FORMAT, STATS_PARAMS(app_klasses)); + aot_log_info(aot)(" unregistered " STATS_FORMAT, STATS_PARAMS(unregistered_klasses)); + aot_log_info(aot)(" (enum) " STATS_FORMAT, STATS_PARAMS(enum_klasses)); + aot_log_info(aot)(" (hidden) " STATS_FORMAT, STATS_PARAMS(hidden_klasses)); + aot_log_info(aot)(" (old) " STATS_FORMAT, STATS_PARAMS(old_klasses)); + aot_log_info(aot)(" (unlinked) = %5d, boot = %d, plat = %d, app = %d, unreg = %d", num_unlinked_klasses, boot_unlinked, platform_unlinked, app_unlinked, unreg_unlinked); - log_info(cds)(" obj array classes = %5d", num_obj_array_klasses); - log_info(cds)(" type array classes = %5d", num_type_array_klasses); - log_info(cds)(" symbols = %5d", _symbols->length()); + aot_log_info(aot)(" obj array classes = %5d", num_obj_array_klasses); + aot_log_info(aot)(" type array classes = %5d", num_type_array_klasses); + aot_log_info(aot)(" symbols = %5d", _symbols->length()); #undef STATS_FORMAT #undef STATS_PARAMS @@ -940,6 +985,28 @@ void ArchiveBuilder::make_klasses_shareable() { DynamicArchive::make_array_klasses_shareable(); } +void ArchiveBuilder::make_training_data_shareable() { + auto clean_td = [&] (address& src_obj, SourceObjInfo& info) { + if (!is_in_buffer_space(info.buffered_addr())) { + return; + } + + if (info.msotype() == MetaspaceObj::KlassTrainingDataType || + info.msotype() == MetaspaceObj::MethodTrainingDataType || + info.msotype() == MetaspaceObj::CompileTrainingDataType) { + TrainingData* buffered_td = (TrainingData*)info.buffered_addr(); + buffered_td->remove_unshareable_info(); + } else if (info.msotype() == MetaspaceObj::MethodDataType) { + MethodData* buffered_mdo = (MethodData*)info.buffered_addr(); + buffered_mdo->remove_unshareable_info(); + } else if (info.msotype() == MetaspaceObj::MethodCountersType) { + MethodCounters* buffered_mc = (MethodCounters*)info.buffered_addr(); + buffered_mc->remove_unshareable_info(); + } + }; + _src_obj_table.iterate_all(clean_td); +} + void ArchiveBuilder::serialize_dynamic_archivable_items(SerializeClosure* soc) { SymbolTable::serialize_shared_table_header(soc, false); SystemDictionaryShared::serialize_dictionary_headers(soc, false); @@ -972,6 +1039,15 @@ address ArchiveBuilder::offset_to_buffered_address(u4 offset) const { return buffered_addr; } +void ArchiveBuilder::start_ac_region() { + ro_region()->pack(); + start_dump_region(&_ac_region); +} + +void ArchiveBuilder::end_ac_region() { + _ac_region.pack(); +} + #if INCLUDE_CDS_JAVA_HEAP narrowKlass ArchiveBuilder::get_requested_narrow_klass(Klass* k) { assert(CDSConfig::is_dumping_heap(), "sanity"); @@ -1025,7 +1101,7 @@ class RelocateBufferToRequested : public BitMapClosure { address top = _builder->buffer_top(); address new_bottom = bottom + _buffer_to_requested_delta; address new_top = top + _buffer_to_requested_delta; - log_debug(cds)("Relocating archive from [" INTPTR_FORMAT " - " INTPTR_FORMAT "] to " + aot_log_debug(aot)("Relocating archive from [" INTPTR_FORMAT " - " INTPTR_FORMAT "] to " "[" INTPTR_FORMAT " - " INTPTR_FORMAT "]", p2i(bottom), p2i(top), p2i(new_bottom), p2i(new_top)); @@ -1081,8 +1157,9 @@ int ArchiveBuilder::precomputed_narrow_klass_shift() { #endif // _LP64 void ArchiveBuilder::relocate_to_requested() { - ro_region()->pack(); - + if (!ro_region()->is_packed()) { + ro_region()->pack(); + } size_t my_archive_size = buffer_top() - buffer_bottom(); if (CDSConfig::is_dumping_static_archive()) { @@ -1128,12 +1205,12 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { static void log_klass(Klass* k, address runtime_dest, const char* type_name, int bytes, Thread* current) { ResourceMark rm(current); - log_debug(cds, map)(_LOG_PREFIX " %s", + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(runtime_dest), type_name, bytes, k->external_name()); } static void log_method(Method* m, address runtime_dest, const char* type_name, int bytes, Thread* current) { ResourceMark rm(current); - log_debug(cds, map)(_LOG_PREFIX " %s", + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(runtime_dest), type_name, bytes, m->external_name()); } @@ -1176,12 +1253,12 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { { ResourceMark rm(current); Symbol* s = (Symbol*)src; - log_debug(cds, map)(_LOG_PREFIX " %s", p2i(runtime_dest), type_name, bytes, + log_debug(aot, map)(_LOG_PREFIX " %s", p2i(runtime_dest), type_name, bytes, s->as_quoted_ascii()); } break; default: - log_debug(cds, map)(_LOG_PREFIX, p2i(runtime_dest), type_name, bytes); + log_debug(aot, map)(_LOG_PREFIX, p2i(runtime_dest), type_name, bytes); break; } @@ -1191,7 +1268,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { log_as_hex(last_obj_base, last_obj_end, last_obj_base + buffer_to_runtime_delta()); if (last_obj_end < region_end) { - log_debug(cds, map)(PTR_FORMAT ": @@ Misc data %zu bytes", + log_debug(aot, map)(PTR_FORMAT ": @@ Misc data %zu bytes", p2i(last_obj_end + buffer_to_runtime_delta()), size_t(region_end - last_obj_end)); log_as_hex(last_obj_end, region_end, last_obj_end + buffer_to_runtime_delta()); @@ -1201,7 +1278,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { #undef _LOG_PREFIX // Log information about a region, whose address at dump time is [base .. top). At - // runtime, this region will be mapped to requested_base. requested_base is 0 if this + // runtime, this region will be mapped to requested_base. requested_base is nullptr if this // region will be mapped at os-selected addresses (such as the bitmap region), or will // be accessed with os::read (the header). // @@ -1210,8 +1287,12 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { static void log_region(const char* name, address base, address top, address requested_base) { size_t size = top - base; base = requested_base; - top = requested_base + size; - log_info(cds, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " %9zu bytes]", + if (requested_base == nullptr) { + top = (address)size; + } else { + top = requested_base + size; + } + log_info(aot, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " %9zu bytes]", name, p2i(base), p2i(top), size); } @@ -1222,7 +1303,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { address end = address(r.end()); log_region("heap", start, end, ArchiveHeapWriter::buffered_addr_to_requested_addr(start)); - LogStreamHandle(Info, cds, map) st; + LogStreamHandle(Info, aot, map) st; HeapRootSegments segments = heap_info->heap_root_segments(); assert(segments.base_offset() == 0, "Sanity"); @@ -1331,7 +1412,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { // Print the fields of instanceOops, or the elements of arrayOops static void log_oop_details(ArchiveHeapInfo* heap_info, oop source_oop, address buffered_addr) { - LogStreamHandle(Trace, cds, map, oops) st; + LogStreamHandle(Trace, aot, map, oops) st; if (st.is_enabled()) { Klass* source_klass = source_oop->klass(); ArchiveBuilder* builder = ArchiveBuilder::current(); @@ -1399,7 +1480,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { } static void log_heap_roots() { - LogStreamHandle(Trace, cds, map, oops) st; + LogStreamHandle(Trace, aot, map, oops) st; if (st.is_enabled()) { for (int i = 0; i < HeapShared::pending_roots()->length(); i++) { st.print("roots[%4d]: ", i); @@ -1460,7 +1541,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { static void log_as_hex(address base, address top, address requested_base, bool is_heap = false) { assert(top >= base, "must be"); - LogStreamHandle(Trace, cds, map) lsh; + LogStreamHandle(Trace, aot, map) lsh; if (lsh.is_enabled()) { int unitsize = sizeof(address); if (is_heap && UseCompressedOops) { @@ -1473,7 +1554,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { } static void log_header(FileMapInfo* mapinfo) { - LogStreamHandle(Info, cds, map) lsh; + LogStreamHandle(Info, aot, map) lsh; if (lsh.is_enabled()) { mapinfo->print(&lsh); } @@ -1483,7 +1564,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { static void log(ArchiveBuilder* builder, FileMapInfo* mapinfo, ArchiveHeapInfo* heap_info, char* bitmap, size_t bitmap_size_in_bytes) { - log_info(cds, map)("%s CDS archive map for %s", CDSConfig::is_dumping_static_archive() ? "Static" : "Dynamic", mapinfo->full_path()); + log_info(aot, map)("%s CDS archive map for %s", CDSConfig::is_dumping_static_archive() ? "Static" : "Dynamic", mapinfo->full_path()); address header = address(mapinfo->header()); address header_end = header + mapinfo->header()->header_size(); @@ -1507,7 +1588,7 @@ class ArchiveBuilder::CDSMapLogger : AllStatic { } #endif - log_info(cds, map)("[End of CDS archive map]"); + log_info(aot, map)("[End of CDS archive map]"); } }; // end ArchiveBuilder::CDSMapLogger @@ -1522,6 +1603,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_i write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false); write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false); + write_region(mapinfo, MetaspaceShared::ac, &_ac_region, /*read_only=*/false,/*allow_exec=*/false); // Split pointer map into read-write and read-only bitmaps ArchivePtrMarker::initialize_rw_ro_maps(&_rw_ptrmap, &_ro_ptrmap); @@ -1543,12 +1625,12 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_i mapinfo->write_header(); mapinfo->close(); - if (log_is_enabled(Info, cds)) { - log_info(cds)("Full module graph = %s", CDSConfig::is_dumping_full_module_graph() ? "enabled" : "disabled"); + if (log_is_enabled(Info, aot)) { + log_info(aot)("Full module graph = %s", CDSConfig::is_dumping_full_module_graph() ? "enabled" : "disabled"); print_stats(); } - if (log_is_enabled(Info, cds, map)) { + if (log_is_enabled(Info, aot, map)) { CDSMapLogger::log(this, mapinfo, heap_info, bitmap, bitmap_size_in_bytes); } @@ -1560,6 +1642,12 @@ void ArchiveBuilder::write_region(FileMapInfo* mapinfo, int region_idx, DumpRegi mapinfo->write_region(region_idx, dump_region->base(), dump_region->used(), read_only, allow_exec); } +void ArchiveBuilder::count_relocated_pointer(bool tagged, bool nulled) { + _relocated_ptr_info._num_ptrs ++; + _relocated_ptr_info._num_tagged_ptrs += tagged ? 1 : 0; + _relocated_ptr_info._num_nulled_ptrs += nulled ? 1 : 0; +} + void ArchiveBuilder::print_region_stats(FileMapInfo *mapinfo, ArchiveHeapInfo* heap_info) { // Print statistics of all the regions const size_t bitmap_used = mapinfo->region_at(MetaspaceShared::bm)->used(); @@ -1574,6 +1662,7 @@ void ArchiveBuilder::print_region_stats(FileMapInfo *mapinfo, ArchiveHeapInfo* h _rw_region.print(total_reserved); _ro_region.print(total_reserved); + _ac_region.print(total_reserved); print_bitmap_region_stats(bitmap_used, total_reserved); @@ -1581,12 +1670,12 @@ void ArchiveBuilder::print_region_stats(FileMapInfo *mapinfo, ArchiveHeapInfo* h print_heap_region_stats(heap_info, total_reserved); } - log_debug(cds)("total : %9zu [100.0%% of total] out of %9zu bytes [%5.1f%% used]", + aot_log_debug(aot)("total : %9zu [100.0%% of total] out of %9zu bytes [%5.1f%% used]", total_bytes, total_reserved, total_u_perc); } void ArchiveBuilder::print_bitmap_region_stats(size_t size, size_t total_size) { - log_debug(cds)("bm space: %9zu [ %4.1f%% of total] out of %9zu bytes [100.0%% used]", + aot_log_debug(aot)("bm space: %9zu [ %4.1f%% of total] out of %9zu bytes [100.0%% used]", size, size/double(total_size)*100.0, size); } @@ -1594,7 +1683,7 @@ void ArchiveBuilder::print_heap_region_stats(ArchiveHeapInfo *info, size_t total char* start = info->buffer_start(); size_t size = info->buffer_byte_size(); char* top = start + size; - log_debug(cds)("hp space: %9zu [ %4.1f%% of total] out of %9zu bytes [100.0%% used] at " INTPTR_FORMAT, + aot_log_debug(aot)("hp space: %9zu [ %4.1f%% of total] out of %9zu bytes [100.0%% used] at " INTPTR_FORMAT, size, size/double(total_size)*100.0, size, p2i(start)); } @@ -1605,6 +1694,6 @@ void ArchiveBuilder::report_out_of_space(const char* name, size_t needed_bytes) _rw_region.print_out_of_space_msg(name, needed_bytes); _ro_region.print_out_of_space_msg(name, needed_bytes); - log_error(cds)("Unable to allocate from '%s' region: Please reduce the number of shared classes.", name); + log_error(aot)("Unable to allocate from '%s' region: Please reduce the number of shared classes.", name); MetaspaceShared::unrecoverable_writing_error(); } diff --git a/src/hotspot/share/cds/archiveBuilder.hpp b/src/hotspot/share/cds/archiveBuilder.hpp index 5913ae29c78..1957786fe76 100644 --- a/src/hotspot/share/cds/archiveBuilder.hpp +++ b/src/hotspot/share/cds/archiveBuilder.hpp @@ -217,6 +217,7 @@ class ArchiveBuilder : public StackObj { DumpRegion _rw_region; DumpRegion _ro_region; + DumpRegion _ac_region; // AOT code // Combined bitmap to track pointers in both RW and RO regions. This is updated // as objects are copied into RW and RO. @@ -237,6 +238,11 @@ class ArchiveBuilder : public StackObj { // statistics DumpAllocStats _alloc_stats; size_t _total_heap_region_size; + struct { + size_t _num_ptrs; + size_t _num_tagged_ptrs; + size_t _num_nulled_ptrs; + } _relocated_ptr_info; void print_region_stats(FileMapInfo *map_info, ArchiveHeapInfo* heap_info); void print_bitmap_region_stats(size_t size, size_t total_size); @@ -257,6 +263,8 @@ class ArchiveBuilder : public StackObj { ~OtherROAllocMark(); }; + void count_relocated_pointer(bool tagged, bool nulled); + private: FollowMode get_follow_mode(MetaspaceClosure::Ref *ref); @@ -372,6 +380,7 @@ class ArchiveBuilder : public StackObj { DumpRegion* pz_region() { return &_pz_region; } DumpRegion* rw_region() { return &_rw_region; } DumpRegion* ro_region() { return &_ro_region; } + DumpRegion* ac_region() { return &_ac_region; } static char* rw_region_alloc(size_t num_bytes) { return current()->rw_region()->allocate(num_bytes); @@ -379,6 +388,12 @@ class ArchiveBuilder : public StackObj { static char* ro_region_alloc(size_t num_bytes) { return current()->ro_region()->allocate(num_bytes); } + static char* ac_region_alloc(size_t num_bytes) { + return current()->ac_region()->allocate(num_bytes); + } + + void start_ac_region(); + void end_ac_region(); template static Array* new_ro_array(int length) { @@ -411,6 +426,7 @@ class ArchiveBuilder : public StackObj { void relocate_metaspaceobj_embedded_pointers(); void record_regenerated_object(address orig_src_obj, address regen_src_obj); void make_klasses_shareable(); + void make_training_data_shareable(); void relocate_to_requested(); void write_archive(FileMapInfo* mapinfo, ArchiveHeapInfo* heap_info); void write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region, @@ -426,6 +442,8 @@ class ArchiveBuilder : public StackObj { mark_and_relocate_to_buffered_addr((address*)ptr_location); } + bool has_been_archived(address src_addr) const; + bool has_been_buffered(address src_addr) const; template bool has_been_buffered(T src_addr) const { return has_been_buffered((address)src_addr); @@ -433,7 +451,8 @@ class ArchiveBuilder : public StackObj { address get_buffered_addr(address src_addr) const; template T get_buffered_addr(T src_addr) const { - return (T)get_buffered_addr((address)src_addr); + CDS_ONLY(return (T)get_buffered_addr((address)src_addr);) + NOT_CDS(return nullptr;) } address get_source_addr(address buffered_addr) const; @@ -446,7 +465,8 @@ class ArchiveBuilder : public StackObj { GrowableArray* symbols() const { return _symbols; } static bool is_active() { - return (_current != nullptr); + CDS_ONLY(return (_current != nullptr)); + NOT_CDS(return false;) } static ArchiveBuilder* current() { diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp index 68015e319c3..181fa6b2bb4 100644 --- a/src/hotspot/share/cds/archiveHeapLoader.cpp +++ b/src/hotspot/share/cds/archiveHeapLoader.cpp @@ -167,7 +167,7 @@ void ArchiveHeapLoader::patch_compressed_embedded_pointers(BitMapView bm, MemRegion region) { narrowOop dt_encoded_bottom = info->encoded_heap_region_dumptime_address(); narrowOop rt_encoded_bottom = CompressedOops::encode_not_null(cast_to_oop(region.start())); - log_info(cds)("patching heap embedded pointers: narrowOop 0x%8x -> 0x%8x", + log_info(aot)("patching heap embedded pointers: narrowOop 0x%8x -> 0x%8x", (uint)dt_encoded_bottom, (uint)rt_encoded_bottom); // Optimization: if dumptime shift is the same as runtime shift, we can perform a @@ -175,15 +175,15 @@ void ArchiveHeapLoader::patch_compressed_embedded_pointers(BitMapView bm, narrowOop* patching_start = (narrowOop*)region.start() + FileMapInfo::current_info()->heap_oopmap_start_pos(); if (_narrow_oop_shift == CompressedOops::shift()) { uint32_t quick_delta = (uint32_t)rt_encoded_bottom - (uint32_t)dt_encoded_bottom; - log_info(cds)("CDS heap data relocation quick delta = 0x%x", quick_delta); + log_info(aot)("heap data relocation quick delta = 0x%x", quick_delta); if (quick_delta == 0) { - log_info(cds)("CDS heap data relocation unnecessary, quick_delta = 0"); + log_info(aot)("heap data relocation unnecessary, quick_delta = 0"); } else { PatchCompressedEmbeddedPointersQuick patcher(patching_start, quick_delta); bm.iterate(&patcher); } } else { - log_info(cds)("CDS heap data quick relocation not possible"); + log_info(aot)("heap data quick relocation not possible"); PatchCompressedEmbeddedPointers patcher(patching_start); bm.iterate(&patcher); } @@ -301,12 +301,12 @@ bool ArchiveHeapLoader::load_heap_region_impl(FileMapInfo* mapinfo, LoadedArchiv if (!mapinfo->read_region(loaded_region->_region_index, (char*)load_address, r->used(), /* do_commit = */ false)) { // There's no easy way to free the buffer, so we will fill it with zero later // in fill_failed_loaded_heap(), and it will eventually be GC'ed. - log_warning(cds)("Loading of heap region %d has failed. Archived objects are disabled", loaded_region->_region_index); + log_warning(aot)("Loading of heap region %d has failed. Archived objects are disabled", loaded_region->_region_index); _loading_failed = true; return false; } assert(r->mapped_base() == (char*)load_address, "sanity"); - log_info(cds)("Loaded heap region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT + log_info(aot)("Loaded heap region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " size %6zu delta %zd", loaded_region->_region_index, load_address, load_address + loaded_region->_region_size, loaded_region->_region_size, loaded_region->_runtime_offset); @@ -408,7 +408,7 @@ void ArchiveHeapLoader::finish_loaded_heap() { } void ArchiveHeapLoader::verify_loaded_heap() { - log_info(cds, heap)("Verify all oops and pointers in loaded heap"); + log_info(aot, heap)("Verify all oops and pointers in loaded heap"); ResourceMark rm; ResourceHashtable table; @@ -459,7 +459,7 @@ void ArchiveHeapLoader::patch_native_pointers() { FileMapRegion* r = FileMapInfo::current_info()->region_at(MetaspaceShared::hp); if (r->mapped_base() != nullptr && r->has_ptrmap()) { - log_info(cds, heap)("Patching native pointers in heap region"); + log_info(aot, heap)("Patching native pointers in heap region"); BitMapView bm = FileMapInfo::current_info()->ptrmap_view(MetaspaceShared::hp); PatchNativePointers patcher((Metadata**)r->mapped_base() + FileMapInfo::current_info()->heap_ptrmap_start_pos()); bm.iterate(&patcher); diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index 5684066105f..ee1e334e84b 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/cdsConfig.hpp" #include "cds/filemap.hpp" @@ -246,7 +247,7 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeapat(root_index++)); } - log_info(cds, heap)("archived obj root segment [%d] = %zu bytes, obj = " PTR_FORMAT, + log_info(aot, heap)("archived obj root segment [%d] = %zu bytes, obj = " PTR_FORMAT, size_elems, size_bytes, p2i(seg_oop)); } @@ -292,7 +293,7 @@ int ArchiveHeapWriter::compare_objs_by_oop_fields(HeapObjOrder* a, HeapObjOrder* } void ArchiveHeapWriter::sort_source_objs() { - log_info(cds)("sorting heap objects"); + log_info(aot)("sorting heap objects"); int len = _source_objs->length(); _source_objs_order = new GrowableArrayCHeap(len); @@ -302,9 +303,9 @@ void ArchiveHeapWriter::sort_source_objs() { HeapObjOrder os = {i, rank}; _source_objs_order->append(os); } - log_info(cds)("computed ranks"); + log_info(aot)("computed ranks"); _source_objs_order->sort(compare_objs_by_oop_fields); - log_info(cds)("sorting heap objects done"); + log_info(aot)("sorting heap objects done"); } void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap* roots) { @@ -329,7 +330,7 @@ void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeaplength() + 1, roots->length(), _num_native_ptrs); } @@ -395,7 +396,7 @@ void ArchiveHeapWriter::maybe_fill_gc_region_gap(size_t required_byte_size) { ensure_buffer_space(filler_end); int array_length = filler_array_length(fill_bytes); - log_info(cds, heap)("Inserting filler obj array of %d elements (%zu bytes total) @ buffer offset %zu", + log_info(aot, heap)("Inserting filler obj array of %d elements (%zu bytes total) @ buffer offset %zu", array_length, fill_bytes, _buffer_used); HeapWord* filler = init_filler_array_at_buffer_top(array_length, fill_bytes); _buffer_used = filler_end; @@ -473,7 +474,7 @@ void ArchiveHeapWriter::set_requested_address(ArchiveHeapInfo* info) { if (UseCompressedOops) { if (UseG1GC) { address heap_end = (address)G1CollectedHeap::heap()->reserved().end(); - log_info(cds, heap)("Heap end = %p", heap_end); + log_info(aot, heap)("Heap end = %p", heap_end); _requested_bottom = align_down(heap_end - heap_region_byte_size, G1HeapRegion::GrainBytes); _requested_bottom = align_down(_requested_bottom, MIN_GC_REGION_ALIGNMENT); assert(is_aligned(_requested_bottom, G1HeapRegion::GrainBytes), "sanity"); @@ -607,18 +608,27 @@ class ArchiveHeapWriter::EmbeddedOopRelocator: public BasicOopIterateClosure { oop _src_obj; address _buffered_obj; CHeapBitMap* _oopmap; - + bool _is_java_lang_ref; public: EmbeddedOopRelocator(oop src_obj, address buffered_obj, CHeapBitMap* oopmap) : - _src_obj(src_obj), _buffered_obj(buffered_obj), _oopmap(oopmap) {} + _src_obj(src_obj), _buffered_obj(buffered_obj), _oopmap(oopmap) + { + _is_java_lang_ref = AOTReferenceObjSupport::check_if_ref_obj(src_obj); + } void do_oop(narrowOop *p) { EmbeddedOopRelocator::do_oop_work(p); } void do_oop( oop *p) { EmbeddedOopRelocator::do_oop_work(p); } private: template void do_oop_work(T *p) { - size_t field_offset = pointer_delta(p, _src_obj, sizeof(char)); - ArchiveHeapWriter::relocate_field_in_buffer((T*)(_buffered_obj + field_offset), _oopmap); + int field_offset = pointer_delta_as_int((char*)p, cast_from_oop(_src_obj)); + T* field_addr = (T*)(_buffered_obj + field_offset); + if (_is_java_lang_ref && AOTReferenceObjSupport::skip_field(field_offset)) { + // Do not copy these fields. Set them to null + *field_addr = (T)0x0; + } else { + ArchiveHeapWriter::relocate_field_in_buffer(field_addr, _oopmap); + } } }; @@ -626,7 +636,7 @@ static void log_bitmap_usage(const char* which, BitMap* bitmap, size_t total_bit // The whole heap is covered by total_bits, but there are only non-zero bits within [start ... end). size_t start = bitmap->find_first_set_bit(0); size_t end = bitmap->size(); - log_info(cds)("%s = %7zu ... %7zu (%3zu%% ... %3zu%% = %3zu%%)", which, + log_info(aot)("%s = %7zu ... %7zu (%3zu%% ... %3zu%% = %3zu%%)", which, start, end, start * 100 / total_bits, end * 100 / total_bits, @@ -753,7 +763,7 @@ void ArchiveHeapWriter::compute_ptrmap(ArchiveHeapInfo* heap_info) { } heap_info->ptrmap()->resize(max_idx + 1); - log_info(cds, heap)("calculate_ptrmap: marked %d non-null native pointers for heap region (%zu bits)", + log_info(aot, heap)("calculate_ptrmap: marked %d non-null native pointers for heap region (%zu bits)", num_non_null_ptrs, size_t(heap_info->ptrmap()->size())); } diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp index 217b30e401d..9a92c6a8648 100644 --- a/src/hotspot/share/cds/archiveUtils.cpp +++ b/src/hotspot/share/cds/archiveUtils.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotLogging.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.inline.hpp" #include "cds/archiveUtils.hpp" @@ -168,7 +169,7 @@ class ArchivePtrBitmapCleaner: public BitMapClosure { } } else { _ptrmap->clear_bit(offset); - DEBUG_ONLY(log_trace(cds, reloc)("Clearing pointer [" PTR_FORMAT "] -> null @ %9zu", p2i(ptr_loc), offset)); + DEBUG_ONLY(log_trace(aot, reloc)("Clearing pointer [" PTR_FORMAT "] -> null @ %9zu", p2i(ptr_loc), offset)); } return true; @@ -207,7 +208,7 @@ char* DumpRegion::expand_top_to(char* newtop) { // This is just a sanity check and should not appear in any real world usage. This // happens only if you allocate more than 2GB of shared objects and would require // millions of shared classes. - log_error(cds)("Out of memory in the CDS archive: Please reduce the number of shared classes."); + aot_log_error(aot)("Out of memory in the CDS archive: Please reduce the number of shared classes."); MetaspaceShared::unrecoverable_writing_error(); } } @@ -233,7 +234,7 @@ void DumpRegion::commit_to(char* newtop) { assert(commit <= uncommitted, "sanity"); if (!_vs->expand_by(commit, false)) { - log_error(cds)("Failed to expand shared space to %zu bytes", + aot_log_error(aot)("Failed to expand shared space to %zu bytes", need_committed_size); MetaspaceShared::unrecoverable_writing_error(); } @@ -244,7 +245,7 @@ void DumpRegion::commit_to(char* newtop) { } else { which = "shared"; } - log_debug(cds)("Expanding %s spaces by %7zu bytes [total %9zu bytes ending at %p]", + log_debug(aot)("Expanding %s spaces by %7zu bytes [total %9zu bytes ending at %p]", which, commit, _vs->actual_committed_size(), _vs->high()); } @@ -270,16 +271,17 @@ void DumpRegion::append_intptr_t(intptr_t n, bool need_to_mark) { } void DumpRegion::print(size_t total_bytes) const { - log_debug(cds)("%s space: %9zu [ %4.1f%% of total] out of %9zu bytes [%5.1f%% used] at " INTPTR_FORMAT, + char* base = used() > 0 ? ArchiveBuilder::current()->to_requested(_base) : nullptr; + log_debug(aot)("%s space: %9zu [ %4.1f%% of total] out of %9zu bytes [%5.1f%% used] at " INTPTR_FORMAT, _name, used(), percent_of(used(), total_bytes), reserved(), percent_of(used(), reserved()), - p2i(ArchiveBuilder::current()->to_requested(_base))); + p2i(base)); } void DumpRegion::print_out_of_space_msg(const char* failing_region, size_t needed_bytes) { - log_error(cds)("[%-8s] " PTR_FORMAT " - " PTR_FORMAT " capacity =%9d, allocated =%9d", + aot_log_error(aot)("[%-8s] " PTR_FORMAT " - " PTR_FORMAT " capacity =%9d, allocated =%9d", _name, p2i(_base), p2i(_top), int(_end - _base), int(_top - _base)); if (strcmp(_name, failing_region) == 0) { - log_error(cds)(" required = %d", int(needed_bytes)); + aot_log_error(aot)(" required = %d", int(needed_bytes)); } } @@ -295,7 +297,10 @@ void DumpRegion::init(ReservedSpace* rs, VirtualSpace* vs) { } void DumpRegion::pack(DumpRegion* next) { - assert(!is_packed(), "sanity"); + if (!is_packed()) { + _end = (char*)align_up(_top, MetaspaceShared::core_region_alignment()); + _is_packed = true; + } _end = (char*)align_up(_top, MetaspaceShared::core_region_alignment()); _is_packed = true; if (next != nullptr) { diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 56d28ec910c..93e84694c35 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -136,12 +136,12 @@ class SharedDataRelocator: public BitMapClosure { _valid_old_base(valid_old_base), _valid_old_end(valid_old_end), _valid_new_base(valid_new_base), _valid_new_end(valid_new_end), _delta(delta) { - log_debug(cds, reloc)("SharedDataRelocator::_patch_base = " PTR_FORMAT, p2i(_patch_base)); - log_debug(cds, reloc)("SharedDataRelocator::_patch_end = " PTR_FORMAT, p2i(_patch_end)); - log_debug(cds, reloc)("SharedDataRelocator::_valid_old_base = " PTR_FORMAT, p2i(_valid_old_base)); - log_debug(cds, reloc)("SharedDataRelocator::_valid_old_end = " PTR_FORMAT, p2i(_valid_old_end)); - log_debug(cds, reloc)("SharedDataRelocator::_valid_new_base = " PTR_FORMAT, p2i(_valid_new_base)); - log_debug(cds, reloc)("SharedDataRelocator::_valid_new_end = " PTR_FORMAT, p2i(_valid_new_end)); + log_debug(aot, reloc)("SharedDataRelocator::_patch_base = " PTR_FORMAT, p2i(_patch_base)); + log_debug(aot, reloc)("SharedDataRelocator::_patch_end = " PTR_FORMAT, p2i(_patch_end)); + log_debug(aot, reloc)("SharedDataRelocator::_valid_old_base = " PTR_FORMAT, p2i(_valid_old_base)); + log_debug(aot, reloc)("SharedDataRelocator::_valid_old_end = " PTR_FORMAT, p2i(_valid_old_end)); + log_debug(aot, reloc)("SharedDataRelocator::_valid_new_base = " PTR_FORMAT, p2i(_valid_new_base)); + log_debug(aot, reloc)("SharedDataRelocator::_valid_new_end = " PTR_FORMAT, p2i(_valid_new_end)); } bool do_bit(size_t offset); @@ -180,6 +180,7 @@ class DumpRegion { bool is_allocatable() const { return !is_packed() && _base != nullptr; } + bool is_empty() const { return _base == _top; } void print(size_t total_bytes) const; void print_out_of_space_msg(const char* failing_region, size_t needed_bytes); diff --git a/src/hotspot/share/cds/archiveUtils.inline.hpp b/src/hotspot/share/cds/archiveUtils.inline.hpp index 72de48743f3..12c9a0bc705 100644 --- a/src/hotspot/share/cds/archiveUtils.inline.hpp +++ b/src/hotspot/share/cds/archiveUtils.inline.hpp @@ -27,6 +27,7 @@ #include "cds/archiveUtils.hpp" +#include "cds/aotLogging.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/metaspaceShared.hpp" @@ -46,7 +47,7 @@ inline bool SharedDataRelocator::do_bit(size_t offset) { assert(new_ptr != nullptr, "don't point to the bottom of the archive"); // See ArchivePtrMarker::mark_pointer(). assert(_valid_new_base <= new_ptr && new_ptr < _valid_new_end, "must be"); - DEBUG_ONLY(log_trace(cds, reloc)("Patch2: @%8d [" PTR_FORMAT "] " PTR_FORMAT " -> " PTR_FORMAT, + DEBUG_ONLY(aot_log_trace(aot, reloc)("Patch2: @%8d [" PTR_FORMAT "] " PTR_FORMAT " -> " PTR_FORMAT, (int)offset, p2i(p), p2i(old_ptr), p2i(new_ptr))); *p = new_ptr; return true; // keep iterating diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index 64ad07b0cf8..b3c13b63aff 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotLogging.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConfig.hpp" #include "cds/classListWriter.hpp" @@ -32,6 +33,7 @@ #include "include/jvm_io.h" #include "logging/log.hpp" #include "memory/universe.hpp" +#include "prims/jvmtiAgentList.hpp" #include "runtime/arguments.hpp" #include "runtime/globals_extension.hpp" #include "runtime/java.hpp" @@ -47,6 +49,8 @@ bool CDSConfig::_is_using_optimized_module_handling = true; bool CDSConfig::_is_dumping_full_module_graph = true; bool CDSConfig::_is_using_full_module_graph = true; bool CDSConfig::_has_aot_linked_classes = false; +bool CDSConfig::_is_single_command_training = false; +bool CDSConfig::_has_temp_aot_config_file = false; bool CDSConfig::_old_cds_flags_used = false; bool CDSConfig::_new_aot_flags_used = false; bool CDSConfig::_disable_heap_dumping = false; @@ -106,10 +110,12 @@ const char* CDSConfig::default_archive_path() { // before CDSConfig::ergo_initialize() is called. assert(_cds_ergo_initialize_started, "sanity"); if (_default_archive_path == nullptr) { + char jvm_path[JVM_MAXPATHLEN]; + os::jvm_path(jvm_path, sizeof(jvm_path)); + char *end = strrchr(jvm_path, *os::file_separator()); + if (end != nullptr) *end = '\0'; stringStream tmp; - const char* subdir = WINDOWS_ONLY("bin") NOT_WINDOWS("lib"); - tmp.print("%s%s%s%s%s%sclasses", Arguments::get_java_home(), os::file_separator(), subdir, - os::file_separator(), Abstract_VM_Version::vm_variant(), os::file_separator()); + tmp.print("%s%sclasses", jvm_path, os::file_separator()); #ifdef _LP64 if (!UseCompressedOops) { tmp.print_raw("_nocoops"); @@ -233,7 +239,7 @@ void CDSConfig::ergo_init_classic_archive_paths() { warning("-XX:+AutoCreateSharedArchive is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."); AutoCreateSharedArchive = false; } - log_error(cds)("Not a valid archive (%s)", SharedArchiveFile); + aot_log_error(aot)("Not a valid %s (%s)", type_of_archive_being_loaded(), SharedArchiveFile); Arguments::no_shared_spaces("invalid archive"); } } else if (base_archive_path == nullptr) { @@ -277,7 +283,7 @@ void CDSConfig::ergo_init_classic_archive_paths() { void CDSConfig::check_internal_module_property(const char* key, const char* value) { if (Arguments::is_incompatible_cds_internal_module_property(key)) { stop_using_optimized_module_handling(); - log_info(cds)("optimized module handling: disabled due to incompatible property: %s=%s", key, value); + aot_log_info(aot)("optimized module handling: disabled due to incompatible property: %s=%s", key, value); } } @@ -292,7 +298,7 @@ void CDSConfig::check_incompatible_property(const char* key, const char* value) if (strcmp(key, property) == 0) { stop_dumping_full_module_graph(); stop_using_full_module_graph(); - log_info(cds)("full module graph: disabled due to incompatible property: %s=%s", key, value); + aot_log_info(aot)("full module graph: disabled due to incompatible property: %s=%s", key, value); break; } } @@ -358,9 +364,9 @@ bool CDSConfig::has_unsupported_runtime_module_options() { warning("CDS is disabled when the %s option is specified.", option); } else { if (new_aot_flags_used()) { - log_warning(cds)("AOT cache is disabled when the %s option is specified.", option); + aot_log_warning(aot)("AOT cache is disabled when the %s option is specified.", option); } else { - log_info(cds)("CDS is disabled when the %s option is specified.", option); + aot_log_info(aot)("CDS is disabled when the %s option is specified.", option); } } return true; @@ -394,38 +400,63 @@ void CDSConfig::check_aot_flags() { _old_cds_flags_used = true; } - // "New" AOT flags must not be mixed with "classic" flags such as -Xshare:dump + // "New" AOT flags must not be mixed with "classic" CDS flags such as -Xshare:dump CHECK_NEW_FLAG(AOTCache); + CHECK_NEW_FLAG(AOTCacheOutput); CHECK_NEW_FLAG(AOTConfiguration); CHECK_NEW_FLAG(AOTMode); CHECK_SINGLE_PATH(AOTCache); + CHECK_SINGLE_PATH(AOTCacheOutput); CHECK_SINGLE_PATH(AOTConfiguration); - if (FLAG_IS_DEFAULT(AOTCache) && FLAG_IS_DEFAULT(AOTConfiguration) && FLAG_IS_DEFAULT(AOTMode)) { - // AOTCache/AOTConfiguration/AOTMode not used. + if (FLAG_IS_DEFAULT(AOTCache) && AOTAdapterCaching) { + log_debug(aot,codecache,init)("AOTCache is not specified - AOTAdapterCaching is ignored"); + } + if (FLAG_IS_DEFAULT(AOTCache) && AOTStubCaching) { + log_debug(aot,codecache,init)("AOTCache is not specified - AOTStubCaching is ignored"); + } + + bool has_cache = !FLAG_IS_DEFAULT(AOTCache); + bool has_cache_output = !FLAG_IS_DEFAULT(AOTCacheOutput); + bool has_config = !FLAG_IS_DEFAULT(AOTConfiguration); + bool has_mode = !FLAG_IS_DEFAULT(AOTMode); + + if (!has_cache && !has_cache_output && !has_config && !has_mode) { + // AOT flags are not used. Use classic CDS workflow return; - } else { - _new_aot_flags_used = true; } + if (has_cache && has_cache_output) { + vm_exit_during_initialization("Only one of AOTCache or AOTCacheOutput can be specified"); + } + + if (!has_cache && (!has_mode || strcmp(AOTMode, "auto") == 0)) { + if (has_cache_output) { + // If AOTCacheOutput has been set, effective mode is "record". + // Default value for AOTConfiguration, if necessary, will be assigned in check_aotmode_record(). + log_info(aot)("Selected AOTMode=record because AOTCacheOutput is specified"); + FLAG_SET_ERGO(AOTMode, "record"); + } + } + + // At least one AOT flag has been used + _new_aot_flags_used = true; + if (FLAG_IS_DEFAULT(AOTMode) || strcmp(AOTMode, "auto") == 0 || strcmp(AOTMode, "on") == 0) { check_aotmode_auto_or_on(); } else if (strcmp(AOTMode, "off") == 0) { check_aotmode_off(); + } else if (strcmp(AOTMode, "record") == 0) { + check_aotmode_record(); } else { - // AOTMode is record or create - if (FLAG_IS_DEFAULT(AOTConfiguration)) { - vm_exit_during_initialization(err_msg("-XX:AOTMode=%s cannot be used without setting AOTConfiguration", AOTMode)); - } - - if (strcmp(AOTMode, "record") == 0) { - check_aotmode_record(); - } else { - assert(strcmp(AOTMode, "create") == 0, "checked by AOTModeConstraintFunc"); - check_aotmode_create(); - } + assert(strcmp(AOTMode, "create") == 0, "checked by AOTModeConstraintFunc"); + check_aotmode_create(); } + + // This is an old flag used by CDS regression testing only. It doesn't apply + // to the AOT workflow. + FLAG_SET_ERGO(AllowArchivingWithJavaAgent, false); } void CDSConfig::check_aotmode_off() { @@ -435,7 +466,8 @@ void CDSConfig::check_aotmode_off() { void CDSConfig::check_aotmode_auto_or_on() { if (!FLAG_IS_DEFAULT(AOTConfiguration)) { - vm_exit_during_initialization("AOTConfiguration can only be used with -XX:AOTMode=record or -XX:AOTMode=create"); + vm_exit_during_initialization(err_msg("AOTConfiguration can only be used with when AOTMode is record or create (selected AOTMode = %s)", + FLAG_IS_DEFAULT(AOTMode) ? "auto" : AOTMode)); } UseSharedSpaces = true; @@ -447,11 +479,63 @@ void CDSConfig::check_aotmode_auto_or_on() { } } +// %p substitution in AOTCache, AOTCacheOutput and AOTCacheConfiguration +static void substitute_aot_filename(JVMFlagsEnum flag_enum) { + JVMFlag* flag = JVMFlag::flag_from_enum(flag_enum); + const char* filename = flag->read(); + assert(filename != nullptr, "must not have default value"); + + // For simplicity, we don't allow %p/%t to be specified twice, because make_log_name() + // substitutes only the first occurrence. Otherwise, if we run with + // java -XX:AOTCacheOutput=%p%p.aot + // it will end up with both the pid of the training process and the assembly process. + const char* first_p = strstr(filename, "%p"); + if (first_p != nullptr && strstr(first_p + 2, "%p") != nullptr) { + vm_exit_during_initialization(err_msg("%s cannot contain more than one %%p", flag->name())); + } + const char* first_t = strstr(filename, "%t"); + if (first_t != nullptr && strstr(first_t + 2, "%t") != nullptr) { + vm_exit_during_initialization(err_msg("%s cannot contain more than one %%t", flag->name())); + } + + // Note: with single-command training, %p will be the pid of the training process, not the + // assembly process. + const char* new_filename = make_log_name(filename, nullptr); + if (strcmp(filename, new_filename) != 0) { + JVMFlag::Error err = JVMFlagAccess::set_ccstr(flag, &new_filename, JVMFlagOrigin::ERGONOMIC); + assert(err == JVMFlag::SUCCESS, "must never fail"); + } + FREE_C_HEAP_ARRAY(char, new_filename); +} + void CDSConfig::check_aotmode_record() { + bool has_config = !FLAG_IS_DEFAULT(AOTConfiguration); + bool has_output = !FLAG_IS_DEFAULT(AOTCacheOutput); + + if (!has_output && !has_config) { + vm_exit_during_initialization("At least one of AOTCacheOutput and AOTConfiguration must be specified when using -XX:AOTMode=record"); + } + + if (has_output) { + _is_single_command_training = true; + substitute_aot_filename(FLAG_MEMBER_ENUM(AOTCacheOutput)); + if (!has_config) { + // Too early; can't use resource allocation yet. + size_t len = strlen(AOTCacheOutput) + 10; + char* temp = AllocateHeap(len, mtArguments); + jio_snprintf(temp, len, "%s.config", AOTCacheOutput); + FLAG_SET_ERGO(AOTConfiguration, temp); + FreeHeap(temp); + _has_temp_aot_config_file = true; + } + } + if (!FLAG_IS_DEFAULT(AOTCache)) { vm_exit_during_initialization("AOTCache must not be specified when using -XX:AOTMode=record"); } + substitute_aot_filename(FLAG_MEMBER_ENUM(AOTConfiguration)); + UseSharedSpaces = false; RequireSharedSpaces = false; _is_dumping_static_archive = true; @@ -463,10 +547,27 @@ void CDSConfig::check_aotmode_record() { } void CDSConfig::check_aotmode_create() { - if (FLAG_IS_DEFAULT(AOTCache)) { - vm_exit_during_initialization("AOTCache must be specified when using -XX:AOTMode=create"); + if (FLAG_IS_DEFAULT(AOTConfiguration)) { + vm_exit_during_initialization("AOTConfiguration must be specified when using -XX:AOTMode=create"); } + bool has_cache = !FLAG_IS_DEFAULT(AOTCache); + bool has_cache_output = !FLAG_IS_DEFAULT(AOTCacheOutput); + + assert(!(has_cache && has_cache_output), "already checked"); + + if (!has_cache && !has_cache_output) { + vm_exit_during_initialization("AOTCache or AOTCacheOutput must be specified when using -XX:AOTMode=create"); + } + + if (!has_cache) { + precond(has_cache_output); + FLAG_SET_ERGO(AOTCache, AOTCacheOutput); + } + // No need to check for (!has_cache_output), as we don't look at AOTCacheOutput after here. + + substitute_aot_filename(FLAG_MEMBER_ENUM(AOTCache)); + _is_dumping_final_static_archive = true; UseSharedSpaces = true; RequireSharedSpaces = true; @@ -476,6 +577,15 @@ void CDSConfig::check_aotmode_create() { } CDSConfig::enable_dumping_static_archive(); + + // We don't load any agents in the assembly phase, so we can ensure that the agents + // cannot affect the contents of the AOT cache. E.g., we don't want the agents to + // redefine any cached classes. We also don't want the agents to modify heap objects that + // are cached. + // + // Since application is not executed in the assembly phase, there's no need to load + // the agents anyway -- no one will notice that the agents are not loaded. + JvmtiAgentList::disable_agent_list(); } void CDSConfig::ergo_init_aot_paths() { @@ -508,6 +618,8 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla FLAG_SET_ERGO_IF_DEFAULT(AOTClassLinking, true); } + setup_compiler_args(); + if (AOTClassLinking) { // If AOTClassLinking is specified, enable all AOT optimizations by default. FLAG_SET_ERGO_IF_DEFAULT(AOTInvokeDynamicLinking, true); @@ -517,7 +629,7 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla } if (is_dumping_static_archive()) { - if (is_dumping_preimage_static_archive()) { + if (is_dumping_preimage_static_archive() || is_dumping_final_static_archive()) { // Don't tweak execution mode } else if (!mode_flag_cmd_line) { // By default, -Xshare:dump runs in interpreter-only mode, which is required for deterministic archive. @@ -528,7 +640,7 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla } else if (Arguments::mode() == Arguments::_comp) { // -Xcomp may use excessive CPU for the test tiers. Also, -Xshare:dump runs a small and fixed set of // Java code, so there's not much benefit in running -Xcomp. - log_info(cds)("reduced -Xcomp to -Xmixed for static dumping"); + aot_log_info(aot)("reduced -Xcomp to -Xmixed for static dumping"); Arguments::set_mode_flags(Arguments::_mixed); } @@ -536,9 +648,6 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla // run to another which resulting in non-determinstic CDS archives. // Disable UseStringDeduplication while dumping CDS archive. UseStringDeduplication = false; - - // Don't use SoftReferences so that objects used by java.lang.invoke tables can be archived. - Arguments::PropertyList_add(new SystemProperty("java.lang.invoke.MethodHandleNatives.USE_SOFT_CACHE", "false", false)); } // RecordDynamicDumpInfo is not compatible with ArchiveClassesAtExit @@ -556,11 +665,11 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla if (AutoCreateSharedArchive) { if (SharedArchiveFile == nullptr) { - log_warning(cds)("-XX:+AutoCreateSharedArchive requires -XX:SharedArchiveFile"); + aot_log_warning(aot)("-XX:+AutoCreateSharedArchive requires -XX:SharedArchiveFile"); return false; } if (ArchiveClassesAtExit != nullptr) { - log_warning(cds)("-XX:+AutoCreateSharedArchive does not work with ArchiveClassesAtExit"); + aot_log_warning(aot)("-XX:+AutoCreateSharedArchive does not work with ArchiveClassesAtExit"); return false; } } @@ -576,13 +685,35 @@ bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_fla // Always verify non-system classes during CDS dump if (!BytecodeVerificationRemote) { BytecodeVerificationRemote = true; - log_info(cds)("All non-system classes will be verified (-Xverify:remote) during CDS dump time."); + aot_log_info(aot)("All non-system classes will be verified (-Xverify:remote) during CDS dump time."); } } return true; } +void CDSConfig::setup_compiler_args() { + // AOT profiles are supported only in the JEP 483 workflow. + bool can_dump_profiles = AOTClassLinking && new_aot_flags_used(); + + if (is_dumping_preimage_static_archive() && can_dump_profiles) { + // JEP 483 workflow -- training + FLAG_SET_ERGO_IF_DEFAULT(AOTRecordTraining, true); + FLAG_SET_ERGO(AOTReplayTraining, false); + } else if (is_dumping_final_static_archive() && can_dump_profiles) { + // JEP 483 workflow -- assembly + FLAG_SET_ERGO(AOTRecordTraining, false); + FLAG_SET_ERGO_IF_DEFAULT(AOTReplayTraining, true); + } else if (is_using_archive() && new_aot_flags_used()) { + // JEP 483 workflow -- production + FLAG_SET_ERGO(AOTRecordTraining, false); + FLAG_SET_ERGO_IF_DEFAULT(AOTReplayTraining, true); + } else { + FLAG_SET_ERGO(AOTReplayTraining, false); + FLAG_SET_ERGO(AOTRecordTraining, false); + } +} + void CDSConfig::prepare_for_dumping() { assert(CDSConfig::is_dumping_archive(), "sanity"); @@ -597,11 +728,11 @@ void CDSConfig::prepare_for_dumping() { #define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info." if (RecordDynamicDumpInfo) { - log_error(cds)("-XX:+RecordDynamicDumpInfo%s", __THEMSG); + aot_log_error(aot)("-XX:+RecordDynamicDumpInfo%s", __THEMSG); MetaspaceShared::unrecoverable_loading_error(); } else { assert(ArchiveClassesAtExit != nullptr, "sanity"); - log_warning(cds)("-XX:ArchiveClassesAtExit" __THEMSG); + aot_log_warning(aot)("-XX:ArchiveClassesAtExit" __THEMSG); } #undef __THEMSG disable_dumping_dynamic_archive(); @@ -646,6 +777,14 @@ bool CDSConfig::is_using_archive() { return UseSharedSpaces; } +bool CDSConfig::is_using_only_default_archive() { + return is_using_archive() && + input_static_archive_path() != nullptr && + default_archive_path() != nullptr && + strcmp(input_static_archive_path(), default_archive_path()) == 0 && + input_dynamic_archive_path() == nullptr; +} + bool CDSConfig::is_logging_lambda_form_invokers() { return ClassListWriter::is_enabled() || is_dumping_dynamic_archive(); } @@ -740,7 +879,7 @@ void CDSConfig::log_reasons_for_not_dumping_heap() { } assert(reason != nullptr, "sanity"); - log_info(cds)("Archived java heap is not supported: %s", reason); + aot_log_info(aot)("Archived java heap is not supported: %s", reason); } // This is *Legacy* optimization for lambdas before JEP 483. May be removed in the future. @@ -790,7 +929,7 @@ void CDSConfig::stop_dumping_full_module_graph(const char* reason) { if (_is_dumping_full_module_graph) { _is_dumping_full_module_graph = false; if (reason != nullptr) { - log_info(cds)("full module graph cannot be dumped: %s", reason); + aot_log_info(aot)("full module graph cannot be dumped: %s", reason); } } } @@ -800,7 +939,7 @@ void CDSConfig::stop_using_full_module_graph(const char* reason) { if (_is_using_full_module_graph) { _is_using_full_module_graph = false; if (reason != nullptr) { - log_info(cds)("full module graph cannot be loaded: %s", reason); + aot_log_info(aot)("full module graph cannot be loaded: %s", reason); } } } @@ -847,3 +986,26 @@ bool CDSConfig::is_dumping_method_handles() { } #endif // INCLUDE_CDS_JAVA_HEAP + +// AOT code generation and its archiving is disabled by default. +// We enable it only in the final image dump after the metadata and heap are dumped. +// This affects only JITed code because it may have embedded oops and metadata pointers +// which AOT code encodes as offsets in final CDS archive regions. + +static bool _is_dumping_aot_code = false; + +bool CDSConfig::is_dumping_aot_code() { + return _is_dumping_aot_code; +} + +void CDSConfig::disable_dumping_aot_code() { + _is_dumping_aot_code = false; +} + +void CDSConfig::enable_dumping_aot_code() { + _is_dumping_aot_code = true; +} + +bool CDSConfig::is_dumping_adapters() { + return (AOTAdapterCaching && is_dumping_final_static_archive()); +} diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp index e96291f6534..1fd229ff34f 100644 --- a/src/hotspot/share/cds/cdsConfig.hpp +++ b/src/hotspot/share/cds/cdsConfig.hpp @@ -41,6 +41,8 @@ class CDSConfig : public AllStatic { static bool _is_dumping_full_module_graph; static bool _is_using_full_module_graph; static bool _has_aot_linked_classes; + static bool _is_single_command_training; + static bool _has_temp_aot_config_file; const static char* _default_archive_path; const static char* _input_static_archive_path; @@ -67,6 +69,7 @@ class CDSConfig : public AllStatic { static void check_aotmode_auto_or_on(); static void check_aotmode_record(); static void check_aotmode_create(); + static void setup_compiler_args(); static void check_unsupported_dumping_module_options(); // Called after Arguments::apply_ergo() has started @@ -103,6 +106,7 @@ class CDSConfig : public AllStatic { // input archive(s) static bool is_using_archive() NOT_CDS_RETURN_(false); + static bool is_using_only_default_archive() NOT_CDS_RETURN_(false); // static_archive static bool is_dumping_static_archive() { return CDS_ONLY(_is_dumping_static_archive) NOT_CDS(false); } @@ -140,6 +144,9 @@ class CDSConfig : public AllStatic { // Misc CDS features static bool allow_only_single_java_thread() NOT_CDS_RETURN_(false); + static bool is_single_command_training() { return CDS_ONLY(_is_single_command_training) NOT_CDS(false); } + static bool has_temp_aot_config_file() { return CDS_ONLY(_has_temp_aot_config_file) NOT_CDS(false); } + // This is *Legacy* optimization for lambdas before JEP 483. May be removed in the future. static bool is_dumping_lambdas_in_legacy_mode() NOT_CDS_RETURN_(false); @@ -181,6 +188,13 @@ class CDSConfig : public AllStatic { static void stop_dumping_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN; static void stop_using_full_module_graph(const char* reason = nullptr) NOT_CDS_JAVA_HEAP_RETURN; + // --- AOT code + + static bool is_dumping_aot_code() NOT_CDS_RETURN_(false); + static void disable_dumping_aot_code() NOT_CDS_RETURN; + static void enable_dumping_aot_code() NOT_CDS_RETURN; + static bool is_dumping_adapters() NOT_CDS_RETURN_(false); + // Some CDS functions assume that they are called only within a single-threaded context. I.e., // they are called from: // - The VM thread (e.g., inside VM_PopulateDumpSharedSpace) diff --git a/src/hotspot/share/cds/cdsEnumKlass.cpp b/src/hotspot/share/cds/cdsEnumKlass.cpp index ffce9fb269a..fe55c904312 100644 --- a/src/hotspot/share/cds/cdsEnumKlass.cpp +++ b/src/hotspot/share/cds/cdsEnumKlass.cpp @@ -99,7 +99,7 @@ void CDSEnumKlass::archive_static_field(int level, KlassSubGraphInfo* subgraph_i bool success = HeapShared::archive_reachable_objects_from(level, subgraph_info, oop_field); assert(success, "VM should have exited with unarchivable objects for _level > 1"); int root_index = HeapShared::append_root(oop_field); - log_info(cds, heap)("Archived enum obj @%d %s::%s (" INTPTR_FORMAT ")", + log_info(aot, heap)("Archived enum obj @%d %s::%s (" INTPTR_FORMAT ")", root_index, ik->external_name(), fd.name()->as_C_string(), p2i((oopDesc*)oop_field)); SystemDictionaryShared::add_enum_klass_static_field(ik, root_index); @@ -113,9 +113,9 @@ bool CDSEnumKlass::initialize_enum_klass(InstanceKlass* k, TRAPS) { RunTimeClassInfo* info = RunTimeClassInfo::get_for(k); assert(info != nullptr, "sanity"); - if (log_is_enabled(Info, cds, heap)) { + if (log_is_enabled(Info, aot, heap)) { ResourceMark rm; - log_info(cds, heap)("Initializing Enum class: %s", k->external_name()); + log_info(aot, heap)("Initializing Enum class: %s", k->external_name()); } oop mirror = k->java_mirror(); diff --git a/src/hotspot/share/cds/cdsHeapVerifier.cpp b/src/hotspot/share/cds/cdsHeapVerifier.cpp index 9bab62dabe6..2f3c2521b22 100644 --- a/src/hotspot/share/cds/cdsHeapVerifier.cpp +++ b/src/hotspot/share/cds/cdsHeapVerifier.cpp @@ -138,11 +138,10 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0) "CD_Object_array", // E same as <...>ConstantUtils.CD_Object_array::CD_Object "INVOKER_SUPER_DESC"); // E same as java.lang.constant.ConstantDescs::CD_Object - ADD_EXCL("java/lang/invoke/MethodHandleImpl$ArrayAccessor", - "OBJECT_ARRAY_GETTER", // D - "OBJECT_ARRAY_SETTER", // D - "OBJECT_ARRAY_LENGTH"); // D - + ADD_EXCL("java/lang/runtime/ObjectMethods", "CLASS_IS_INSTANCE", // D + "FALSE", // D + "TRUE", // D + "ZERO"); // D } # undef ADD_EXCL @@ -152,10 +151,10 @@ CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0) CDSHeapVerifier::~CDSHeapVerifier() { if (_problems > 0) { - log_error(cds, heap)("Scanned %d objects. Found %d case(s) where " + log_error(aot, heap)("Scanned %d objects. Found %d case(s) where " "an object points to a static field that " "may hold a different value at runtime.", _archived_objs, _problems); - log_error(cds, heap)("Please see cdsHeapVerifier.cpp and aotClassInitializer.cpp for details"); + log_error(aot, heap)("Please see cdsHeapVerifier.cpp and aotClassInitializer.cpp for details"); MetaspaceShared::unrecoverable_writing_error(); } } @@ -286,7 +285,7 @@ inline bool CDSHeapVerifier::do_entry(oop& orig_obj, HeapShared::CachedOopInfo& ResourceMark rm; char* class_name = info->_holder->name()->as_C_string(); char* field_name = info->_name->as_C_string(); - LogStream ls(Log(cds, heap)::warning()); + LogStream ls(Log(aot, heap)::warning()); ls.print_cr("Archive heap points to a static field that may hold a different value at runtime:"); ls.print_cr("Field: %s::%s", class_name, field_name); ls.print("Value: "); diff --git a/src/hotspot/share/cds/cdsProtectionDomain.cpp b/src/hotspot/share/cds/cdsProtectionDomain.cpp index dc3d8621db1..e743df67796 100644 --- a/src/hotspot/share/cds/cdsProtectionDomain.cpp +++ b/src/hotspot/share/cds/cdsProtectionDomain.cpp @@ -120,7 +120,7 @@ PackageEntry* CDSProtectionDomain::get_package_entry_from_class(InstanceKlass* i PackageEntry* pkg_entry = ik->package(); if (CDSConfig::is_using_full_module_graph() && ik->is_shared() && pkg_entry != nullptr) { assert(MetaspaceShared::is_in_shared_metaspace(pkg_entry), "must be"); - assert(!ik->is_shared_unregistered_class(), "unexpected archived package entry for an unregistered class"); + assert(!ik->defined_by_other_loaders(), "unexpected archived package entry for an unregistered class"); assert(ik->module()->is_named(), "unexpected archived package entry for a class in an unnamed module"); return pkg_entry; } diff --git a/src/hotspot/share/cds/cds_globals.hpp b/src/hotspot/share/cds/cds_globals.hpp index 2dae9b45221..e51dd26ff06 100644 --- a/src/hotspot/share/cds/cds_globals.hpp +++ b/src/hotspot/share/cds/cds_globals.hpp @@ -64,7 +64,8 @@ range(2, 246) \ \ product(bool, AllowArchivingWithJavaAgent, false, DIAGNOSTIC, \ - "Allow Java agent to be run with CDS dumping") \ + "Allow Java agent to be run with CDS dumping (not applicable" \ + " to AOT") \ \ develop(ccstr, ArchiveHeapTestClass, nullptr, \ "For JVM internal testing only. The static field named " \ @@ -112,9 +113,14 @@ "The configuration file written by -XX:AOTMode=record, and " \ "loaded by -XX:AOTMode=create. This file contains profiling data "\ "for deciding what contents should be added to AOTCache. ") \ + constraint(AOTConfigurationConstraintFunc, AtParse) \ \ product(ccstr, AOTCache, nullptr, \ "Cache for improving start up and warm up") \ + constraint(AOTCacheConstraintFunc, AtParse) \ + \ + product(ccstr, AOTCacheOutput, nullptr, \ + "Specifies the file name for writing the AOT cache") \ \ product(bool, AOTInvokeDynamicLinking, false, DIAGNOSTIC, \ "AOT-link JVM_CONSTANT_InvokeDynamic entries in cached " \ @@ -127,6 +133,42 @@ product(bool, AOTCacheParallelRelocation, true, DIAGNOSTIC, \ "Use parallel relocation code to speed up startup.") \ \ + /* flags to control training and deployment modes */ \ + \ + product(bool, AOTRecordTraining, false, DIAGNOSTIC, \ + "Request output of training data for improved deployment.") \ + \ + product(bool, AOTReplayTraining, false, DIAGNOSTIC, \ + "Read training data, if available, for use in this execution") \ + \ + product(bool, AOTPrintTrainingInfo, false, DIAGNOSTIC, \ + "Print additional information about training") \ + \ + product(bool, AOTVerifyTrainingData, trueInDebug, DIAGNOSTIC, \ + "Verify archived training data") \ + \ + product(bool, AOTCompileEagerly, false, DIAGNOSTIC, \ + "Compile methods as soon as possible") \ + \ + /* AOT Code flags */ \ + \ + product(bool, AOTAdapterCaching, false, DIAGNOSTIC, \ + "Enable saving and restoring i2c2i adapters in AOT cache") \ + \ + product(bool, AOTStubCaching, false, DIAGNOSTIC, \ + "Enable saving and restoring stubs and code blobs in AOT cache") \ + \ + product(uint, AOTCodeMaxSize, 10*M, DIAGNOSTIC, \ + "Buffer size in bytes for AOT code caching") \ + range(1*M, max_jint) \ + \ + product(bool, AbortVMOnAOTCodeFailure, false, DIAGNOSTIC, \ + "Abort VM on the first occurrence of AOT code load or store " \ + "failure. By default VM will continue execute without AOT code.") \ + \ + develop(bool, TestAOTAdapterLinkFailure, false, \ + "Test failure of adapter linking when loading from AOT cache.") \ + // end of CDS_FLAGS DECLARE_FLAGS(CDS_FLAGS) diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 10154265bec..9cf703c627f 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotConstantPoolResolver.hpp" +#include "cds/aotLogging.hpp" #include "cds/archiveUtils.hpp" #include "cds/classListParser.hpp" #include "cds/lambdaFormInvokers.hpp" @@ -68,7 +69,7 @@ ClassListParser::ClassListParser(const char* file, ParseMode parse_mode) : _file_input(do_open(file), /* need_close=*/true), _input_stream(&_file_input), _parse_mode(parse_mode) { - log_info(cds)("Parsing %s%s", file, + aot_log_info(aot)("Parsing %s%s", file, parse_lambda_forms_invokers_only() ? " (lambda form invokers only)" : ""); if (!_file_input.is_open()) { char reason[JVM_MAXPATHLEN]; @@ -163,18 +164,18 @@ void ClassListParser::parse_class_name_and_attributes(TRAPS) { if (message != nullptr) { ex_msg = java_lang_String::as_utf8_string(message); } - log_warning(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), ex_msg); + aot_log_warning(aot)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), ex_msg); // We might have an invalid class name or an bad class. Warn about it // and keep going to the next line. CLEAR_PENDING_EXCEPTION; - log_warning(cds)("Preload Warning: Cannot find %s", _class_name); + aot_log_warning(aot)("Preload Warning: Cannot find %s", _class_name); return; } assert(klass != nullptr, "sanity"); - if (log_is_enabled(Trace, cds)) { + if (aot_log_is_enabled(Trace, aot)) { ResourceMark rm(THREAD); - log_trace(cds)("Shared spaces preloaded: %s", klass->external_name()); + log_trace(aot)("Shared spaces preloaded: %s", klass->external_name()); } if (klass->is_instance_klass()) { @@ -395,17 +396,13 @@ bool ClassListParser::parse_uint_option(const char* option_name, int* value) { return false; } -objArrayOop ClassListParser::get_specified_interfaces(TRAPS) { +GrowableArray ClassListParser::get_specified_interfaces() { const int n = _interfaces->length(); - if (n == 0) { - return nullptr; - } else { - objArrayOop array = oopFactory::new_objArray(vmClasses::Class_klass(), n, CHECK_NULL); - for (int i = 0; i < n; i++) { - array->obj_at_put(i, lookup_class_by_id(_interfaces->at(i))->java_mirror()); - } - return array; + GrowableArray specified_interfaces(n); + for (int i = 0; i < n; i++) { + specified_interfaces.append(lookup_class_by_id(_interfaces->at(i))); } + return specified_interfaces; } void ClassListParser::print_specified_interfaces() { @@ -502,13 +499,32 @@ void ClassListParser::check_class_name(const char* class_name) { void ClassListParser::constant_pool_resolution_warning(const char* msg, ...) { va_list ap; va_start(ap, msg); - LogTarget(Warning, cds, resolve) lt; + LogTarget(Warning, aot, resolve) lt; LogStream ls(lt); print_diagnostic_info(&ls, msg, ap); ls.print("Your classlist may be out of sync with the JDK or the application."); va_end(ap); } +// If an unregistered class U is specified to have a registered supertype S1 +// named SN but an unregistered class S2 also named SN has already been loaded +// S2 will be incorrectly used as the supertype of U instead of S1 due to +// limitations in the loading mechanism of unregistered classes. +void ClassListParser::check_supertype_obstruction(int specified_supertype_id, const InstanceKlass* specified_supertype, TRAPS) { + if (specified_supertype->defined_by_other_loaders()) { + return; // Only registered supertypes can be obstructed + } + const InstanceKlass* obstructor = SystemDictionaryShared::get_unregistered_class(specified_supertype->name()); + if (obstructor == nullptr) { + return; // No unregistered types with the same name have been loaded, i.e. no obstruction + } + // 'specified_supertype' is S1, 'obstructor' is S2 from the explanation above + ResourceMark rm; + THROW_MSG(vmSymbols::java_lang_UnsupportedOperationException(), + err_msg("%s (id %d) has super-type %s (id %d) obstructed by another class with the same name", + _class_name, _id, specified_supertype->external_name(), specified_supertype_id)); +} + // This function is used for loading classes for customized class loaders // during archive dumping. InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS) { @@ -527,19 +543,24 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS error("If source location is specified, id must be also specified"); } if (strncmp(_class_name, "java/", 5) == 0) { - log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s", + aot_log_info(aot)("Prohibited package for non-bootstrap classes: %s.class from %s", _class_name, _source); THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()); } ResourceMark rm; - char * source_path = os::strdup_check_oom(ClassLoader::uri_to_path(_source)); InstanceKlass* specified_super = lookup_class_by_id(_super); - Handle super_class(THREAD, specified_super->java_mirror()); - objArrayOop r = get_specified_interfaces(CHECK_NULL); - objArrayHandle interfaces(THREAD, r); - InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, - super_class, interfaces, CHECK_NULL); + GrowableArray specified_interfaces = get_specified_interfaces(); + // Obstruction must be checked before the class loading attempt because it may + // cause class loading errors (JVMS 5.3.5.3-5.3.5.4) + check_supertype_obstruction(_super, specified_super, CHECK_NULL); + for (int i = 0; i < _interfaces->length(); i++) { + check_supertype_obstruction(_interfaces->at(i), specified_interfaces.at(i), CHECK_NULL); + } + + const char* source_path = ClassLoader::uri_to_path(_source); + InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL); + if (k->java_super() != specified_super) { error("The specified super class %s (id %d) does not match actual super class %s", specified_super->external_name(), _super, @@ -551,8 +572,17 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS error("The number of interfaces (%d) specified in class list does not match the class file (%d)", _interfaces->length(), k->local_interfaces()->length()); } + for (int i = 0; i < _interfaces->length(); i++) { + InstanceKlass* specified_interface = specified_interfaces.at(i); + if (!k->local_interfaces()->contains(specified_interface)) { + print_specified_interfaces(); + print_actual_interfaces(k); + error("Specified interface %s (id %d) is not directly implemented", + specified_interface->external_name(), _interfaces->at(i)); + } + } - assert(k->is_shared_unregistered_class(), "must be"); + assert(k->defined_by_other_loaders(), "must be"); bool added = SystemDictionaryShared::add_unregistered_class(THREAD, k); if (!added) { @@ -619,7 +649,7 @@ void ClassListParser::resolve_indy(JavaThread* current, Symbol* class_name_symbo if (message != nullptr) { ex_msg = java_lang_String::as_utf8_string(message); } - log_warning(cds)("resolve_indy for class %s has encountered exception: %s %s", + aot_log_warning(aot)("resolve_indy for class %s has encountered exception: %s %s", class_name_symbol->as_C_string(), PENDING_EXCEPTION->klass()->external_name(), ex_msg); @@ -659,7 +689,7 @@ void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) { BootstrapInfo bootstrap_specifier(pool, pool_index, indy_index); Handle bsm = bootstrap_specifier.resolve_bsm(CHECK); if (!LambdaProxyClassDictionary::is_supported_invokedynamic(&bootstrap_specifier)) { - log_debug(cds, lambda)("is_supported_invokedynamic check failed for cp_index %d", pool_index); + log_debug(aot, lambda)("is_supported_invokedynamic check failed for cp_index %d", pool_index); continue; } bool matched = is_matching_cp_entry(pool, pool_index, CHECK); @@ -682,7 +712,7 @@ void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) { } if (!found) { ResourceMark rm(THREAD); - log_warning(cds)("No invoke dynamic constant pool entry can be found for class %s. The classlist is probably out-of-date.", + aot_log_warning(aot)("No invoke dynamic constant pool entry can be found for class %s. The classlist is probably out-of-date.", class_name_symbol->as_C_string()); } } @@ -744,7 +774,7 @@ Klass* ClassListParser::load_current_class(Symbol* class_name_symbol, TRAPS) { error("Duplicated ID %d for class %s", id, _class_name); } if (id2klass_table()->maybe_grow()) { - log_info(cds, hashtables)("Expanded id2klass_table() to %d", id2klass_table()->table_size()); + log_info(aot, hashtables)("Expanded id2klass_table() to %d", id2klass_table()->table_size()); } } @@ -848,9 +878,9 @@ void ClassListParser::parse_constant_pool_tag() { } if (SystemDictionaryShared::should_be_excluded(ik)) { - if (log_is_enabled(Warning, cds, resolve)) { + if (log_is_enabled(Warning, aot, resolve)) { ResourceMark rm; - log_warning(cds, resolve)("Cannot aot-resolve constants for %s because it is excluded", ik->external_name()); + log_warning(aot, resolve)("Cannot aot-resolve constants for %s because it is excluded", ik->external_name()); } return; } diff --git a/src/hotspot/share/cds/classListParser.hpp b/src/hotspot/share/cds/classListParser.hpp index 1b059b4d85a..1762c5c6a30 100644 --- a/src/hotspot/share/cds/classListParser.hpp +++ b/src/hotspot/share/cds/classListParser.hpp @@ -137,7 +137,8 @@ class ClassListParser : public StackObj { void print_diagnostic_info(outputStream* st, const char* msg, ...) ATTRIBUTE_PRINTF(3, 0); void constant_pool_resolution_warning(const char* msg, ...) ATTRIBUTE_PRINTF(2, 0); void error(const char* msg, ...) ATTRIBUTE_PRINTF(2, 0); - objArrayOop get_specified_interfaces(TRAPS); + GrowableArray get_specified_interfaces(); + void check_supertype_obstruction(int specified_supertype_id, const InstanceKlass* specified_supertype, TRAPS); public: static void parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS); diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 2a3513c45f5..c1ac1b47b11 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -57,7 +57,7 @@ void ClassListWriter::write(const InstanceKlass* k, const ClassFileStream* cfs) assert(is_enabled(), "must be"); if (!ClassLoader::has_jrt_entry()) { - log_warning(cds)("DumpLoadedClassList and CDS are not supported in exploded build"); + log_warning(aot)("DumpLoadedClassList and CDS are not supported in exploded build"); DumpLoadedClassList = nullptr; return; } diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp index b8243cedf6d..fe8b8d917be 100644 --- a/src/hotspot/share/cds/cppVtables.cpp +++ b/src/hotspot/share/cds/cppVtables.cpp @@ -32,7 +32,9 @@ #include "oops/instanceMirrorKlass.hpp" #include "oops/instanceRefKlass.hpp" #include "oops/instanceStackChunkKlass.hpp" +#include "oops/methodCounters.hpp" #include "oops/methodData.hpp" +#include "oops/trainingData.hpp" #include "oops/objArrayKlass.hpp" #include "oops/typeArrayKlass.hpp" #include "runtime/arguments.hpp" @@ -60,8 +62,13 @@ f(InstanceRefKlass) \ f(InstanceStackChunkKlass) \ f(Method) \ + f(MethodData) \ + f(MethodCounters) \ f(ObjArrayKlass) \ - f(TypeArrayKlass) + f(TypeArrayKlass) \ + f(KlassTrainingData) \ + f(MethodTrainingData) \ + f(CompileTrainingData) class CppVtableInfo { intptr_t _vtable_size; @@ -116,7 +123,7 @@ void CppVtableCloner::initialize(const char* name, CppVtableInfo* info) { // We already checked (and, if necessary, adjusted n) when the vtables were allocated, so we are // safe to do memcpy. - log_debug(cds, vtables)("Copying %3d vtable entries for %s", n, name); + log_debug(aot, vtables)("Copying %3d vtable entries for %s", n, name); memcpy(dstvtable, srcvtable, sizeof(intptr_t) * n); } @@ -166,7 +173,7 @@ int CppVtableCloner::get_vtable_length(const char* name) { break; } } - log_debug(cds, vtables)("Found %3d vtable entries for %s", vtable_len, name); + log_debug(aot, vtables)("Found %3d vtable entries for %s", vtable_len, name); return vtable_len; } @@ -279,14 +286,11 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob case MetaspaceObj::ConstMethodType: case MetaspaceObj::ConstantPoolCacheType: case MetaspaceObj::AnnotationsType: - case MetaspaceObj::MethodCountersType: case MetaspaceObj::RecordComponentType: + case MetaspaceObj::AdapterHandlerEntryType: + case MetaspaceObj::AdapterFingerPrintType: // These have no vtables. break; - case MetaspaceObj::MethodDataType: - // We don't archive MethodData <-- should have been removed in removed_unsharable_info - ShouldNotReachHere(); - break; default: for (kind = 0; kind < _num_cloned_vtable_kinds; kind ++) { if (vtable_of((Metadata*)obj) == _orig_cpp_vtptrs[kind] || diff --git a/src/hotspot/share/cds/dumpAllocStats.cpp b/src/hotspot/share/cds/dumpAllocStats.cpp index 5587ac2fac8..5f324566103 100644 --- a/src/hotspot/share/cds/dumpAllocStats.cpp +++ b/src/hotspot/share/cds/dumpAllocStats.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotClassLinker.hpp" +#include "cds/cdsConfig.hpp" #include "cds/dumpAllocStats.hpp" #include "logging/log.hpp" #include "logging/logMessage.hpp" @@ -52,7 +53,7 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all) { const char *sep = "--------------------+---------------------------+---------------------------+--------------------------"; const char *hdr = " ro_cnt ro_bytes % | rw_cnt rw_bytes % | all_cnt all_bytes %"; - LogMessage(cds) msg; + LogMessage(aot) msg; msg.debug("Detailed metadata info (excluding heap region):"); msg.debug("%s", hdr); @@ -118,8 +119,15 @@ void DumpAllocStats::print_stats(int ro_all, int rw_all) { _num_indy_cp_entries, _num_indy_cp_entries_archived, percent_of(_num_indy_cp_entries_archived, _num_indy_cp_entries), _num_indy_cp_entries_reverted); - msg.info("Platform loader initiated classes = %5d", AOTClassLinker::num_platform_initiated_classes()); - msg.info("App loader initiated classes = %5d", AOTClassLinker::num_app_initiated_classes()); + msg.info("Platform loader initiated classes = %6d", AOTClassLinker::num_platform_initiated_classes()); + msg.info("App loader initiated classes = %6d", AOTClassLinker::num_app_initiated_classes()); + msg.info("MethodCounters = %6d (%8d bytes)", _counts[RW][MethodCountersType], + _bytes [RW][MethodCountersType]); + msg.info("KlassTrainingData = %6d (%8d bytes)", _counts[RW][KlassTrainingDataType], + _bytes [RW][KlassTrainingDataType]); + msg.info("MethodTrainingData = %6d (%8d bytes)", _counts[RW][MethodTrainingDataType], + _bytes [RW][MethodTrainingDataType]); + } #ifdef ASSERT diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.cpp b/src/hotspot/share/cds/dumpTimeClassInfo.cpp index 94a0f14ff1f..6a06344fb0d 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.cpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.cpp @@ -71,9 +71,9 @@ void DumpTimeClassInfo::add_verification_constraint(InstanceKlass* k, Symbol* na c |= from_is_object ? RunTimeClassInfo::FROM_IS_OBJECT : 0; vcflags_array->append(c); - if (log_is_enabled(Trace, cds, verification)) { + if (log_is_enabled(Trace, aot, verification)) { ResourceMark rm; - log_trace(cds, verification)("add_verification_constraint: %s: %s must be subclass of %s [0x%x] array len %d flags len %d", + log_trace(aot, verification)("add_verification_constraint: %s: %s must be subclass of %s [0x%x] array len %d flags len %d", k->external_name(), from_name->as_klass_external_name(), name->as_klass_external_name(), c, vc_array->length(), vcflags_array->length()); } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp index 6f5ca6d7915..2d1f57175a0 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.inline.hpp @@ -46,7 +46,7 @@ void DumpTimeSharedClassTable::iterate_all_live_classes(Function function) const assert(SafepointSynchronize::is_at_safepoint(), "invariant"); assert_lock_strong(DumpTimeTable_lock); if (CDSConfig::is_dumping_final_static_archive() && !k->is_loaded()) { - assert(k->is_shared_unregistered_class(), "must be"); + assert(k->defined_by_other_loaders(), "must be"); function(k, info); } else if (k->is_loader_alive()) { function(k, info); diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index bf4257253e8..b1072dbce9b 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -25,6 +25,7 @@ #include "cds/aotArtifactFinder.hpp" #include "cds/aotClassLinker.hpp" #include "cds/aotClassLocation.hpp" +#include "cds/aotLogging.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapWriter.hpp" #include "cds/archiveUtils.inline.hpp" @@ -101,7 +102,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder { // is caused by dynamic dumping. void verify_universe(const char* info) { if (VerifyBeforeExit) { - log_info(cds)("Verify %s", info); + log_info(aot)("Verify %s", info); // Among other things, this ensures that Eden top is correct. Universe::heap()->prepare_for_verify(); Universe::verify(info); @@ -120,8 +121,8 @@ class DynamicArchiveBuilder : public ArchiveBuilder { return; } - log_info(cds,dynamic)("CDS dynamic dump: clinit = " JLONG_FORMAT "ms)", - ClassLoader::class_init_time_ms()); + log_info(cds, dynamic)("CDS dynamic dump: clinit = " JLONG_FORMAT "ms)", + ClassLoader::class_init_time_ms()); init_header(); gather_source_objs(); @@ -136,7 +137,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder { sort_methods(); - log_info(cds)("Make classes shareable"); + log_info(aot)("Make classes shareable"); make_klasses_shareable(); char* serialized_data; @@ -161,7 +162,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder { } if (CDSConfig::is_dumping_lambdas_in_legacy_mode()) { - log_info(cds)("Adjust lambda proxy class dictionary"); + log_info(aot)("Adjust lambda proxy class dictionary"); LambdaProxyClassDictionary::adjust_dumptime_table(); } @@ -378,7 +379,7 @@ void DynamicArchiveBuilder::gather_array_klasses() { } } } - log_debug(cds)("Total array klasses gathered for dynamic archive: %d", DynamicArchive::num_array_klasses()); + log_debug(aot)("Total array klasses gathered for dynamic archive: %d", DynamicArchive::num_array_klasses()); } class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation { @@ -390,7 +391,7 @@ class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation { void doit() { ResourceMark rm; if (AllowArchivingWithJavaAgent) { - log_warning(cds)("This %s was created with AllowArchivingWithJavaAgent. It should be used " + aot_log_warning(aot)("This %s was created with AllowArchivingWithJavaAgent. It should be used " "for testing purposes only and should not be used in a production environment", CDSConfig::type_of_archive_being_loaded()); } @@ -445,7 +446,7 @@ void DynamicArchive::setup_array_klasses() { ArrayKlass::cast(elm)->set_higher_dimension(oak); } } - log_debug(cds)("Total array klasses read from dynamic archive: %d", _dynamic_archive_array_klasses->length()); + log_debug(aot)("Total array klasses read from dynamic archive: %d", _dynamic_archive_array_klasses->length()); } } @@ -501,8 +502,8 @@ void DynamicArchive::dump_at_exit(JavaThread* current) { if (HAS_PENDING_EXCEPTION) { // One of the prepatory steps failed oop ex = current->pending_exception(); - log_error(cds)("Dynamic dump has failed"); - log_error(cds)("%s: %s", ex->klass()->external_name(), + aot_log_error(aot)("Dynamic dump has failed"); + aot_log_error(aot)("%s: %s", ex->klass()->external_name(), java_lang_String::as_utf8_string(java_lang_Throwable::message(ex))); CLEAR_PENDING_EXCEPTION; CDSConfig::disable_dumping_dynamic_archive(); // Just for good measure @@ -526,14 +527,14 @@ bool DynamicArchive::validate(FileMapInfo* dynamic_info) { // Check the header crc if (dynamic_header->base_header_crc() != base_info->crc()) { - log_warning(cds)("Dynamic archive cannot be used: static archive header checksum verification failed."); + aot_log_warning(aot)("Dynamic archive cannot be used: static archive header checksum verification failed."); return false; } // Check each space's crc for (int i = 0; i < MetaspaceShared::n_regions; i++) { if (dynamic_header->base_region_crc(i) != base_info->region_crc(i)) { - log_warning(cds)("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i); + aot_log_warning(aot)("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i); return false; } } diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 580699b60b5..a413aa2d8e8 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -23,6 +23,7 @@ */ #include "cds/aotClassLocation.hpp" +#include "cds/aotLogging.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.inline.hpp" #include "cds/archiveHeapWriter.hpp" @@ -59,6 +60,7 @@ #include "oops/compressedKlass.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" +#include "oops/trainingData.hpp" #include "oops/typeArrayKlass.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" @@ -230,6 +232,14 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment, } else { _narrow_klass_pointer_bits = _narrow_klass_shift = -1; } + _type_profile_level = TypeProfileLevel; + _type_profile_args_limit = TypeProfileArgsLimit; + _type_profile_parms_limit = TypeProfileParmsLimit; + _type_profile_width = TypeProfileWidth; + _bci_profile_width = BciProfileWidth; + _profile_traps = ProfileTraps; + _type_profile_casts = TypeProfileCasts; + _spec_trap_limit_extra_entries = SpecTrapLimitExtraEntries; _max_heap_size = MaxHeapSize; _use_optimized_module_handling = CDSConfig::is_using_optimized_module_handling(); _has_aot_linked_classes = CDSConfig::is_dumping_aot_linked_classes(); @@ -315,7 +325,7 @@ bool FileMapInfo::validate_class_location() { AOTClassLocationConfig* config = header()->class_location_config(); bool has_extra_module_paths = false; - if (!config->validate(header()->has_aot_linked_classes(), &has_extra_module_paths)) { + if (!config->validate(full_path(), header()->has_aot_linked_classes(), &has_extra_module_paths)) { if (PrintSharedArchiveAndExit) { MetaspaceShared::set_archive_loading_failed(); return true; @@ -326,7 +336,7 @@ bool FileMapInfo::validate_class_location() { if (header()->has_full_module_graph() && has_extra_module_paths) { CDSConfig::stop_using_optimized_module_handling(); - log_info(cds)("optimized module handling: disabled because extra module path(s) are specified"); + MetaspaceShared::report_loading_error("optimized module handling: disabled because extra module path(s) are specified"); } if (CDSConfig::is_dumping_dynamic_archive()) { @@ -336,13 +346,13 @@ bool FileMapInfo::validate_class_location() { // the runtime image and the -cp, dynamic dumping is disabled. if (config->num_boot_classpaths() > 0) { CDSConfig::disable_dumping_dynamic_archive(); - log_warning(cds)( + aot_log_warning(aot)( "Dynamic archiving is disabled because base layer archive has appended boot classpath"); } if (config->num_module_paths() > 0) { if (has_extra_module_paths) { CDSConfig::disable_dumping_dynamic_archive(); - log_warning(cds)( + aot_log_warning(aot)( "Dynamic archiving is disabled because base layer archive has a different module path"); } } @@ -397,7 +407,7 @@ class FileHeaderHelper { assert(_archive_name != nullptr, "Archive name is null"); _fd = os::open(_archive_name, O_RDONLY | O_BINARY, 0); if (_fd < 0) { - log_info(cds)("Specified %s not found (%s)", CDSConfig::type_of_archive_being_loaded(), _archive_name); + aot_log_info(aot)("Specified %s not found (%s)", CDSConfig::type_of_archive_being_loaded(), _archive_name); return false; } return initialize(_fd); @@ -414,31 +424,31 @@ class FileHeaderHelper { os::lseek(fd, 0, SEEK_SET); size_t n = ::read(fd, (void*)&gen_header, (unsigned int)size); if (n != size) { - log_warning(cds)("Unable to read generic CDS file map header from %s", file_type); + aot_log_warning(aot)("Unable to read generic CDS file map header from %s", file_type); return false; } if (gen_header._magic != CDS_ARCHIVE_MAGIC && gen_header._magic != CDS_DYNAMIC_ARCHIVE_MAGIC && gen_header._magic != CDS_PREIMAGE_ARCHIVE_MAGIC) { - log_warning(cds)("The %s has a bad magic number: %#x", file_type, gen_header._magic); + aot_log_warning(aot)("The %s has a bad magic number: %#x", file_type, gen_header._magic); return false; } if (gen_header._version < CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION) { - log_warning(cds)("Cannot handle %s version 0x%x. Must be at least 0x%x.", + aot_log_warning(aot)("Cannot handle %s version 0x%x. Must be at least 0x%x.", file_type, gen_header._version, CDS_GENERIC_HEADER_SUPPORTED_MIN_VERSION); return false; } if (gen_header._version != CURRENT_CDS_ARCHIVE_VERSION) { - log_warning(cds)("The %s version 0x%x does not match the required version 0x%x.", + aot_log_warning(aot)("The %s version 0x%x does not match the required version 0x%x.", file_type, gen_header._version, CURRENT_CDS_ARCHIVE_VERSION); } size_t filelen = os::lseek(fd, 0, SEEK_END); if (gen_header._header_size >= filelen) { - log_warning(cds)("Archive file header larger than archive file"); + aot_log_warning(aot)("Archive file header larger than archive file"); return false; } @@ -448,7 +458,7 @@ class FileHeaderHelper { os::lseek(fd, 0, SEEK_SET); n = ::read(fd, (void*)_header, (unsigned int)size); if (n != size) { - log_warning(cds)("Unable to read file map header from %s", file_type); + aot_log_warning(aot)("Unable to read file map header from %s", file_type); return false; } @@ -493,9 +503,9 @@ class FileHeaderHelper { 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); - log_warning(cds)("Header checksum verification failed."); + aot_log_info(aot)("_crc expected: %d", header->crc()); + aot_log_info(aot)(" actual: %d", actual_crc); + aot_log_warning(aot)("Header checksum verification failed."); return false; } } @@ -508,18 +518,18 @@ class FileHeaderHelper { unsigned int header_size = _header->_header_size; if (name_offset + name_size < name_offset) { - log_warning(cds)("base_archive_name offset/size overflow: " UINT32_FORMAT "/" UINT32_FORMAT, + aot_log_warning(aot)("base_archive_name offset/size overflow: " UINT32_FORMAT "/" UINT32_FORMAT, name_offset, name_size); return false; } if (is_static_archive() || is_preimage_static_archive()) { if (name_offset != 0) { - log_warning(cds)("static shared archive must have zero _base_archive_name_offset"); + aot_log_warning(aot)("static shared archive must have zero _base_archive_name_offset"); return false; } if (name_size != 0) { - log_warning(cds)("static shared archive must have zero _base_archive_name_size"); + aot_log_warning(aot)("static shared archive must have zero _base_archive_name_size"); return false; } } else { @@ -527,24 +537,24 @@ class FileHeaderHelper { 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. - log_warning(cds)("Invalid base_archive_name offset/size: " UINT32_FORMAT "/" UINT32_FORMAT, + aot_log_warning(aot)("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) { - log_warning(cds)("Invalid base_archive_name offset/size (out of range): " + aot_log_warning(aot)("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) { - log_warning(cds)("Base archive name is damaged"); + aot_log_warning(aot)("Base archive name is damaged"); return false; } if (!os::file_exists(name)) { - log_warning(cds)("Base archive %s does not exist", name); + aot_log_warning(aot)("Base archive %s does not exist", name); return false; } _base_archive_name = name; @@ -579,7 +589,7 @@ bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name, default: assert(header->_magic == CDS_ARCHIVE_MAGIC, "must be"); if (AutoCreateSharedArchive) { - log_warning(cds)("AutoCreateSharedArchive is ignored because %s is a static archive", archive_name); + aot_log_warning(aot)("AutoCreateSharedArchive is ignored because %s is a static archive", archive_name); } return true; } @@ -607,7 +617,7 @@ bool FileMapInfo::is_preimage_static_archive(const char* file) { bool FileMapInfo::init_from_file(int fd) { FileHeaderHelper file_helper(_full_path, _is_static); if (!file_helper.initialize(fd)) { - log_warning(cds)("Unable to read the file header."); + aot_log_warning(aot)("Unable to read the file header."); return false; } GenericCDSFileMapHeader* gen_header = file_helper.get_generic_file_header(); @@ -619,15 +629,15 @@ bool FileMapInfo::init_from_file(int fd) { // Good } else { if (CDSConfig::new_aot_flags_used()) { - log_warning(cds)("Not a valid %s (%s)", file_type, _full_path); + aot_log_warning(aot)("Not a valid %s (%s)", file_type, _full_path); } else { - log_warning(cds)("Not a base shared archive: %s", _full_path); + aot_log_warning(aot)("Not a base shared archive: %s", _full_path); } return false; } } else { if (gen_header->_magic != CDS_DYNAMIC_ARCHIVE_MAGIC) { - log_warning(cds)("Not a top shared archive: %s", _full_path); + aot_log_warning(aot)("Not a top shared archive: %s", _full_path); return false; } } @@ -637,14 +647,14 @@ bool FileMapInfo::init_from_file(int fd) { size_t size = gen_header->_header_size; size_t n = ::read(fd, (void*)_header, (unsigned int)size); if (n != size) { - log_warning(cds)("Failed to read file header from the top archive file\n"); + aot_log_warning(aot)("Failed to read file header from the top archive file\n"); return false; } if (header()->version() != CURRENT_CDS_ARCHIVE_VERSION) { - log_info(cds)("_version expected: 0x%x", CURRENT_CDS_ARCHIVE_VERSION); - log_info(cds)(" actual: 0x%x", header()->version()); - log_warning(cds)("The %s has the wrong version.", file_type); + aot_log_info(aot)("_version expected: 0x%x", CURRENT_CDS_ARCHIVE_VERSION); + aot_log_info(aot)(" actual: 0x%x", header()->version()); + aot_log_warning(aot)("The %s has the wrong version.", file_type); return false; } @@ -653,10 +663,10 @@ bool FileMapInfo::init_from_file(int fd) { unsigned int header_size = header()->header_size(); if (base_offset != 0 && name_size != 0) { if (header_size != base_offset + name_size) { - log_info(cds)("_header_size: " UINT32_FORMAT, header_size); - log_info(cds)("base_archive_name_size: " UINT32_FORMAT, header()->base_archive_name_size()); - log_info(cds)("base_archive_name_offset: " UINT32_FORMAT, header()->base_archive_name_offset()); - log_warning(cds)("The %s has an incorrect header size.", file_type); + aot_log_info(aot)("_header_size: " UINT32_FORMAT, header_size); + aot_log_info(aot)("base_archive_name_size: " UINT32_FORMAT, header()->base_archive_name_size()); + aot_log_info(aot)("base_archive_name_offset: " UINT32_FORMAT, header()->base_archive_name_offset()); + aot_log_warning(aot)("The %s has an incorrect header size.", file_type); return false; } } @@ -664,16 +674,16 @@ bool FileMapInfo::init_from_file(int fd) { const char* actual_ident = header()->jvm_ident(); if (actual_ident[JVM_IDENT_MAX-1] != 0) { - log_warning(cds)("JVM version identifier is corrupted."); + aot_log_warning(aot)("JVM version identifier is corrupted."); return false; } char expected_ident[JVM_IDENT_MAX]; get_header_version(expected_ident); if (strncmp(actual_ident, expected_ident, JVM_IDENT_MAX-1) != 0) { - log_info(cds)("_jvm_ident expected: %s", expected_ident); - log_info(cds)(" actual: %s", actual_ident); - log_warning(cds)("The %s was created by a different" + aot_log_info(aot)("_jvm_ident expected: %s", expected_ident); + aot_log_info(aot)(" actual: %s", actual_ident); + aot_log_warning(aot)("The %s was created by a different" " version or build of HotSpot", file_type); return false; } @@ -685,7 +695,7 @@ bool FileMapInfo::init_from_file(int fd) { for (int i = 0; i < MetaspaceShared::n_regions; i++) { FileMapRegion* r = region_at(i); if (r->file_offset() > len || len - r->file_offset() < r->used()) { - log_warning(cds)("The %s has been truncated.", file_type); + aot_log_warning(aot)("The %s has been truncated.", file_type); return false; } } @@ -695,7 +705,7 @@ bool FileMapInfo::init_from_file(int fd) { void FileMapInfo::seek_to_position(size_t pos) { if (os::lseek(_fd, (long)pos, SEEK_SET) < 0) { - log_error(cds)("Unable to seek to position %zu", pos); + aot_log_error(aot)("Unable to seek to position %zu", pos); MetaspaceShared::unrecoverable_loading_error(); } } @@ -708,18 +718,18 @@ bool FileMapInfo::open_for_read() { const char* file_type = CDSConfig::type_of_archive_being_loaded(); const char* info = CDSConfig::is_dumping_final_static_archive() ? "AOTConfiguration file " : ""; - log_info(cds)("trying to map %s%s", info, _full_path); + aot_log_info(aot)("trying to map %s%s", info, _full_path); int fd = os::open(_full_path, O_RDONLY | O_BINARY, 0); if (fd < 0) { if (errno == ENOENT) { - log_info(cds)("Specified %s not found (%s)", file_type, _full_path); + aot_log_info(aot)("Specified %s not found (%s)", file_type, _full_path); } else { - log_warning(cds)("Failed to open %s (%s)", file_type, + aot_log_warning(aot)("Failed to open %s (%s)", file_type, os::strerror(errno)); } return false; } else { - log_info(cds)("Opened %s %s.", file_type, _full_path); + aot_log_info(aot)("Opened %s %s.", file_type, _full_path); } _fd = fd; @@ -730,14 +740,14 @@ bool FileMapInfo::open_for_read() { // Write the FileMapInfo information to the file. void FileMapInfo::open_as_output() { - LogMessage(cds) msg; - if (msg.is_info()) { + if (CDSConfig::new_aot_flags_used()) { if (CDSConfig::is_dumping_preimage_static_archive()) { - msg.info("Writing binary AOTConfiguration file: "); + log_info(aot)("Writing binary AOTConfiguration file: %s", _full_path); } else { - msg.info("Dumping shared data to file: "); + log_info(aot)("Writing AOTCache file: %s", _full_path); } - msg.info(" %s", _full_path); + } else { + aot_log_info(aot)("Dumping shared data to file: %s", _full_path); } #ifdef _WINDOWS // On Windows, need WRITE permission to remove the file. @@ -747,10 +757,9 @@ void FileMapInfo::open_as_output() { // Use remove() to delete the existing file because, on Unix, this will // allow processes that have it open continued access to the file. remove(_full_path); - int mode = CDSConfig::is_dumping_preimage_static_archive() ? 0666 : 0444; - int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, mode); + int fd = os::open(_full_path, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666); if (fd < 0) { - log_error(cds)("Unable to create %s %s: (%s).", CDSConfig::type_of_archive_being_written(), _full_path, + aot_log_error(aot)("Unable to create %s %s: (%s).", CDSConfig::type_of_archive_being_written(), _full_path, os::strerror(errno)); MetaspaceShared::writing_error(); return; @@ -816,7 +825,7 @@ bool FileMapRegion::check_region_crc(char* base) const { assert(base != nullptr, "must be initialized"); int crc = ClassLoader::crc32(0, base, (jint)sz); if (crc != this->crc()) { - log_warning(cds)("Checksum verification failed."); + aot_log_warning(aot)("Checksum verification failed."); return false; } return true; @@ -824,7 +833,7 @@ bool FileMapRegion::check_region_crc(char* base) const { static const char* region_name(int region_index) { static const char* names[] = { - "rw", "ro", "bm", "hp" + "rw", "ro", "bm", "hp", "ac" }; const int num_regions = sizeof(names)/sizeof(names[0]); assert(0 <= region_index && region_index < num_regions, "sanity"); @@ -838,7 +847,7 @@ BitMapView FileMapInfo::bitmap_view(int region_index, bool is_oopmap) { bitmap_base += is_oopmap ? r->oopmap_offset() : r->ptrmap_offset(); size_t size_in_bits = is_oopmap ? r->oopmap_size_in_bits() : r->ptrmap_size_in_bits(); - log_debug(cds, reloc)("mapped %s relocation %smap @ " INTPTR_FORMAT " (%zu bits)", + aot_log_debug(aot, reloc)("mapped %s relocation %smap @ " INTPTR_FORMAT " (%zu bits)", region_name(region_index), is_oopmap ? "oop" : "ptr", p2i(bitmap_base), size_in_bits); @@ -906,10 +915,13 @@ void FileMapInfo::write_region(int region, char* base, size_t size, r->set_file_offset(_file_offset); int crc = ClassLoader::crc32(0, base, (jint)size); if (size > 0) { - log_info(cds)("Shared file region (%s) %d: %8zu" + aot_log_info(aot)("Shared file region (%s) %d: %8zu" " bytes, addr " INTPTR_FORMAT " file offset 0x%08" PRIxPTR " crc 0x%08x", region_name(region), region, size, p2i(requested_base), _file_offset, crc); + } else { + aot_log_info(aot)("Shared file region (%s) %d: %8zu" + " bytes", region_name(region), region, size); } r->init(region, mapping_offset, size, read_only, allow_exec, crc); @@ -1066,10 +1078,10 @@ void FileMapInfo::close() { */ static char* map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only, - bool allow_exec, MemTag mem_tag = mtNone) { + bool allow_exec, MemTag mem_tag) { char* mem = os::map_memory(fd, file_name, file_offset, addr, bytes, - AlwaysPreTouch ? false : read_only, - allow_exec, mem_tag); + mem_tag, AlwaysPreTouch ? false : read_only, + allow_exec); if (mem != nullptr && AlwaysPreTouch) { os::pretouch_memory(mem, mem + bytes); } @@ -1094,16 +1106,16 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() { assert(WINDOWS_ONLY(false) NOT_WINDOWS(true), "Don't call on Windows"); // Replace old mapping with new one that is writable. char *base = os::map_memory(_fd, _full_path, r->file_offset(), - addr, size, false /* !read_only */, + addr, size, mtNone, false /* !read_only */, r->allow_exec()); close(); // These have to be errors because the shared region is now unmapped. if (base == nullptr) { - log_error(cds)("Unable to remap shared readonly space (errno=%d).", errno); + aot_log_error(aot)("Unable to remap shared readonly space (errno=%d).", errno); vm_exit(1); } if (base != addr) { - log_error(cds)("Unable to remap shared readonly space (errno=%d).", errno); + aot_log_error(aot)("Unable to remap shared readonly space (errno=%d).", errno); vm_exit(1); } r->set_read_only(false); @@ -1111,7 +1123,7 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() { } // Memory map a region in the address space. -static const char* shared_region_name[] = { "ReadWrite", "ReadOnly", "Bitmap", "Heap" }; +static const char* shared_region_name[] = { "ReadWrite", "ReadOnly", "Bitmap", "Heap", "Code" }; MapArchiveResult FileMapInfo::map_regions(int regions[], int num_regions, char* mapped_base_address, ReservedSpace rs) { DEBUG_ONLY(FileMapRegion* last_region = nullptr); @@ -1134,7 +1146,7 @@ MapArchiveResult FileMapInfo::map_regions(int regions[], int num_regions, char* assert(r->mapped_base() == last_region->mapped_end(), "must have no gaps"); } last_region = r;) - log_info(cds)("Mapped %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", is_static() ? "static " : "dynamic", + aot_log_info(aot)("Mapped %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", is_static() ? "static " : "dynamic", idx, p2i(r->mapped_base()), p2i(r->mapped_end()), shared_region_name[idx]); @@ -1151,11 +1163,11 @@ MapArchiveResult FileMapInfo::map_regions(int regions[], int num_regions, char* bool FileMapInfo::read_region(int i, char* base, size_t size, bool do_commit) { FileMapRegion* r = region_at(i); if (do_commit) { - log_info(cds)("Commit %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)%s", + aot_log_info(aot)("Commit %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)%s", is_static() ? "static " : "dynamic", i, p2i(base), p2i(base + size), shared_region_name[i], r->allow_exec() ? " exec" : ""); if (!os::commit_memory(base, size, r->allow_exec())) { - log_error(cds)("Failed to commit %s region #%d (%s)", is_static() ? "static " : "dynamic", + aot_log_error(aot)("Failed to commit %s region #%d (%s)", is_static() ? "static " : "dynamic", i, shared_region_name[i]); return false; } @@ -1204,7 +1216,7 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba // 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, + aot_log_info(aot)("Failed to read %s shared space into reserved space at " INTPTR_FORMAT, shared_region_name[i], p2i(requested_addr)); return MAP_ARCHIVE_OTHER_FAILURE; // oom or I/O error. } else { @@ -1218,7 +1230,7 @@ MapArchiveResult FileMapInfo::map_region(int i, intx addr_delta, char* mapped_ba requested_addr, size, r->read_only(), r->allow_exec(), mtClassShared); if (base != requested_addr) { - log_info(cds)("Unable to map %s shared space at " INTPTR_FORMAT, + aot_log_info(aot)("Unable to map %s shared space at " INTPTR_FORMAT, shared_region_name[i], p2i(requested_addr)); _memory_mapping_failed = true; return MAP_ARCHIVE_MMAP_FAILURE; @@ -1253,12 +1265,12 @@ char* FileMapInfo::map_bitmap_region() { char* bitmap_base = map_memory(_fd, _full_path, r->file_offset(), requested_addr, r->used_aligned(), read_only, allow_exec, mtClassShared); if (bitmap_base == nullptr) { - log_info(cds)("failed to map relocation bitmap"); + MetaspaceShared::report_loading_error("failed to map relocation bitmap"); return nullptr; } if (VerifySharedSpaces && !r->check_region_crc(bitmap_base)) { - log_error(cds)("relocation bitmap CRC error"); + aot_log_error(aot)("relocation bitmap CRC error"); if (!os::unmap_memory(bitmap_base, r->used_aligned())) { fatal("os::unmap_memory of relocation bitmap failed"); } @@ -1267,13 +1279,49 @@ char* FileMapInfo::map_bitmap_region() { r->set_mapped_from_file(true); r->set_mapped_base(bitmap_base); - log_info(cds)("Mapped %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", + aot_log_info(aot)("Mapped %s region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", is_static() ? "static " : "dynamic", MetaspaceShared::bm, p2i(r->mapped_base()), p2i(r->mapped_end()), shared_region_name[MetaspaceShared::bm]); return bitmap_base; } +bool FileMapInfo::map_aot_code_region(ReservedSpace rs) { + FileMapRegion* r = region_at(MetaspaceShared::ac); + assert(r->used() > 0 && r->used_aligned() == rs.size(), "must be"); + + char* requested_base = rs.base(); + assert(requested_base != nullptr, "should be inside code cache"); + + char* mapped_base; + if (MetaspaceShared::use_windows_memory_mapping()) { + if (!read_region(MetaspaceShared::ac, requested_base, r->used_aligned(), /* do_commit = */ true)) { + aot_log_info(aot)("Failed to read aot code shared space into reserved space at " INTPTR_FORMAT, + p2i(requested_base)); + return false; + } + mapped_base = requested_base; + } else { + // We do not execute in-place in the AOT code region. + // AOT code is copied to the CodeCache for execution. + bool read_only = false, allow_exec = false; + mapped_base = map_memory(_fd, _full_path, r->file_offset(), + requested_base, r->used_aligned(), read_only, allow_exec, mtClassShared); + } + if (mapped_base == nullptr) { + aot_log_info(aot)("failed to map aot code region"); + return false; + } else { + assert(mapped_base == requested_base, "must be"); + r->set_mapped_from_file(true); + r->set_mapped_base(mapped_base); + aot_log_info(aot)("Mapped static region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", + MetaspaceShared::ac, p2i(r->mapped_base()), p2i(r->mapped_end()), + shared_region_name[MetaspaceShared::ac]); + return true; + } +} + class SharedDataRelocationTask : public ArchiveWorkerTask { private: BitMapView* const _rw_bm; @@ -1303,7 +1351,7 @@ class SharedDataRelocationTask : public ArchiveWorkerTask { // This is called when we cannot map the archive at the requested[ base address (usually 0x800000000). // We relocate all pointers in the 2 core regions (ro, rw). bool FileMapInfo::relocate_pointers_in_core_regions(intx addr_delta) { - log_debug(cds, reloc)("runtime archive relocation start"); + aot_log_debug(aot, reloc)("runtime archive relocation start"); char* bitmap_base = map_bitmap_region(); if (bitmap_base == nullptr) { @@ -1350,7 +1398,7 @@ bool FileMapInfo::relocate_pointers_in_core_regions(intx addr_delta) { // The MetaspaceShared::bm region will be unmapped in MetaspaceShared::initialize_shared_spaces(). - log_debug(cds, reloc)("runtime archive relocation done"); + aot_log_debug(aot, reloc)("runtime archive relocation done"); return true; } } @@ -1399,7 +1447,7 @@ MemRegion FileMapInfo::get_heap_region_requested_range() { address start = heap_region_requested_address(); address end = start + size; - log_info(cds)("Requested heap region [" INTPTR_FORMAT " - " INTPTR_FORMAT "] = %8zu bytes", + aot_log_info(aot)("Requested heap region [" INTPTR_FORMAT " - " INTPTR_FORMAT "] = %8zu bytes", p2i(start), p2i(end), size); return MemRegion((HeapWord*)start, (HeapWord*)end); @@ -1415,9 +1463,9 @@ void FileMapInfo::map_or_load_heap_region() { success = ArchiveHeapLoader::load_heap_region(this); } else { if (!UseCompressedOops && !ArchiveHeapLoader::can_map()) { - log_info(cds)("Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"); + MetaspaceShared::report_loading_error("Cannot use CDS heap data. Selected GC not compatible -XX:-UseCompressedOops"); } else { - log_info(cds)("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required."); + MetaspaceShared::report_loading_error("Cannot use CDS heap data. UseEpsilonGC, UseG1GC, UseSerialGC, UseParallelGC, or UseShenandoahGC are required."); } } } @@ -1429,8 +1477,10 @@ void FileMapInfo::map_or_load_heap_region() { // all AOT-linked classes are visible. // // We get here because the heap is too small. The app will fail anyway. So let's quit. - MetaspaceShared::unrecoverable_loading_error("CDS archive has aot-linked classes but the archived " - "heap objects cannot be loaded. Try increasing your heap size."); + aot_log_error(aot)("%s has aot-linked classes but the archived " + "heap objects cannot be loaded. Try increasing your heap size.", + CDSConfig::type_of_archive_being_loaded()); + MetaspaceShared::unrecoverable_loading_error(); } CDSConfig::stop_using_full_module_graph("archive heap loading failed"); } @@ -1461,19 +1511,19 @@ bool FileMapInfo::can_use_heap_region() { const int archive_narrow_klass_pointer_bits = header()->narrow_klass_pointer_bits(); const int archive_narrow_klass_shift = header()->narrow_klass_shift(); - log_info(cds)("CDS archive was created with max heap size = %zuM, and the following configuration:", + aot_log_info(aot)("CDS archive was created with max heap size = %zuM, and the following configuration:", max_heap_size()/M); - log_info(cds)(" narrow_klass_base at mapping start address, narrow_klass_pointer_bits = %d, narrow_klass_shift = %d", + aot_log_info(aot)(" narrow_klass_base at mapping start address, narrow_klass_pointer_bits = %d, narrow_klass_shift = %d", archive_narrow_klass_pointer_bits, archive_narrow_klass_shift); - log_info(cds)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", + aot_log_info(aot)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift()); - log_info(cds)("The current max heap size = %zuM, G1HeapRegion::GrainBytes = %zu", + aot_log_info(aot)("The current max heap size = %zuM, G1HeapRegion::GrainBytes = %zu", MaxHeapSize/M, G1HeapRegion::GrainBytes); - log_info(cds)(" narrow_klass_base = " PTR_FORMAT ", arrow_klass_pointer_bits = %d, narrow_klass_shift = %d", + aot_log_info(aot)(" narrow_klass_base = " PTR_FORMAT ", arrow_klass_pointer_bits = %d, narrow_klass_shift = %d", p2i(CompressedKlassPointers::base()), CompressedKlassPointers::narrow_klass_pointer_bits(), CompressedKlassPointers::shift()); - log_info(cds)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", + aot_log_info(aot)(" 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 "]", + aot_log_info(aot)(" heap range = [" PTR_FORMAT " - " PTR_FORMAT "]", UseCompressedOops ? p2i(CompressedOops::begin()) : UseG1GC ? p2i((address)G1CollectedHeap::heap()->reserved().start()) : 0L, UseCompressedOops ? p2i(CompressedOops::end()) : @@ -1500,11 +1550,20 @@ bool FileMapInfo::can_use_heap_region() { default: ShouldNotReachHere(); }; - LogTarget(Info, cds) lt; - if (lt.is_enabled()) { - LogStream ls(lt); - ls.print_raw(ss.base()); - header()->print(&ls); + if (CDSConfig::new_aot_flags_used()) { + LogTarget(Info, aot) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print_raw(ss.base()); + header()->print(&ls); + } + } else { + LogTarget(Info, cds) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + ls.print_raw(ss.base()); + header()->print(&ls); + } } assert(false, "%s", ss.base()); } @@ -1591,12 +1650,12 @@ bool FileMapInfo::map_heap_region_impl() { size_t word_size = size / HeapWordSize; address requested_start = heap_region_requested_address(); - log_info(cds)("Preferred address to map heap data (to avoid relocation) is " INTPTR_FORMAT, p2i(requested_start)); + aot_log_info(aot)("Preferred address to map heap data (to avoid relocation) is " INTPTR_FORMAT, p2i(requested_start)); // allocate from java heap HeapWord* start = G1CollectedHeap::heap()->alloc_archive_region(word_size, (HeapWord*)requested_start); if (start == nullptr) { - log_info(cds)("UseSharedSpaces: Unable to allocate java heap region for archive heap."); + MetaspaceShared::report_loading_error("UseSharedSpaces: Unable to allocate java heap region for archive heap."); return false; } @@ -1607,12 +1666,15 @@ bool FileMapInfo::map_heap_region_impl() { char* addr = (char*)_mapped_heap_memregion.start(); char* base; - if (MetaspaceShared::use_windows_memory_mapping()) { + if (MetaspaceShared::use_windows_memory_mapping() || UseLargePages) { + // With UseLargePages, memory mapping may fail on some OSes if the size is not + // large page aligned, so let's use read() instead. In this case, the memory region + // is already commited by G1 so we don't need to commit it again. if (!read_region(MetaspaceShared::hp, addr, align_up(_mapped_heap_memregion.byte_size(), os::vm_page_size()), - /* do_commit = */ true)) { + /* do_commit = */ !UseLargePages)) { dealloc_heap_region(); - log_error(cds)("Failed to read archived heap region into " INTPTR_FORMAT, p2i(addr)); + aot_log_error(aot)("Failed to read archived heap region into " INTPTR_FORMAT, p2i(addr)); return false; } // Checks for VerifySharedSpaces is already done inside read_region() @@ -1620,10 +1682,10 @@ bool FileMapInfo::map_heap_region_impl() { } else { base = map_memory(_fd, _full_path, r->file_offset(), addr, _mapped_heap_memregion.byte_size(), r->read_only(), - r->allow_exec()); + r->allow_exec(), mtJavaHeap); if (base == nullptr || base != addr) { dealloc_heap_region(); - log_info(cds)("UseSharedSpaces: Unable to map at required address in java heap. " + aot_log_info(aot)("UseSharedSpaces: Unable to map at required address in java heap. " INTPTR_FORMAT ", size = %zu bytes", p2i(addr), _mapped_heap_memregion.byte_size()); return false; @@ -1631,7 +1693,7 @@ bool FileMapInfo::map_heap_region_impl() { if (VerifySharedSpaces && !r->check_region_crc(base)) { dealloc_heap_region(); - log_info(cds)("UseSharedSpaces: mapped heap region is corrupt"); + MetaspaceShared::report_loading_error("UseSharedSpaces: mapped heap region is corrupt"); return false; } } @@ -1655,15 +1717,15 @@ bool FileMapInfo::map_heap_region_impl() { if (_heap_pointers_need_patching) { char* bitmap_base = map_bitmap_region(); if (bitmap_base == nullptr) { - log_info(cds)("CDS heap cannot be used because bitmap region cannot be mapped"); + MetaspaceShared::report_loading_error("CDS heap cannot be used because bitmap region cannot be mapped"); dealloc_heap_region(); _heap_pointers_need_patching = false; return false; } } - log_info(cds)("Heap data mapped at " INTPTR_FORMAT ", size = %8zu bytes", + aot_log_info(aot)("Heap data mapped at " INTPTR_FORMAT ", size = %8zu bytes", p2i(mapped_start), _mapped_heap_memregion.byte_size()); - log_info(cds)("CDS heap data relocation delta = %zd bytes", delta); + aot_log_info(aot)("CDS heap data relocation delta = %zd bytes", delta); return true; } @@ -1723,12 +1785,12 @@ void FileMapInfo::unmap_region(int i) { if (mapped_base != nullptr) { if (size > 0 && r->mapped_from_file()) { - log_info(cds)("Unmapping region #%d at base " INTPTR_FORMAT " (%s)", i, p2i(mapped_base), + aot_log_info(aot)("Unmapping region #%d at base " INTPTR_FORMAT " (%s)", i, p2i(mapped_base), shared_region_name[i]); if (r->in_reserved_space()) { // This region was mapped inside a ReservedSpace. Its memory will be freed when the ReservedSpace // is released. Zero it so that we don't accidentally read its content. - log_info(cds)("Region #%d (%s) is in a reserved space, it will be freed when the space is released", i, shared_region_name[i]); + aot_log_info(aot)("Region #%d (%s) is in a reserved space, it will be freed when the space is released", i, shared_region_name[i]); } else { if (!os::unmap_memory(mapped_base, size)) { fatal("os::unmap_memory failed"); @@ -1768,16 +1830,16 @@ bool FileMapInfo::open_as_input() { // are replaced at runtime by JVMTI ClassFileLoadHook. All of those classes are resolved // during the JVMTI "early" stage, so we can still use CDS if // JvmtiExport::has_early_class_hook_env() is false. - log_info(cds)("CDS is disabled because early JVMTI ClassFileLoadHook is in use."); + MetaspaceShared::report_loading_error("CDS is disabled because early JVMTI ClassFileLoadHook is in use."); return false; } if (!open_for_read() || !init_from_file(_fd) || !validate_header()) { if (_is_static) { - log_info(cds)("Loading static archive failed."); + MetaspaceShared::report_loading_error("Loading static archive failed."); return false; } else { - log_info(cds)("Loading dynamic archive failed."); + MetaspaceShared::report_loading_error("Loading dynamic archive failed."); if (AutoCreateSharedArchive) { CDSConfig::enable_dumping_dynamic_archive(_full_path); } @@ -1792,29 +1854,34 @@ bool FileMapInfo::validate_aot_class_linking() { // These checks need to be done after FileMapInfo::initialize(), which gets called before Universe::heap() // is available. if (header()->has_aot_linked_classes()) { + const char* archive_type = CDSConfig::type_of_archive_being_loaded(); CDSConfig::set_has_aot_linked_classes(true); if (JvmtiExport::should_post_class_file_load_hook()) { - log_error(cds)("CDS archive has aot-linked classes. It cannot be used when JVMTI ClassFileLoadHook is in use."); + aot_log_error(aot)("%s has aot-linked classes. It cannot be used when JVMTI ClassFileLoadHook is in use.", + archive_type); return false; } if (JvmtiExport::has_early_vmstart_env()) { - log_error(cds)("CDS archive has aot-linked classes. It cannot be used when JVMTI early vm start is in use."); + aot_log_error(aot)("%s has aot-linked classes. It cannot be used when JVMTI early vm start is in use.", + archive_type); return false; } if (!CDSConfig::is_using_full_module_graph()) { - log_error(cds)("CDS archive has aot-linked classes. It cannot be used when archived full module graph is not used."); + aot_log_error(aot)("%s has aot-linked classes. It cannot be used when archived full module graph is not used.", + archive_type); return false; } const char* prop = Arguments::get_property("java.security.manager"); if (prop != nullptr && strcmp(prop, "disallow") != 0) { - log_error(cds)("CDS archive has aot-linked classes. It cannot be used with -Djava.security.manager=%s.", prop); + aot_log_error(aot)("%s has aot-linked classes. It cannot be used with -Djava.security.manager=%s.", + archive_type, prop); return false; } #if INCLUDE_JVMTI if (Arguments::has_jdwp_agent()) { - log_error(cds)("CDS archive has aot-linked classes. It cannot be used with JDWP agent"); + aot_log_error(aot)("%s has aot-linked classes. It cannot be used with JDWP agent", archive_type); return false; } #endif @@ -1856,29 +1923,87 @@ int FileMapHeader::compute_crc() { bool FileMapHeader::validate() { const char* file_type = CDSConfig::type_of_archive_being_loaded(); if (_obj_alignment != ObjectAlignmentInBytes) { - log_info(cds)("The %s's ObjectAlignmentInBytes of %d" + aot_log_info(aot)("The %s's ObjectAlignmentInBytes of %d" " does not equal the current ObjectAlignmentInBytes of %d.", file_type, _obj_alignment, ObjectAlignmentInBytes); return false; } if (_compact_strings != CompactStrings) { - log_info(cds)("The %s's CompactStrings setting (%s)" + aot_log_info(aot)("The %s's CompactStrings setting (%s)" " does not equal the current CompactStrings setting (%s).", file_type, _compact_strings ? "enabled" : "disabled", CompactStrings ? "enabled" : "disabled"); return false; } + if (TrainingData::have_data()) { + if (_type_profile_level != TypeProfileLevel) { + MetaspaceShared::report_loading_error("The %s's TypeProfileLevel setting (%d)" + " does not equal the current TypeProfileLevel setting (%d).", file_type, + _type_profile_level, TypeProfileLevel); + return false; + } + if (_type_profile_args_limit != TypeProfileArgsLimit) { + MetaspaceShared::report_loading_error("The %s's TypeProfileArgsLimit setting (%d)" + " does not equal the current TypeProfileArgsLimit setting (%d).", file_type, + _type_profile_args_limit, TypeProfileArgsLimit); + return false; + } + if (_type_profile_parms_limit != TypeProfileParmsLimit) { + MetaspaceShared::report_loading_error("The %s's TypeProfileParamsLimit setting (%d)" + " does not equal the current TypeProfileParamsLimit setting (%d).", file_type, + _type_profile_args_limit, TypeProfileArgsLimit); + return false; + + } + if (_type_profile_width != TypeProfileWidth) { + MetaspaceShared::report_loading_error("The %s's TypeProfileWidth setting (%d)" + " does not equal the current TypeProfileWidth setting (%d).", file_type, + (int)_type_profile_width, (int)TypeProfileWidth); + return false; + + } + if (_bci_profile_width != BciProfileWidth) { + MetaspaceShared::report_loading_error("The %s's BciProfileWidth setting (%d)" + " does not equal the current BciProfileWidth setting (%d).", file_type, + (int)_bci_profile_width, (int)BciProfileWidth); + return false; + } + if (_type_profile_casts != TypeProfileCasts) { + MetaspaceShared::report_loading_error("The %s's TypeProfileCasts setting (%s)" + " does not equal the current TypeProfileCasts setting (%s).", file_type, + _type_profile_casts ? "enabled" : "disabled", + TypeProfileCasts ? "enabled" : "disabled"); + + return false; + + } + if (_profile_traps != ProfileTraps) { + MetaspaceShared::report_loading_error("The %s's ProfileTraps setting (%s)" + " does not equal the current ProfileTraps setting (%s).", file_type, + _profile_traps ? "enabled" : "disabled", + ProfileTraps ? "enabled" : "disabled"); + + return false; + } + if (_spec_trap_limit_extra_entries != SpecTrapLimitExtraEntries) { + MetaspaceShared::report_loading_error("The %s's SpecTrapLimitExtraEntries setting (%d)" + " does not equal the current SpecTrapLimitExtraEntries setting (%d).", file_type, + _spec_trap_limit_extra_entries, SpecTrapLimitExtraEntries); + return false; + + } + } // This must be done after header validation because it might change the // header data const char* prop = Arguments::get_property("java.system.class.loader"); if (prop != nullptr) { if (has_aot_linked_classes()) { - log_error(cds)("CDS archive has aot-linked classes. It cannot be used when the " - "java.system.class.loader property is specified."); + aot_log_error(aot)("%s has aot-linked classes. It cannot be used when the " + "java.system.class.loader property is specified.", CDSConfig::type_of_archive_being_loaded()); return false; } - log_warning(cds)("Archived non-system classes are disabled because the " + aot_log_warning(aot)("Archived non-system classes are disabled because the " "java.system.class.loader property is specified (value = \"%s\"). " "To use archived non-system classes, this property must not be set", prop); _has_platform_or_app_classes = false; @@ -1887,7 +2012,7 @@ bool FileMapHeader::validate() { if (!_verify_local && BytecodeVerificationLocal) { // we cannot load boot classes, so there's no point of using the CDS archive - log_info(cds)("The %s's BytecodeVerificationLocal setting (%s)" + aot_log_info(aot)("The %s's BytecodeVerificationLocal setting (%s)" " does not equal the current BytecodeVerificationLocal setting (%s).", file_type, _verify_local ? "enabled" : "disabled", BytecodeVerificationLocal ? "enabled" : "disabled"); @@ -1899,7 +2024,7 @@ bool FileMapHeader::validate() { if (_has_platform_or_app_classes && !_verify_remote // we didn't verify the archived platform/app classes && BytecodeVerificationRemote) { // but we want to verify all loaded platform/app classes - log_info(cds)("The %s was created with less restrictive " + aot_log_info(aot)("The %s was created with less restrictive " "verification setting than the current setting.", file_type); // Pretend that we didn't have any archived platform/app classes, so they won't be loaded // by SystemDictionaryShared. @@ -1911,26 +2036,26 @@ bool FileMapHeader::validate() { // Note: _allow_archiving_with_java_agent is set in the shared archive during dump time // while AllowArchivingWithJavaAgent is set during the current run. if (_allow_archiving_with_java_agent && !AllowArchivingWithJavaAgent) { - log_warning(cds)("The setting of the AllowArchivingWithJavaAgent is different " + aot_log_warning(aot)("The setting of the AllowArchivingWithJavaAgent is different " "from the setting in the %s.", file_type); return false; } if (_allow_archiving_with_java_agent) { - log_warning(cds)("This %s was created with AllowArchivingWithJavaAgent. It should be used " + aot_log_warning(aot)("This %s was created with AllowArchivingWithJavaAgent. It should be used " "for testing purposes only and should not be used in a production environment", file_type); } - log_info(cds)("The %s was created with UseCompressedOops = %d, UseCompressedClassPointers = %d, UseCompactObjectHeaders = %d", + aot_log_info(aot)("The %s was created with UseCompressedOops = %d, UseCompressedClassPointers = %d, UseCompactObjectHeaders = %d", file_type, compressed_oops(), compressed_class_pointers(), compact_headers()); if (compressed_oops() != UseCompressedOops || compressed_class_pointers() != UseCompressedClassPointers) { - log_warning(cds)("Unable to use %s.\nThe saved state of UseCompressedOops and UseCompressedClassPointers is " + aot_log_warning(aot)("Unable to use %s.\nThe saved state of UseCompressedOops and UseCompressedClassPointers is " "different from runtime, CDS will be disabled.", file_type); return false; } if (compact_headers() != UseCompactObjectHeaders) { - log_warning(cds)("Unable to use %s.\nThe %s's UseCompactObjectHeaders setting (%s)" + aot_log_warning(aot)("Unable to use %s.\nThe %s's UseCompactObjectHeaders setting (%s)" " does not equal the current UseCompactObjectHeaders setting (%s).", file_type, file_type, _compact_headers ? "enabled" : "disabled", UseCompactObjectHeaders ? "enabled" : "disabled"); @@ -1939,7 +2064,7 @@ bool FileMapHeader::validate() { if (!_use_optimized_module_handling && !CDSConfig::is_dumping_final_static_archive()) { CDSConfig::stop_using_optimized_module_handling(); - log_info(cds)("optimized module handling: disabled because archive was created without optimized module handling"); + aot_log_info(aot)("optimized module handling: disabled because archive was created without optimized module handling"); } if (is_static()) { @@ -2027,7 +2152,7 @@ ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, Handle cl cfs = cpe->open_stream_for_loader(THREAD, file_name, loader_data); } assert(cfs != nullptr, "must be able to read the classfile data of shared classes for built-in loaders."); - log_debug(cds, jvmti)("classfile data for %s [%d: %s] = %d bytes", class_name, path_index, + log_debug(aot, jvmti)("classfile data for %s [%d: %s] = %d bytes", class_name, path_index, cfs->source(), cfs->length()); return cfs; } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 8793e110948..e0b33fc8245 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -145,6 +145,17 @@ class FileMapHeader: private CDSFileMapHeaderBase { size_t _heap_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the heap. size_t _rw_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the rw region size_t _ro_ptrmap_start_pos; // The first bit in the ptrmap corresponds to this position in the ro region + + // The following are parameters that affect MethodData layout. + uint _type_profile_level; + int _type_profile_args_limit; + int _type_profile_parms_limit; + intx _type_profile_width; + intx _bci_profile_width; + bool _profile_traps; + bool _type_profile_casts; + int _spec_trap_limit_extra_entries; + template T from_mapped_offset(size_t offset) const { return (T)(mapped_base_address() + offset); } @@ -368,6 +379,7 @@ class FileMapInfo : public CHeapObj { MemRegion get_heap_region_requested_range() NOT_CDS_JAVA_HEAP_RETURN_(MemRegion()); bool read_region(int i, char* base, size_t size, bool do_commit); char* map_bitmap_region(); + bool map_aot_code_region(ReservedSpace rs); void unmap_region(int i); void close(); bool is_open() { return _file_open; } diff --git a/src/hotspot/share/cds/finalImageRecipes.cpp b/src/hotspot/share/cds/finalImageRecipes.cpp index f0ce8ceb020..8fc01220a6f 100644 --- a/src/hotspot/share/cds/finalImageRecipes.cpp +++ b/src/hotspot/share/cds/finalImageRecipes.cpp @@ -173,7 +173,7 @@ void FinalImageRecipes::load_all_classes(TRAPS) { Klass* k = _all_klasses->at(i); if (k->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(k); - if (ik->is_shared_unregistered_class()) { + if (ik->defined_by_other_loaders()) { SystemDictionaryShared::init_dumptime_info(ik); SystemDictionaryShared::add_unregistered_class(THREAD, ik); SystemDictionaryShared::copy_unregistered_class_size_and_crc32(ik); @@ -181,9 +181,9 @@ void FinalImageRecipes::load_all_classes(TRAPS) { Klass* actual = SystemDictionary::resolve_or_fail(ik->name(), class_loader, true, CHECK); if (actual != ik) { ResourceMark rm(THREAD); - log_error(cds)("Unable to resolve class from CDS archive: %s", ik->external_name()); - log_error(cds)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual)); - log_error(cds)("Please check if your VM command-line is the same as in the training run"); + log_error(aot)("Unable to resolve class from CDS archive: %s", ik->external_name()); + log_error(aot)("Expected: " INTPTR_FORMAT ", actual: " INTPTR_FORMAT, p2i(ik), p2i(actual)); + log_error(aot)("Please check if your VM command-line is the same as in the training run"); MetaspaceShared::unrecoverable_writing_error(); } assert(ik->is_loaded(), "must be"); @@ -205,10 +205,10 @@ void FinalImageRecipes::apply_recipes(TRAPS) { if (_final_image_recipes != nullptr) { _final_image_recipes->apply_recipes_impl(THREAD); if (HAS_PENDING_EXCEPTION) { - log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), + log_error(aot)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); - log_error(cds)("Please check if your VM command-line is the same as in the training run"); - MetaspaceShared::unrecoverable_writing_error("Unexpected exception, use -Xlog:cds,exceptions=trace for detail"); + log_error(aot)("Please check if your VM command-line is the same as in the training run"); + MetaspaceShared::unrecoverable_writing_error("Unexpected exception, use -Xlog:aot,exceptions=trace for detail"); } } diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index ce98b2b93b7..06cbaf1dbe7 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -25,6 +25,8 @@ #include "cds/aotArtifactFinder.hpp" #include "cds/aotClassInitializer.hpp" #include "cds/aotClassLocation.hpp" +#include "cds/aotLogging.hpp" +#include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/archiveHeapWriter.hpp" @@ -173,9 +175,9 @@ static void reset_states(oop obj, TRAPS) { Method* method = klass->find_method(method_name, method_sig); if (method != nullptr) { assert(method->is_private(), "must be"); - if (log_is_enabled(Debug, cds)) { + if (log_is_enabled(Debug, aot)) { ResourceMark rm(THREAD); - log_debug(cds)(" calling %s", method->name_and_sig_as_C_string()); + log_debug(aot)(" calling %s", method->name_and_sig_as_C_string()); } JavaValue result(T_VOID); JavaCalls::call_special(&result, h_obj, klass, @@ -187,9 +189,9 @@ static void reset_states(oop obj, TRAPS) { void HeapShared::reset_archived_object_states(TRAPS) { assert(CDSConfig::is_dumping_heap(), "dump-time only"); - log_debug(cds)("Resetting platform loader"); + log_debug(aot)("Resetting platform loader"); reset_states(SystemDictionary::java_platform_loader(), CHECK); - log_debug(cds)("Resetting system loader"); + log_debug(aot)("Resetting system loader"); reset_states(SystemDictionary::java_system_loader(), CHECK); // Clean up jdk.internal.loader.ClassLoaders::bootLoader(), which is not @@ -199,7 +201,7 @@ void HeapShared::reset_archived_object_states(TRAPS) { // Note, this object is non-null, and is not the same as // ClassLoaderData::the_null_class_loader_data()->class_loader(), // which is null. - log_debug(cds)("Resetting boot loader"); + log_debug(aot)("Resetting boot loader"); JavaValue result(T_OBJECT); JavaCalls::call_static(&result, vmClasses::jdk_internal_loader_ClassLoaders_klass(), @@ -276,9 +278,9 @@ void HeapShared::clear_root(int index) { if (ArchiveHeapLoader::is_in_use()) { int seg_idx, int_idx; get_segment_indexes(index, seg_idx, int_idx); - if (log_is_enabled(Debug, cds, heap)) { + if (log_is_enabled(Debug, aot, heap)) { oop old = root_segment(seg_idx)->obj_at(int_idx); - log_debug(cds, heap)("Clearing root %d: was " PTR_FORMAT, index, p2i(old)); + log_debug(aot, heap)("Clearing root %d: was " PTR_FORMAT, index, p2i(old)); } root_segment(seg_idx)->obj_at_put(int_idx, nullptr); } @@ -293,7 +295,7 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra } if (ArchiveHeapWriter::is_too_large_to_archive(obj->size())) { - log_debug(cds, heap)("Cannot archive, object (" PTR_FORMAT ") is too large: %zu", + log_debug(aot, heap)("Cannot archive, object (" PTR_FORMAT ") is too large: %zu", p2i(obj), obj->size()); debug_trace(); return false; @@ -341,9 +343,9 @@ bool HeapShared::archive_object(oop obj, oop referrer, KlassSubGraphInfo* subgra } } - if (log_is_enabled(Debug, cds, heap)) { + if (log_is_enabled(Debug, aot, heap)) { ResourceMark rm; - LogTarget(Debug, cds, heap) log; + LogTarget(Debug, aot, heap) log; LogStream out(log); out.print("Archived heap object " PTR_FORMAT " : %s ", p2i(obj), obj->klass()->external_name()); @@ -568,9 +570,9 @@ void HeapShared::copy_and_rescan_aot_inited_mirror(InstanceKlass* ik) { assert(success, "sanity"); } - if (log_is_enabled(Debug, cds, init)) { + if (log_is_enabled(Debug, aot, init)) { ResourceMark rm; - log_debug(cds, init)("copied %3d field(s) in aot-initialized mirror %s%s%s", nfields, ik->external_name(), + log_debug(aot, init)("copied %3d field(s) in aot-initialized mirror %s%s%s", nfields, ik->external_name(), ik->is_hidden() ? " (hidden)" : "", ik->is_enum_subclass() ? " (enum)" : ""); } @@ -605,11 +607,8 @@ static objArrayOop get_archived_resolved_references(InstanceKlass* src_ik) { } void HeapShared::archive_strings() { - oop shared_strings_array = StringTable::init_shared_strings_array(_dumped_interned_strings); + oop shared_strings_array = StringTable::init_shared_strings_array(); bool success = archive_reachable_objects_from(1, _dump_time_special_subgraph, shared_strings_array); - // We must succeed because: - // - _dumped_interned_strings do not contain any large strings. - // - StringTable::init_shared_table() doesn't create any large arrays. assert(success, "shared strings array must not point to arrays or strings that are too large to archive"); StringTable::set_shared_strings_array_index(append_root(shared_strings_array)); } @@ -656,7 +655,7 @@ void HeapShared::start_scanning_for_oops() { create_archived_object_cache(); if (UseCompressedOops || UseG1GC) { - log_info(cds)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]", + aot_log_info(aot)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]", UseCompressedOops ? p2i(CompressedOops::begin()) : p2i((address)G1CollectedHeap::heap()->reserved().start()), UseCompressedOops ? p2i(CompressedOops::end()) : @@ -682,7 +681,7 @@ void HeapShared::write_heap(ArchiveHeapInfo *heap_info) { check_special_subgraph_classes(); } - StringTable::write_shared_table(_dumped_interned_strings); + StringTable::write_shared_table(); ArchiveHeapWriter::write(_pending_roots, heap_info); ArchiveBuilder::OtherROAllocMark mark; @@ -709,8 +708,6 @@ void HeapShared::scan_java_class(Klass* orig_k) { bool success = HeapShared::archive_reachable_objects_from(1, _dump_time_special_subgraph, rr); assert(success, "must be"); } - - orig_ik->constants()->add_dumped_interned_strings(); } } @@ -806,7 +803,7 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) { } else if (orig_k->is_objArray_klass()) { Klass* abk = ObjArrayKlass::cast(orig_k)->bottom_klass(); if (abk->is_instance_klass()) { - assert(InstanceKlass::cast(abk)->is_shared_boot_class(), + assert(InstanceKlass::cast(abk)->defined_by_boot_loader(), "must be boot class"); check_allowed_klass(InstanceKlass::cast(ObjArrayKlass::cast(orig_k)->bottom_klass())); } @@ -821,10 +818,10 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) { return; } - if (log_is_enabled(Debug, cds, heap)) { + if (log_is_enabled(Debug, aot, heap)) { if (!_subgraph_object_klasses->contains(orig_k)) { ResourceMark rm; - log_debug(cds, heap)("Adding klass %s", orig_k->external_name()); + log_debug(aot, heap)("Adding klass %s", orig_k->external_name()); } } @@ -867,7 +864,7 @@ void KlassSubGraphInfo::check_allowed_klass(InstanceKlass* ik) { #endif ResourceMark rm; - log_error(cds, heap)("Class %s not allowed in archive heap. Must be in java.base%s%s", + log_error(aot, heap)("Class %s not allowed in archive heap. Must be in java.base%s%s", ik->external_name(), lambda_msg, testcls_msg); MetaspaceShared::unrecoverable_writing_error(); } @@ -879,7 +876,7 @@ bool KlassSubGraphInfo::is_non_early_klass(Klass* k) { if (k->is_instance_klass()) { if (!SystemDictionaryShared::is_early_klass(InstanceKlass::cast(k))) { ResourceMark rm; - log_info(cds, heap)("non-early: %s", k->external_name()); + log_info(aot, heap)("non-early: %s", k->external_name()); return true; } else { return false; @@ -907,7 +904,7 @@ void ArchivedKlassSubGraphInfoRecord::init(KlassSubGraphInfo* info) { if (_has_non_early_klasses) { ResourceMark rm; - log_info(cds, heap)( + log_info(aot, heap)( "Subgraph of klass %s has non-early klasses and cannot be used when JVMTI ClassFileLoadHook is enabled", _k->external_name()); } @@ -946,13 +943,13 @@ void ArchivedKlassSubGraphInfoRecord::init(KlassSubGraphInfo* info) { if (subgraph_k->has_aot_initialized_mirror()) { continue; } - if (log_is_enabled(Info, cds, heap)) { + if (log_is_enabled(Info, aot, heap)) { ResourceMark rm; const char* owner_name = is_special ? "" : _k->external_name(); if (subgraph_k->is_instance_klass()) { InstanceKlass* src_ik = InstanceKlass::cast(ArchiveBuilder::current()->get_source_addr(subgraph_k)); } - log_info(cds, heap)( + log_info(aot, heap)( "Archived object klass %s (%2d) => %s", owner_name, n, subgraph_k->external_name()); } @@ -1021,7 +1018,7 @@ void HeapShared::write_subgraph_info_table() { _archived_ArchiveHeapTestClass = array; } #endif - if (log_is_enabled(Info, cds, heap)) { + if (log_is_enabled(Info, aot, heap)) { print_stats(); } } @@ -1056,7 +1053,7 @@ void HeapShared::serialize_tables(SerializeClosure* soc) { static void verify_the_heap(Klass* k, const char* which) { if (VerifyArchivedFields > 0) { ResourceMark rm; - log_info(cds, heap)("Verify heap %s initializing static field(s) in %s", + log_info(aot, heap)("Verify heap %s initializing static field(s) in %s", which, k->external_name()); VM_Verify verify_op; @@ -1070,7 +1067,7 @@ static void verify_the_heap(Klass* k, const char* which) { // // -XX:VerifyArchivedFields=2 force a GC to happen in such an early stage // to check for GC safety. - log_info(cds, heap)("Trigger GC %s initializing static field(s) in %s", + log_info(aot, heap)("Trigger GC %s initializing static field(s) in %s", which, k->external_name()); FlagSetting fs1(VerifyBeforeGC, true); FlagSetting fs2(VerifyDuringGC, true); @@ -1100,7 +1097,7 @@ void HeapShared::resolve_classes_for_subgraphs(JavaThread* current, ArchivableSt ArchivableStaticFieldInfo* info = &fields[i]; TempNewSymbol klass_name = SymbolTable::new_symbol(info->klass_name); InstanceKlass* k = SystemDictionaryShared::find_builtin_class(klass_name); - assert(k != nullptr && k->is_shared_boot_class(), "sanity"); + assert(k != nullptr && k->defined_by_boot_loader(), "sanity"); resolve_classes_for_subgraph_of(current, k); } } @@ -1189,7 +1186,7 @@ void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k AOTClassLocationConfig::runtime()->num_module_paths() > 0) { // ArchivedModuleGraph was created with a --module-path that's different than the runtime --module-path. // Thus, it might contain references to modules that do not exist at runtime. We cannot use it. - log_info(cds, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_optimized_module_handling=%s num_module_paths=%d", + log_info(aot, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_optimized_module_handling=%s num_module_paths=%d", BOOL_TO_STR(CDSConfig::is_using_optimized_module_handling()), AOTClassLocationConfig::runtime()->num_module_paths()); return; @@ -1232,34 +1229,34 @@ HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAP // Initialize from archived data. Currently this is done only // during VM initialization time. No lock is needed. if (record == nullptr) { - if (log_is_enabled(Info, cds, heap)) { + if (log_is_enabled(Info, aot, heap)) { ResourceMark rm(THREAD); - log_info(cds, heap)("subgraph %s is not recorded", + log_info(aot, heap)("subgraph %s is not recorded", k->external_name()); } return nullptr; } else { if (record->is_full_module_graph() && !CDSConfig::is_using_full_module_graph()) { - if (log_is_enabled(Info, cds, heap)) { + if (log_is_enabled(Info, aot, heap)) { ResourceMark rm(THREAD); - log_info(cds, heap)("subgraph %s cannot be used because full module graph is disabled", + log_info(aot, heap)("subgraph %s cannot be used because full module graph is disabled", k->external_name()); } return nullptr; } if (record->has_non_early_klasses() && JvmtiExport::should_post_class_file_load_hook()) { - if (log_is_enabled(Info, cds, heap)) { + if (log_is_enabled(Info, aot, heap)) { ResourceMark rm(THREAD); - log_info(cds, heap)("subgraph %s cannot be used because JVMTI ClassFileLoadHook is enabled", + log_info(aot, heap)("subgraph %s cannot be used because JVMTI ClassFileLoadHook is enabled", k->external_name()); } return nullptr; } - if (log_is_enabled(Info, cds, heap)) { + if (log_is_enabled(Info, aot, heap)) { ResourceMark rm; - log_info(cds, heap)("%s subgraph %s ", do_init ? "init" : "resolve", k->external_name()); + log_info(aot, heap)("%s subgraph %s ", do_init ? "init" : "resolve", k->external_name()); } resolve_or_init(k, do_init, CHECK_NULL); @@ -1287,7 +1284,7 @@ void HeapShared::resolve_or_init(const char* klass_name, bool do_init, TRAPS) { if (k == nullptr) { return; } - assert(k->is_shared_boot_class(), "sanity"); + assert(k->defined_by_boot_loader(), "sanity"); resolve_or_init(k, false, CHECK); if (do_init) { resolve_or_init(k, true, CHECK); @@ -1331,14 +1328,14 @@ void HeapShared::init_archived_fields_for(Klass* k, const ArchivedKlassSubGraphI } else { m->obj_field_put(field_offset, v); } - log_debug(cds, heap)(" " PTR_FORMAT " init field @ %2d = " PTR_FORMAT, p2i(k), field_offset, p2i(v)); + log_debug(aot, heap)(" " PTR_FORMAT " init field @ %2d = " PTR_FORMAT, p2i(k), field_offset, p2i(v)); } // Done. Java code can see the archived sub-graphs referenced from k's // mirror after this point. - if (log_is_enabled(Info, cds, heap)) { + if (log_is_enabled(Info, aot, heap)) { ResourceMark rm; - log_info(cds, heap)("initialize_from_archived_subgraph %s " PTR_FORMAT "%s%s", + log_info(aot, heap)("initialize_from_archived_subgraph %s " PTR_FORMAT "%s%s", k->external_name(), p2i(k), JvmtiExport::is_early_phase() ? " (early)" : "", k->has_aot_initialized_mirror() ? " (aot-inited)" : ""); } @@ -1363,34 +1360,37 @@ void HeapShared::clear_archived_roots_of(Klass* k) { } } -// Push all oops that are referenced by _referencing_obj onto the _stack. -class HeapShared::ReferentPusher: public BasicOopIterateClosure { +// Push all oop fields (or oop array elemenets in case of an objArray) in +// _referencing_obj onto the _stack. +class HeapShared::OopFieldPusher: public BasicOopIterateClosure { PendingOopStack* _stack; GrowableArray _found_oop_fields; int _level; bool _record_klasses_only; KlassSubGraphInfo* _subgraph_info; oop _referencing_obj; + bool _is_java_lang_ref; public: - ReferentPusher(PendingOopStack* stack, - int level, - bool record_klasses_only, - KlassSubGraphInfo* subgraph_info, - oop orig) : + OopFieldPusher(PendingOopStack* stack, + int level, + bool record_klasses_only, + KlassSubGraphInfo* subgraph_info, + oop orig) : _stack(stack), _found_oop_fields(), _level(level), _record_klasses_only(record_klasses_only), _subgraph_info(subgraph_info), _referencing_obj(orig) { + _is_java_lang_ref = AOTReferenceObjSupport::check_if_ref_obj(orig); } - void do_oop(narrowOop *p) { ReferentPusher::do_oop_work(p); } - void do_oop( oop *p) { ReferentPusher::do_oop_work(p); } + void do_oop(narrowOop *p) { OopFieldPusher::do_oop_work(p); } + void do_oop( oop *p) { OopFieldPusher::do_oop_work(p); } - ~ReferentPusher() { + ~OopFieldPusher() { while (_found_oop_fields.length() > 0) { // This produces the exact same traversal order as the previous version - // of ReferentPusher that recurses on the C stack -- a depth-first search, + // of OopFieldPusher that recurses on the C stack -- a depth-first search, // walking the oop fields in _referencing_obj by ascending field offsets. oop obj = _found_oop_fields.pop(); _stack->push(PendingOop(obj, _referencing_obj, _level + 1)); @@ -1399,17 +1399,21 @@ class HeapShared::ReferentPusher: public BasicOopIterateClosure { protected: template void do_oop_work(T *p) { - oop obj = RawAccess<>::oop_load(p); + int field_offset = pointer_delta_as_int((char*)p, cast_from_oop(_referencing_obj)); + oop obj = HeapAccess::oop_load_at(_referencing_obj, field_offset); if (!CompressedOops::is_null(obj)) { - size_t field_delta = pointer_delta(p, _referencing_obj, sizeof(char)); + if (_is_java_lang_ref && AOTReferenceObjSupport::skip_field(field_offset)) { + // Do not follow these fields. They will be cleared to null. + return; + } - if (!_record_klasses_only && log_is_enabled(Debug, cds, heap)) { + if (!_record_klasses_only && log_is_enabled(Debug, aot, heap)) { ResourceMark rm; - log_debug(cds, heap)("(%d) %s[%zu] ==> " PTR_FORMAT " size %zu %s", _level, - _referencing_obj->klass()->external_name(), field_delta, + log_debug(aot, heap)("(%d) %s[%d] ==> " PTR_FORMAT " size %zu %s", _level, + _referencing_obj->klass()->external_name(), field_offset, p2i(obj), obj->size() * HeapWordSize, obj->klass()->external_name()); - if (log_is_enabled(Trace, cds, heap)) { - LogTarget(Trace, cds, heap) log; + if (log_is_enabled(Trace, aot, heap)) { + LogTarget(Trace, aot, heap) log; LogStream out(log); obj->print_on(&out); } @@ -1496,14 +1500,14 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap // If you get an error here, you probably made a change in the JDK library that has added // these objects that are referenced (directly or indirectly) by static fields. ResourceMark rm; - log_error(cds, heap)("Cannot archive object " PTR_FORMAT " of class %s", p2i(orig_obj), orig_obj->klass()->external_name()); + log_error(aot, heap)("Cannot archive object " PTR_FORMAT " of class %s", p2i(orig_obj), orig_obj->klass()->external_name()); debug_trace(); MetaspaceShared::unrecoverable_writing_error(); } - if (log_is_enabled(Debug, cds, heap) && java_lang_Class::is_instance(orig_obj)) { + if (log_is_enabled(Debug, aot, heap) && java_lang_Class::is_instance(orig_obj)) { ResourceMark rm; - LogTarget(Debug, cds, heap) log; + LogTarget(Debug, aot, heap) log; LogStream out(log); out.print("Found java mirror " PTR_FORMAT " ", p2i(orig_obj)); Klass* k = java_lang_Class::as_Klass(orig_obj); @@ -1542,7 +1546,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap // If you get an error here, you probably made a change in the JDK library that has added a Class // object that is referenced (directly or indirectly) by an ArchivableStaticFieldInfo // defined at the top of this file. - log_error(cds, heap)("(%d) Unknown java.lang.Class object is in the archived sub-graph", level); + log_error(aot, heap)("(%d) Unknown java.lang.Class object is in the archived sub-graph", level); debug_trace(); MetaspaceShared::unrecoverable_writing_error(); } @@ -1562,7 +1566,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap if (!archive_object(orig_obj, referrer, subgraph_info)) { // Skip archiving the sub-graph referenced from the current entry field. ResourceMark rm; - log_error(cds, heap)( + log_error(aot, heap)( "Cannot archive the sub-graph referenced from %s object (" PTR_FORMAT ") size %zu, skipped.", orig_obj->klass()->external_name(), p2i(orig_obj), orig_obj->size() * HeapWordSize); @@ -1586,7 +1590,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap // Find all the oops that are referenced by orig_obj, push them onto the stack // so we can work on them next. ResourceMark rm; - ReferentPusher pusher(stack, level, record_klasses_only, subgraph_info, orig_obj); + OopFieldPusher pusher(stack, level, record_klasses_only, subgraph_info, orig_obj); orig_obj->oop_iterate(&pusher); } @@ -1613,7 +1617,7 @@ bool HeapShared::walk_one_object(PendingOopStack* stack, int level, KlassSubGrap // - No java.lang.Class instance (java mirror) can be included inside // an archived sub-graph. Mirror can only be the sub-graph entry object. // -// The Java heap object sub-graph archiving process (see ReferentPusher): +// The Java heap object sub-graph archiving process (see OopFieldPusher): // // 1) Java object sub-graph archiving starts from a given static field // within a Class instance (java mirror). If the static field is a @@ -1640,32 +1644,32 @@ void HeapShared::archive_reachable_objects_from_static_field(InstanceKlass *k, int field_offset, const char* field_name) { assert(CDSConfig::is_dumping_heap(), "dump time only"); - assert(k->is_shared_boot_class(), "must be boot class"); + assert(k->defined_by_boot_loader(), "must be boot class"); oop m = k->java_mirror(); KlassSubGraphInfo* subgraph_info = get_subgraph_info(k); oop f = m->obj_field(field_offset); - log_debug(cds, heap)("Start archiving from: %s::%s (" PTR_FORMAT ")", klass_name, field_name, p2i(f)); + log_debug(aot, heap)("Start archiving from: %s::%s (" PTR_FORMAT ")", klass_name, field_name, p2i(f)); if (!CompressedOops::is_null(f)) { - if (log_is_enabled(Trace, cds, heap)) { - LogTarget(Trace, cds, heap) log; + if (log_is_enabled(Trace, aot, heap)) { + LogTarget(Trace, aot, heap) log; LogStream out(log); f->print_on(&out); } bool success = archive_reachable_objects_from(1, subgraph_info, f); if (!success) { - log_error(cds, heap)("Archiving failed %s::%s (some reachable objects cannot be archived)", + log_error(aot, heap)("Archiving failed %s::%s (some reachable objects cannot be archived)", klass_name, field_name); } else { // Note: the field value is not preserved in the archived mirror. // Record the field as a new subGraph entry point. The recorded // information is restored from the archive at runtime. subgraph_info->add_subgraph_entry_field(field_offset, f); - log_info(cds, heap)("Archived field %s::%s => " PTR_FORMAT, klass_name, field_name, p2i(f)); + log_info(aot, heap)("Archived field %s::%s => " PTR_FORMAT, klass_name, field_name, p2i(f)); } } else { // The field contains null, we still need to record the entry point, @@ -1691,7 +1695,7 @@ class VerifySharedOopClosure: public BasicOopIterateClosure { void HeapShared::verify_subgraph_from_static_field(InstanceKlass* k, int field_offset) { assert(CDSConfig::is_dumping_heap(), "dump time only"); - assert(k->is_shared_boot_class(), "must be boot class"); + assert(k->defined_by_boot_loader(), "must be boot class"); oop m = k->java_mirror(); oop f = m->obj_field(field_offset); @@ -1784,7 +1788,7 @@ void HeapShared::set_has_been_seen_during_subgraph_recording(oop obj) { } void HeapShared::start_recording_subgraph(InstanceKlass *k, const char* class_name, bool is_full_module_graph) { - log_info(cds, heap)("Start recording subgraph(s) for archived fields in %s", class_name); + log_info(aot, heap)("Start recording subgraph(s) for archived fields in %s", class_name); init_subgraph_info(k, is_full_module_graph); init_seen_objects_table(); _num_new_walked_objs = 0; @@ -1795,7 +1799,7 @@ void HeapShared::start_recording_subgraph(InstanceKlass *k, const char* class_na void HeapShared::done_recording_subgraph(InstanceKlass *k, const char* class_name) { int num_new_recorded_klasses = get_subgraph_info(k)->num_subgraph_object_klasses() - _num_old_recorded_klasses; - log_info(cds, heap)("Done recording subgraph(s) for archived fields in %s: " + log_info(aot, heap)("Done recording subgraph(s) for archived fields in %s: " "walked %d objs, archived %d new objs, recorded %d classes", class_name, _num_new_walked_objs, _num_new_archived_objs, num_new_recorded_klasses); @@ -1847,7 +1851,7 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], #endif if (is_test_class) { - log_warning(cds)("Loading ArchiveHeapTestClass %s ...", test_class_name); + log_warning(aot)("Loading ArchiveHeapTestClass %s ...", test_class_name); } Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, THREAD); @@ -1865,7 +1869,7 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], } InstanceKlass* ik = InstanceKlass::cast(k); - assert(InstanceKlass::cast(ik)->is_shared_boot_class(), + assert(InstanceKlass::cast(ik)->defined_by_boot_loader(), "Only support boot classes"); if (is_test_class) { @@ -1895,7 +1899,7 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], } if (is_test_class) { - log_warning(cds)("Initializing ArchiveHeapTestClass %s ...", test_class_name); + log_warning(aot)("Initializing ArchiveHeapTestClass %s ...", test_class_name); } ik->initialize(CHECK); @@ -2044,26 +2048,23 @@ void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[], done_recording_subgraph(info->klass, klass_name); } - log_info(cds, heap)("Archived subgraph records = %d", + log_info(aot, heap)("Archived subgraph records = %d", _num_total_subgraph_recordings); - log_info(cds, heap)(" Walked %d objects", _num_total_walked_objs); - log_info(cds, heap)(" Archived %d objects", _num_total_archived_objs); - log_info(cds, heap)(" Recorded %d klasses", _num_total_recorded_klasses); + log_info(aot, heap)(" Walked %d objects", _num_total_walked_objs); + log_info(aot, heap)(" Archived %d objects", _num_total_archived_objs); + log_info(aot, heap)(" Recorded %d klasses", _num_total_recorded_klasses); #ifndef PRODUCT for (int i = 0; fields[i].valid(); i++) { ArchivableStaticFieldInfo* f = &fields[i]; verify_subgraph_from_static_field(f->klass, f->offset); } - log_info(cds, heap)(" Verified %d references", _num_total_verifications); + log_info(aot, heap)(" Verified %d references", _num_total_verifications); #endif } -// Not all the strings in the global StringTable are dumped into the archive, because -// some of those strings may be only referenced by classes that are excluded from -// the archive. We need to explicitly mark the strings that are: -// [1] used by classes that WILL be archived; -// [2] included in the SharedArchiveConfigFile. +// Keep track of the contents of the archived interned string table. This table +// is used only by CDSHeapVerifier. void HeapShared::add_to_dumped_interned_strings(oop string) { assert_at_safepoint(); // DumpedInternedStrings uses raw oops assert(!ArchiveHeapWriter::is_string_too_large_to_archive(string), "must be"); @@ -2085,7 +2086,7 @@ void HeapShared::debug_trace() { ResourceMark rm; oop referrer = _object_being_archived.referrer(); if (referrer != nullptr) { - LogStream ls(Log(cds, heap)::error()); + LogStream ls(Log(aot, heap)::error()); ls.print_cr("Reference trace"); CDSHeapVerifier::trace_to_root(&ls, referrer); } @@ -2158,18 +2159,18 @@ void HeapShared::print_stats() { size_t byte_size_limit = (size_t(1) << i) * HeapWordSize; size_t count = _alloc_count[i]; size_t size = _alloc_size[i]; - log_info(cds, heap)("%8zu objects are <= %-6zu" + log_info(aot, heap)("%8zu objects are <= %-6zu" " bytes (total %8zu bytes, avg %8.1f bytes)", count, byte_size_limit, size * HeapWordSize, avg_size(size, count)); huge_count -= count; huge_size -= size; } - log_info(cds, heap)("%8zu huge objects (total %8zu bytes" + log_info(aot, heap)("%8zu huge objects (total %8zu bytes" ", avg %8.1f bytes)", huge_count, huge_size * HeapWordSize, avg_size(huge_size, huge_count)); - log_info(cds, heap)("%8zu total objects (total %8zu bytes" + log_info(aot, heap)("%8zu total objects (total %8zu bytes" ", avg %8.1f bytes)", _total_obj_count, _total_obj_size * HeapWordSize, avg_size(_total_obj_size, _total_obj_count)); diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 04c9ae91381..f4e86aa5895 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -164,8 +164,8 @@ class HeapShared: AllStatic { static void count_allocation(size_t size); static void print_stats(); - static void debug_trace(); public: + static void debug_trace(); static unsigned oop_hash(oop const& p); static unsigned string_oop_hash(oop const& string) { return java_lang_String::hash_code(string); @@ -357,7 +357,7 @@ class HeapShared: AllStatic { int level() const { return _level; } }; - class ReferentPusher; + class OopFieldPusher; using PendingOopStack = GrowableArrayCHeap; static PendingOop _object_being_archived; diff --git a/src/hotspot/share/cds/lambdaFormInvokers.cpp b/src/hotspot/share/cds/lambdaFormInvokers.cpp index 7832de8c6cc..d6a51c87513 100644 --- a/src/hotspot/share/cds/lambdaFormInvokers.cpp +++ b/src/hotspot/share/cds/lambdaFormInvokers.cpp @@ -83,10 +83,10 @@ void LambdaFormInvokers::append(char* line) { class PrintLambdaFormMessage { public: PrintLambdaFormMessage() { - log_info(cds)("Regenerate MethodHandle Holder classes..."); + log_info(aot)("Regenerate MethodHandle Holder classes..."); } ~PrintLambdaFormMessage() { - log_info(cds)("Regenerate MethodHandle Holder classes...done"); + log_info(aot)("Regenerate MethodHandle Holder classes...done"); } }; @@ -114,7 +114,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { PrintLambdaFormMessage plm; if (_lambdaform_lines == nullptr || _lambdaform_lines->length() == 0) { - log_info(cds)("Nothing to regenerate for holder classes"); + log_info(aot)("Nothing to regenerate for holder classes"); return; } @@ -150,12 +150,12 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { if (HAS_PENDING_EXCEPTION) { if (!PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) { - log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), + log_error(aot)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); if (CDSConfig::is_dumping_static_archive()) { - log_error(cds)("Failed to generate LambdaForm holder classes. Is your classlist out of date?"); + log_error(aot)("Failed to generate LambdaForm holder classes. Is your classlist out of date?"); } else { - log_error(cds)("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?"); + log_error(aot)("Failed to generate LambdaForm holder classes. Was the base archive generated with an outdated classlist?"); } CLEAR_PENDING_EXCEPTION; } @@ -226,7 +226,7 @@ void LambdaFormInvokers::regenerate_class(char* class_name, ClassFileStream& st, if (!klass->is_shared()) { SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); // exclude the existing class from dump } - log_info(cds, lambda)("Regenerated class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT, + log_info(aot, lambda)("Regenerated class %s, old: " INTPTR_FORMAT " new: " INTPTR_FORMAT, class_name, p2i(klass), p2i(result)); } @@ -256,7 +256,7 @@ void LambdaFormInvokers::dump_static_archive_invokers() { } assert(index == count, "Should match"); } - log_debug(cds)("Total LF lines stored into %s: %d", CDSConfig::type_of_archive_being_written(), count); + log_debug(aot)("Total LF lines stored into %s: %d", CDSConfig::type_of_archive_being_written(), count); } } @@ -268,7 +268,7 @@ void LambdaFormInvokers::read_static_archive_invokers() { char* str = line->adr_at(0); append(str); } - log_debug(cds)("Total LF lines read from %s: %d", CDSConfig::type_of_archive_being_loaded(), _static_archive_invokers->length()); + log_debug(aot)("Total LF lines read from %s: %d", CDSConfig::type_of_archive_being_loaded(), _static_archive_invokers->length()); } } diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index 6b2e432d559..a812af18ba7 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -99,7 +99,7 @@ void LambdaProxyClassDictionary::dumptime_init() { } bool LambdaProxyClassDictionary::is_supported_invokedynamic(BootstrapInfo* bsi) { - LogTarget(Debug, cds, lambda) log; + LogTarget(Debug, aot, lambda) log; if (bsi->arg_values() == nullptr || !bsi->arg_values()->is_objArray()) { if (log.is_enabled()) { LogStream log_stream(log); @@ -170,7 +170,6 @@ void LambdaProxyClassDictionary::add_lambda_proxy_class(InstanceKlass* caller_ik MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); - lambda_ik->assign_class_loader_type(); lambda_ik->set_shared_classpath_index(caller_ik->shared_classpath_index()); InstanceKlass* nest_host = caller_ik->nest_host(CHECK); assert(nest_host != nullptr, "unexpected nullptr nest_host"); @@ -268,9 +267,9 @@ InstanceKlass* LambdaProxyClassDictionary::find_lambda_proxy_class(InstanceKlass const RunTimeLambdaProxyClassInfo* info = _runtime_static_table.lookup(&key, hash, 0); InstanceKlass* proxy_klass = find_lambda_proxy_class(info); if (proxy_klass == nullptr) { - if (info != nullptr && log_is_enabled(Debug, cds)) { + if (info != nullptr && log_is_enabled(Debug, aot)) { ResourceMark rm; - log_debug(cds)("Used all static archived lambda proxy classes for: %s %s%s", + log_debug(aot)("Used all static archived lambda proxy classes for: %s %s%s", caller_ik->external_name(), invoked_name->as_C_string(), invoked_type->as_C_string()); } } else { @@ -281,9 +280,9 @@ InstanceKlass* LambdaProxyClassDictionary::find_lambda_proxy_class(InstanceKlass info = _runtime_dynamic_table.lookup(&key, hash, 0); proxy_klass = find_lambda_proxy_class(info); if (proxy_klass == nullptr) { - if (info != nullptr && log_is_enabled(Debug, cds)) { + if (info != nullptr && log_is_enabled(Debug, aot)) { ResourceMark rm; - log_debug(cds)("Used all dynamic archived lambda proxy classes for: %s %s%s", + log_debug(aot)("Used all dynamic archived lambda proxy classes for: %s %s%s", caller_ik->external_name(), invoked_name->as_C_string(), invoked_type->as_C_string()); } } @@ -306,9 +305,9 @@ InstanceKlass* LambdaProxyClassDictionary::find_lambda_proxy_class(const RunTime prev_klass->set_next_link(nullptr); proxy_klass = curr_klass; proxy_klass->clear_lambda_proxy_is_available(); - if (log_is_enabled(Debug, cds)) { + if (log_is_enabled(Debug, aot)) { ResourceMark rm; - log_debug(cds)("Loaded lambda proxy: %s ", proxy_klass->external_name()); + log_debug(aot)("Loaded lambda proxy: %s ", proxy_klass->external_name()); } } } @@ -413,7 +412,7 @@ class CopyLambdaProxyClassInfoToArchive : StackObj { // In static dump, info._proxy_klasses->at(0) is already relocated to point to the archived class // (not the original class). ResourceMark rm; - log_info(cds,dynamic)("Archiving hidden %s", info._proxy_klasses->at(0)->external_name()); + log_info(cds, dynamic)("Archiving hidden %s", info._proxy_klasses->at(0)->external_name()); size_t byte_size = sizeof(RunTimeLambdaProxyClassInfo); RunTimeLambdaProxyClassInfo* runtime_info = (RunTimeLambdaProxyClassInfo*)ArchiveBuilder::ro_region_alloc(byte_size); diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index ef2a6dcb8e6..233e64c5e3e 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -28,6 +28,8 @@ #include "cds/aotClassLocation.hpp" #include "cds/aotConstantPoolResolver.hpp" #include "cds/aotLinkedClassBulkLoader.hpp" +#include "cds/aotLogging.hpp" +#include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/archiveHeapWriter.hpp" @@ -58,6 +60,7 @@ #include "classfile/systemDictionaryShared.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" +#include "code/aotCodeCache.hpp" #include "code/codeCache.hpp" #include "gc/shared/gcVMOperations.hpp" #include "interpreter/bytecodeStream.hpp" @@ -69,6 +72,7 @@ #include "memory/memoryReserver.hpp" #include "memory/metaspace.hpp" #include "memory/metaspaceClosure.hpp" +#include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "nmt/memTracker.hpp" @@ -78,6 +82,7 @@ #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" #include "oops/oopHandle.hpp" +#include "oops/trainingData.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/globals.hpp" @@ -184,7 +189,7 @@ class DumpClassListCLDClosure : public CLDClosure { return; } if (_dumped_classes.maybe_grow()) { - log_info(cds, hashtables)("Expanded _dumped_classes table to %d", _dumped_classes.table_size()); + log_info(aot, hashtables)("Expanded _dumped_classes table to %d", _dumped_classes.table_size()); } if (ik->java_super()) { dump(ik->java_super()); @@ -255,7 +260,7 @@ static char* compute_shared_base(size_t cds_max) { : nullptr; if (aligned_base != specified_base) { - log_info(cds)("SharedBaseAddress (" INTPTR_FORMAT ") aligned up to " INTPTR_FORMAT, + aot_log_info(aot)("SharedBaseAddress (" INTPTR_FORMAT ") aligned up to " INTPTR_FORMAT, p2i(specified_base), p2i(aligned_base)); } @@ -273,7 +278,7 @@ static char* compute_shared_base(size_t cds_max) { // Arguments::default_SharedBaseAddress() is hard-coded in cds_globals.hpp. It must be carefully // picked that (a) the align_up() below will always return a valid value; (b) none of // the following asserts will fail. - log_warning(cds)("SharedBaseAddress (" INTPTR_FORMAT ") is %s. Reverted to " INTPTR_FORMAT, + aot_log_warning(aot)("SharedBaseAddress (" INTPTR_FORMAT ") is %s. Reverted to " INTPTR_FORMAT, p2i((void*)SharedBaseAddress), err, p2i((void*)Arguments::default_SharedBaseAddress())); @@ -288,7 +293,7 @@ static char* compute_shared_base(size_t cds_max) { void MetaspaceShared::initialize_for_static_dump() { assert(CDSConfig::is_dumping_static_archive(), "sanity"); - log_info(cds)("Core region alignment: %zu", core_region_alignment()); + aot_log_info(aot)("Core region alignment: %zu", core_region_alignment()); // The max allowed size for CDS archive. We use this to limit SharedBaseAddress // to avoid address space wrap around. size_t cds_max; @@ -312,7 +317,7 @@ void MetaspaceShared::initialize_for_static_dump() { os::vm_page_size(), mtClassShared); if (!_symbol_rs.is_reserved()) { - log_error(cds)("Unable to reserve memory for symbols: %zu bytes.", symbol_rs_size); + aot_log_error(aot)("Unable to reserve memory for symbols: %zu bytes.", symbol_rs_size); MetaspaceShared::unrecoverable_writing_error(); } _symbol_region.init(&_symbol_rs, &_symbol_vs); @@ -348,7 +353,7 @@ void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) ResourceMark rm(current); if (utf8_length == 0x7fffffff) { // buf_len will overflown 32-bit value. - log_error(cds)("string length too large: %d", utf8_length); + aot_log_error(aot)("string length too large: %d", utf8_length); MetaspaceShared::unrecoverable_loading_error(); } int buf_len = utf8_length+1; @@ -365,13 +370,13 @@ void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) oop str = StringTable::intern(utf8_buffer, THREAD); if (HAS_PENDING_EXCEPTION) { - log_warning(cds, heap)("[line %d] extra interned string allocation failed; size too large: %d", + log_warning(aot, heap)("[line %d] extra interned string allocation failed; size too large: %d", reader.last_line_no(), utf8_length); CLEAR_PENDING_EXCEPTION; } else { #if INCLUDE_CDS_JAVA_HEAP if (ArchiveHeapWriter::is_string_too_large_to_archive(str)) { - log_warning(cds, heap)("[line %d] extra interned string ignored; size too large: %d", + log_warning(aot, heap)("[line %d] extra interned string ignored; size too large: %d", reader.last_line_no(), utf8_length); continue; } @@ -405,7 +410,7 @@ void MetaspaceShared::write_method_handle_intrinsics() { word_size += m->constants()->cache()->size(); } } - log_info(cds)("Archived %d method handle intrinsics (%d bytes)", len, word_size * BytesPerWord); + log_info(aot)("Archived %d method handle intrinsics (%d bytes)", len, word_size * BytesPerWord); } // About "serialize" -- @@ -480,6 +485,7 @@ void MetaspaceShared::serialize(SerializeClosure* soc) { SystemDictionaryShared::serialize_dictionary_headers(soc); AOTLinkedClassBulkLoader::serialize(soc, true); FinalImageRecipes::serialize(soc); + TrainingData::serialize(soc); InstanceMirrorKlass::serialize_offsets(soc); // Dump/restore well known classes (pointers) @@ -490,6 +496,8 @@ void MetaspaceShared::serialize(SerializeClosure* soc) { soc->do_ptr((void**)&_archived_method_handle_intrinsics); LambdaFormInvokers::serialize(soc); + AdapterHandlerLibrary::serialize_shared_table_header(soc); + soc->do_tag(666); } @@ -535,7 +543,7 @@ class VM_PopulateDumpSharedSpace : public VM_Operation { void dump_java_heap_objects(); void dump_shared_symbol_table(GrowableArray* symbols) { - log_info(cds)("Dumping symbol table ..."); + log_info(aot)("Dumping symbol table ..."); SymbolTable::write_to_archive(symbols); } char* dump_early_read_only_tables(); @@ -564,6 +572,7 @@ class StaticArchiveBuilder : public ArchiveBuilder { SystemDictionaryShared::dumptime_classes_do(it); Universe::metaspace_pointers_do(it); vmSymbols::metaspace_pointers_do(it); + TrainingData::iterate_roots(it); // The above code should find all the symbols that are referenced by the // archived classes. We just need to add the extra symbols which @@ -603,11 +612,18 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables(AOTClassLocationConfig*& if (CDSConfig::is_dumping_preimage_static_archive()) { FinalImageRecipes::record_recipes(); } + + TrainingData::dump_training_data(); + MetaspaceShared::write_method_handle_intrinsics(); // Write lambform lines into archive LambdaFormInvokers::dump_static_archive_invokers(); + if (CDSConfig::is_dumping_adapters()) { + AdapterHandlerLibrary::dump_aot_adapter_table(); + } + // Write the other data to the output array. DumpRegion* ro_region = ArchiveBuilder::current()->ro_region(); char* start = ro_region->top(); @@ -638,15 +654,6 @@ void VM_PopulateDumpSharedSpace::doit() { // Block concurrent class unloading from changing the _dumptime_table MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag); -#if INCLUDE_CDS_JAVA_HEAP - if (CDSConfig::is_dumping_heap() && _extra_interned_strings != nullptr) { - for (int i = 0; i < _extra_interned_strings->length(); i ++) { - OopHandle string = _extra_interned_strings->at(i); - HeapShared::add_to_dumped_interned_strings(string.resolve()); - } - } -#endif - _builder.gather_source_objs(); _builder.reserve_buffer(); @@ -657,7 +664,7 @@ void VM_PopulateDumpSharedSpace::doit() { _builder.dump_ro_metadata(); _builder.relocate_metaspaceobj_embedded_pointers(); - log_info(cds)("Make classes shareable"); + log_info(aot)("Make classes shareable"); _builder.make_klasses_shareable(); MetaspaceShared::make_method_handle_intrinsics_shareable(); @@ -669,10 +676,13 @@ void VM_PopulateDumpSharedSpace::doit() { char* serialized_data = dump_read_only_tables(cl_config); if (CDSConfig::is_dumping_lambdas_in_legacy_mode()) { - log_info(cds)("Adjust lambda proxy class dictionary"); + log_info(aot)("Adjust lambda proxy class dictionary"); LambdaProxyClassDictionary::adjust_dumptime_table(); } + log_info(cds)("Make training data shareable"); + _builder.make_training_data_shareable(); + // The vtable clones contain addresses of the current process. // We don't want to write these addresses into the archive. CppVtables::zero_archived_vtables(); @@ -733,7 +743,7 @@ bool MetaspaceShared::may_be_eagerly_linked(InstanceKlass* ik) { // linked/verified at runtime. return false; } - if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared_unregistered_class()) { + if (CDSConfig::is_dumping_dynamic_archive() && ik->defined_by_other_loaders()) { // Linking of unregistered classes at this stage may cause more // classes to be resolved, resulting in calls to ClassLoader.loadClass() // that may not be expected by custom class loaders. @@ -769,7 +779,7 @@ void MetaspaceShared::link_shared_classes(TRAPS) { // Keep scanning until we have linked no more classes. } - // Resolve constant pool entries -- we don't load any new classes during this stage + // Eargerly resolve all string constants in constant pools { ResourceMark rm(THREAD); CollectClassesForLinking collect_classes; @@ -777,7 +787,7 @@ void MetaspaceShared::link_shared_classes(TRAPS) { for (int i = 0; i < mirrors->length(); i++) { OopHandle mirror = mirrors->at(i); InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve())); - AOTConstantPoolResolver::dumptime_resolve_constants(ik, CHECK); + AOTConstantPoolResolver::preresolve_string_cp_entries(ik, CHECK); } } @@ -791,17 +801,26 @@ void MetaspaceShared::link_shared_classes(TRAPS) { void MetaspaceShared::preload_and_dump(TRAPS) { CDSConfig::DumperThreadMark dumper_thread_mark(THREAD); ResourceMark rm(THREAD); + HandleMark hm(THREAD); + + if (CDSConfig::is_dumping_final_static_archive() && AOTPrintTrainingInfo) { + tty->print_cr("==================== archived_training_data ** before dumping ===================="); + TrainingData::print_archived_training_data_on(tty); + } + StaticArchiveBuilder builder; preload_and_dump_impl(builder, THREAD); if (HAS_PENDING_EXCEPTION) { if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) { - log_error(cds)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " + aot_log_error(aot)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " "%zuM", MaxHeapSize/M); MetaspaceShared::writing_error(); } else { - log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), - java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); - MetaspaceShared::writing_error("Unexpected exception, use -Xlog:cds,exceptions=trace for detail"); + oop message = java_lang_Throwable::message(PENDING_EXCEPTION); + aot_log_error(aot)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), + message == nullptr ? "(null)" : java_lang_String::as_utf8_string(message)); + MetaspaceShared::writing_error(err_msg("Unexpected exception, use -Xlog:aot%s,exceptions=trace for detail", + CDSConfig::new_aot_flags_used() ? "" : ",cds")); } } @@ -810,7 +829,6 @@ void MetaspaceShared::preload_and_dump(TRAPS) { // We are in the JVM that runs the training run. Continue execution, // so that it can finish all clean-up and return the correct exit // code to the OS. - tty->print_cr("AOTConfiguration recorded: %s", AOTConfiguration); } else { // The JLI launcher only recognizes the "old" -Xshare:dump flag. // When the new -XX:AOTMode=create flag is used, we can't return @@ -838,15 +856,15 @@ void MetaspaceShared::adjust_heap_sizes_for_dumping() { julong max_heap_size = (julong)(4 * G); if (MinHeapSize > max_heap_size) { - log_debug(cds)("Setting MinHeapSize to 4G for CDS dumping, original size = %zuM", MinHeapSize/M); + log_debug(aot)("Setting MinHeapSize to 4G for CDS dumping, original size = %zuM", 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 = %zuM", InitialHeapSize/M); + log_debug(aot)("Setting InitialHeapSize to 4G for CDS dumping, original size = %zuM", 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 = %zuM", MaxHeapSize/M); + log_debug(aot)("Setting MaxHeapSize to 4G for CDS dumping, original size = %zuM", MaxHeapSize/M); FLAG_SET_ERGO(MaxHeapSize, max_heap_size); } } @@ -869,7 +887,7 @@ void MetaspaceShared::preload_classes(TRAPS) { classlist_path = SharedClassListFile; } - log_info(cds)("Loading classes to share ..."); + aot_log_info(aot)("Loading classes to share ..."); ClassListParser::parse_classlist(classlist_path, ClassListParser::_parse_all, CHECK); if (ExtraSharedClassListFile) { @@ -890,7 +908,7 @@ void MetaspaceShared::preload_classes(TRAPS) { // are archived. exercise_runtime_cds_code(CHECK); - log_info(cds)("Loading classes to share: done."); + aot_log_info(aot)("Loading classes to share: done."); } void MetaspaceShared::exercise_runtime_cds_code(TRAPS) { @@ -908,14 +926,14 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS preload_classes(CHECK); if (SharedArchiveConfigFile) { - log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile); + log_info(aot)("Reading extra data from %s ...", SharedArchiveConfigFile); read_extra_data(THREAD, SharedArchiveConfigFile); - log_info(cds)("Reading extra data: done."); + log_info(aot)("Reading extra data: done."); } } if (CDSConfig::is_dumping_preimage_static_archive()) { - log_info(cds)("Reading lambda form invokers from JDK default classlist ..."); + log_info(aot)("Reading lambda form invokers from JDK default classlist ..."); char default_classlist[JVM_MAXPATHLEN]; get_default_classlist(default_classlist, JVM_MAXPATHLEN); struct stat statbuf; @@ -929,7 +947,7 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS if (CDSConfig::is_dumping_heap()) { assert(CDSConfig::allow_only_single_java_thread(), "Required"); if (!HeapShared::is_archived_boot_layer_available(THREAD)) { - log_info(cds)("archivedBootLayer not available, disabling full module graph"); + report_loading_error("archivedBootLayer not available, disabling full module graph"); CDSConfig::stop_dumping_full_module_graph(); } // Do this before link_shared_classes(), as the following line may load new classes. @@ -939,21 +957,22 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS if (CDSConfig::is_dumping_final_static_archive()) { if (ExtraSharedClassListFile) { - log_info(cds)("Loading extra classes from %s ...", ExtraSharedClassListFile); + log_info(aot)("Loading extra classes from %s ...", ExtraSharedClassListFile); ClassListParser::parse_classlist(ExtraSharedClassListFile, ClassListParser::_parse_all, CHECK); } } // Rewrite and link classes - log_info(cds)("Rewriting and linking classes ..."); + log_info(aot)("Rewriting and linking classes ..."); // Link any classes which got missed. This would happen if we have loaded classes that // 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); - log_info(cds)("Rewriting and linking classes: done"); + log_info(aot)("Rewriting and linking classes: done"); + TrainingData::init_dumptime_table(CHECK); // captures TrainingDataSetLocker if (CDSConfig::is_dumping_regenerated_lambdaform_invokers()) { LambdaFormInvokers::regenerate_holder_classes(CHECK); @@ -962,27 +981,19 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS #if INCLUDE_CDS_JAVA_HEAP if (CDSConfig::is_dumping_heap()) { ArchiveHeapWriter::init(); + if (CDSConfig::is_dumping_full_module_graph()) { ClassLoaderDataShared::ensure_module_entry_tables_exist(); HeapShared::reset_archived_object_states(CHECK); } - if (CDSConfig::is_dumping_method_handles()) { - // This assert means that the MethodType and MethodTypeForm tables won't be - // updated concurrently when we are saving their contents into a side table. - assert(CDSConfig::allow_only_single_java_thread(), "Required"); - - JavaValue result(T_VOID); - JavaCalls::call_static(&result, vmClasses::MethodType_klass(), - vmSymbols::createArchivedObjects(), - vmSymbols::void_method_signature(), - CHECK); - } + AOTReferenceObjSupport::initialize(CHECK); + AOTReferenceObjSupport::stabilize_cached_reference_objects(CHECK); if (CDSConfig::is_initing_classes_at_dump_time()) { // java.lang.Class::reflectionFactory cannot be archived yet. We set this field // to null, and it will be initialized again at runtime. - log_debug(cds)("Resetting Class::reflectionFactory"); + log_debug(aot)("Resetting Class::reflectionFactory"); TempNewSymbol method_name = SymbolTable::new_symbol("resetArchivedStates"); Symbol* method_sig = vmSymbols::void_method_signature(); JavaValue result(T_VOID); @@ -997,7 +1008,7 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS // some new strings may be added to the intern table. StringTable::allocate_shared_strings_array(CHECK); } else { - log_info(cds)("Not dumping heap, reset CDSConfig::_is_using_optimized_module_handling"); + log_info(aot)("Not dumping heap, reset CDSConfig::_is_using_optimized_module_handling"); CDSConfig::stop_using_optimized_module_handling(); } #endif @@ -1005,7 +1016,27 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS VM_PopulateDumpSharedSpace op(builder); VMThread::execute(&op); - if (!write_static_archive(&builder, op.map_info(), op.heap_info())) { + if (AOTCodeCache::is_on_for_dump() && CDSConfig::is_dumping_final_static_archive()) { + CDSConfig::enable_dumping_aot_code(); + { + builder.start_ac_region(); + // Write the contents to AOT code region and close AOTCodeCache before packing the region + AOTCodeCache::close(); + builder.end_ac_region(); + } + CDSConfig::disable_dumping_aot_code(); + } + + bool status = write_static_archive(&builder, op.map_info(), op.heap_info()); + if (status && CDSConfig::is_dumping_preimage_static_archive()) { + tty->print_cr("%s AOTConfiguration recorded: %s", + CDSConfig::has_temp_aot_config_file() ? "Temporary" : "", AOTConfiguration); + if (CDSConfig::is_single_command_training()) { + fork_and_dump_final_static_archive(CHECK); + } + } + + if (!status) { THROW_MSG(vmSymbols::java_io_IOException(), "Encountered error while dumping"); } } @@ -1022,12 +1053,138 @@ bool MetaspaceShared::write_static_archive(ArchiveBuilder* builder, FileMapInfo* builder->write_archive(map_info, heap_info); if (AllowArchivingWithJavaAgent) { - log_warning(cds)("This %s was created with AllowArchivingWithJavaAgent. It should be used " + aot_log_warning(aot)("This %s was created with AllowArchivingWithJavaAgent. It should be used " "for testing purposes only and should not be used in a production environment", CDSConfig::type_of_archive_being_loaded()); } return true; } +static void print_java_launcher(outputStream* st) { + st->print("%s%sbin%sjava", Arguments::get_java_home(), os::file_separator(), os::file_separator()); +} + +static void append_args(GrowableArray* args, const char* arg, TRAPS) { + Handle string = java_lang_String::create_from_str(arg, CHECK); + args->append(string); +} + +// Pass all options in Arguments::jvm_args_array() to a child JVM process +// using the JAVA_TOOL_OPTIONS environment variable. +static int exec_jvm_with_java_tool_options(const char* java_launcher_path, TRAPS) { + ResourceMark rm(THREAD); + HandleMark hm(THREAD); + GrowableArray args; + + const char* cp = Arguments::get_appclasspath(); + if (cp != nullptr && strlen(cp) > 0 && strcmp(cp, ".") != 0) { + // We cannot use "-cp", because "-cp" is only interpreted by the java launcher, + // and is not interpreter by arguments.cpp when it loads args from JAVA_TOOL_OPTIONS + stringStream ss; + ss.print("-Djava.class.path="); + ss.print_raw(cp); + append_args(&args, ss.freeze(), CHECK_0); + // CDS$ProcessLauncher::execWithJavaToolOptions() must unset CLASSPATH, which has + // a higher priority than -Djava.class.path= + } + + // Pass all arguments. These include those from JAVA_TOOL_OPTIONS and _JAVA_OPTIONS. + for (int i = 0; i < Arguments::num_jvm_args(); i++) { + const char* arg = Arguments::jvm_args_array()[i]; + if (strstr(arg, "-XX:AOTCacheOutput=") == arg || // arg starts with ... + strstr(arg, "-XX:AOTConfiguration=") == arg || + strstr(arg, "-XX:AOTMode=") == arg) { + // Filter these out. They wiill be set below. + } else { + append_args(&args, arg, CHECK_0); + } + } + + // Note: because we are running in AOTMode=record, JDK_AOT_VM_OPTIONS have not been + // parsed, so they are not in Arguments::jvm_args_array. If JDK_AOT_VM_OPTIONS is in + // the environment, it will be inherited and parsed by the child JVM process + // in Arguments::parse_java_tool_options_environment_variable(). + precond(strcmp(AOTMode, "record") == 0); + + // We don't pass Arguments::jvm_flags_array(), as those will be added by + // the child process when it loads .hotspotrc + + { + // If AOTCacheOutput contains %p, it should have been already substituted with the + // pid of the training process. + stringStream ss; + ss.print("-XX:AOTCacheOutput="); + ss.print_raw(AOTCacheOutput); + append_args(&args, ss.freeze(), CHECK_0); + } + { + // If AOTCacheConfiguration contains %p, it should have been already substituted with the + // pid of the training process. + // If AOTCacheConfiguration was not explicitly specified, it should have been assigned a + // temporary file name. + stringStream ss; + ss.print("-XX:AOTConfiguration="); + ss.print_raw(AOTConfiguration); + append_args(&args, ss.freeze(), CHECK_0); + } + + append_args(&args, "-XX:AOTMode=create", CHECK_0); + + Symbol* klass_name = SymbolTable::new_symbol("jdk/internal/misc/CDS$ProcessLauncher"); + Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK_0); + Symbol* methodName = SymbolTable::new_symbol("execWithJavaToolOptions"); + Symbol* methodSignature = SymbolTable::new_symbol("(Ljava/lang/String;[Ljava/lang/String;)I"); + + Handle launcher = java_lang_String::create_from_str(java_launcher_path, CHECK_0); + objArrayOop array = oopFactory::new_objArray(vmClasses::String_klass(), args.length(), CHECK_0); + for (int i = 0; i < args.length(); i++) { + array->obj_at_put(i, args.at(i)()); + } + objArrayHandle launcher_args(THREAD, array); + + // The following call will pass all options inside the JAVA_TOOL_OPTIONS env variable to + // the child process. It will also clear the _JAVA_OPTIONS and CLASSPATH env variables for + // the child process. + // + // Note: the env variables are set only for the child process. They are not changed + // for the current process. See java.lang.ProcessBuilder::environment(). + JavaValue result(T_OBJECT); + JavaCallArguments javacall_args(2); + javacall_args.push_oop(launcher); + javacall_args.push_oop(launcher_args); + JavaCalls::call_static(&result, + InstanceKlass::cast(k), + methodName, + methodSignature, + &javacall_args, + CHECK_0); + return result.get_jint(); +} + +void MetaspaceShared::fork_and_dump_final_static_archive(TRAPS) { + assert(CDSConfig::is_dumping_preimage_static_archive(), "sanity"); + + ResourceMark rm; + stringStream ss; + print_java_launcher(&ss); + const char* cmd = ss.freeze(); + tty->print_cr("Launching child process %s to assemble AOT cache %s using configuration %s", cmd, AOTCacheOutput, AOTConfiguration); + int status = exec_jvm_with_java_tool_options(cmd, CHECK); + if (status != 0) { + log_error(aot)("Child process failed; status = %d", status); + // We leave the temp config file for debugging + } else if (CDSConfig::has_temp_aot_config_file()) { + const char* tmp_config = AOTConfiguration; + // On Windows, need WRITE permission to remove the file. + WINDOWS_ONLY(chmod(tmp_config, _S_IREAD | _S_IWRITE)); + status = remove(tmp_config); + if (status != 0) { + log_error(aot)("Failed to remove temporary AOT configuration file %s", tmp_config); + } else { + tty->print_cr("Removed temporary AOT configuration file %s", tmp_config); + } + } +} + // Returns true if the class's status has changed. bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { ExceptionMark em(current); @@ -1042,7 +1199,7 @@ bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { if (ik->is_loaded() && !ik->is_linked() && ik->can_be_verified_at_dumptime() && !SystemDictionaryShared::has_class_failed_verification(ik)) { bool saved = BytecodeVerificationLocal; - if (ik->is_shared_unregistered_class() && ik->class_loader() == nullptr) { + if (ik->defined_by_other_loaders() && ik->class_loader() == nullptr) { // The verification decision is based on BytecodeVerificationRemote // for non-system classes. Since we are using the null classloader // to load non-system classes for customized class loaders during dumping, @@ -1055,7 +1212,7 @@ bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) { ik->link_class(THREAD); if (HAS_PENDING_EXCEPTION) { ResourceMark rm(THREAD); - log_warning(cds)("Preload Warning: Verification failed for %s", + aot_log_warning(aot)("Preload Warning: Verification failed for %s", ik->external_name()); CLEAR_PENDING_EXCEPTION; SystemDictionaryShared::set_class_has_failed_verification(ik); @@ -1107,10 +1264,7 @@ bool MetaspaceShared::is_shared_static(void* p) { // - When -XX:+RequireSharedSpaces is specified, AND the JVM cannot load the archive(s) due // to version or classpath mismatch. void MetaspaceShared::unrecoverable_loading_error(const char* message) { - log_error(cds)("An error has occurred while processing the %s.", CDSConfig::type_of_archive_being_loaded()); - if (message != nullptr) { - log_error(cds)("%s", message); - } + report_loading_error("%s", message); if (CDSConfig::is_dumping_final_static_archive()) { vm_exit_during_initialization("Must be a valid AOT configuration generated by the current JVM", AOTConfiguration); @@ -1121,6 +1275,33 @@ void MetaspaceShared::unrecoverable_loading_error(const char* message) { } } +void MetaspaceShared::report_loading_error(const char* format, ...) { + // When using AOT cache, errors messages are always printed on the error channel. + LogStream ls_aot(LogLevel::Error, LogTagSetMapping::tagset()); + + // If we are loading load the default CDS archive, it may fail due to incompatible VM options. + // Print at the info level to avoid excessive verbosity. + // However, if the user has specified a CDS archive (or AOT cache), they would be interested in + // knowing that the loading fails, so we print at the error level. + LogLevelType level = (!CDSConfig::is_using_archive() || CDSConfig::is_using_only_default_archive()) ? + LogLevel::Info : LogLevel::Error; + LogStream ls_cds(level, LogTagSetMapping::tagset()); + + LogStream& ls = CDSConfig::new_aot_flags_used() ? ls_aot : ls_cds; + va_list ap; + va_start(ap, format); + + static bool printed_error = false; + if (!printed_error) { // No need for locks. Loading error checks happen only in main thread. + ls.print_cr("An error has occurred while processing the %s. Run with -Xlog:%s for details.", + CDSConfig::type_of_archive_being_loaded(), CDSConfig::new_aot_flags_used() ? "aot" : "aot,cds"); + printed_error = true; + } + ls.vprint_cr(format, ap); + + va_end(ap); +} + // This function is called when the JVM is unable to write the specified CDS archive due to an // unrecoverable error. void MetaspaceShared::unrecoverable_writing_error(const char* message) { @@ -1131,9 +1312,9 @@ void MetaspaceShared::unrecoverable_writing_error(const char* message) { // This function is called when the JVM is unable to write the specified CDS archive due to a // an error. The error will be propagated void MetaspaceShared::writing_error(const char* message) { - log_error(cds)("An error has occurred while writing the shared archive file."); + aot_log_error(aot)("An error has occurred while writing the shared archive file."); if (message != nullptr) { - log_error(cds)("%s", message); + aot_log_error(aot)("%s", message); } } @@ -1145,17 +1326,17 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { FileMapInfo* dynamic_mapinfo = nullptr; if (static_mapinfo != nullptr) { - log_info(cds)("Core region alignment: %zu", static_mapinfo->core_region_alignment()); + aot_log_info(aot)("Core region alignment: %zu", static_mapinfo->core_region_alignment()); dynamic_mapinfo = open_dynamic_archive(); - log_info(cds)("ArchiveRelocationMode: %d", ArchiveRelocationMode); + aot_log_info(aot)("ArchiveRelocationMode: %d", ArchiveRelocationMode); // First try to map at the requested address result = map_archives(static_mapinfo, dynamic_mapinfo, true); if (result == MAP_ARCHIVE_MMAP_FAILURE) { // Mapping has failed (probably due to ASLR). Let's map at an address chosen // by the OS. - log_info(cds)("Try to map archive(s) at an alternative address"); + aot_log_info(aot)("Try to map archive(s) at an alternative address"); result = map_archives(static_mapinfo, dynamic_mapinfo, false); } } @@ -1176,17 +1357,20 @@ void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() { } else { set_shared_metaspace_range(nullptr, nullptr, nullptr); if (CDSConfig::is_dumping_dynamic_archive()) { - log_warning(cds)("-XX:ArchiveClassesAtExit is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."); + aot_log_warning(aot)("-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; CDSConfig::disable_dumping_dynamic_archive(); - log_info(cds)("Unable to map shared spaces"); if (PrintSharedArchiveAndExit) { MetaspaceShared::unrecoverable_loading_error("Unable to use shared archive."); - } else if (RequireSharedSpaces) { - MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces"); + } else { + if (RequireSharedSpaces) { + MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces"); + } else { + report_loading_error("Unable to map shared spaces"); + } } } @@ -1242,7 +1426,7 @@ FileMapInfo* MetaspaceShared::open_dynamic_archive() { MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo, bool use_requested_addr) { if (use_requested_addr && static_mapinfo->requested_base_address() == nullptr) { - log_info(cds)("Archive(s) were created with -XX:SharedBaseAddress=0. Always map at os-selected address."); + aot_log_info(aot)("Archive(s) were created with -XX:SharedBaseAddress=0. Always map at os-selected address."); return MAP_ARCHIVE_MMAP_FAILURE; } @@ -1250,12 +1434,12 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File // For product build only -- this is for benchmarking the cost of doing relocation. // For debug builds, the check is done below, after reserving the space, for better test coverage // (see comment below). - log_info(cds)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address"); + aot_log_info(aot)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address"); return MAP_ARCHIVE_MMAP_FAILURE; }); if (ArchiveRelocationMode == 2 && !use_requested_addr) { - log_info(cds)("ArchiveRelocationMode == 2: never map archive(s) at an alternative address"); + aot_log_info(aot)("ArchiveRelocationMode == 2: never map archive(s) at an alternative address"); return MAP_ARCHIVE_MMAP_FAILURE; }; @@ -1276,7 +1460,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File class_space_rs); if (mapped_base_address == nullptr) { result = MAP_ARCHIVE_MMAP_FAILURE; - log_debug(cds)("Failed to reserve spaces (use_requested_addr=%u)", (unsigned)use_requested_addr); + aot_log_debug(aot)("Failed to reserve spaces (use_requested_addr=%u)", (unsigned)use_requested_addr); } else { if (Metaspace::using_class_space()) { @@ -1306,10 +1490,10 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File } #endif // ASSERT - log_info(cds)("Reserved archive_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes%s", + aot_log_info(aot)("Reserved archive_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes%s", p2i(archive_space_rs.base()), p2i(archive_space_rs.end()), archive_space_rs.size(), (prot_zone_size > 0 ? " (includes protection zone)" : "")); - log_info(cds)("Reserved class_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes", + aot_log_info(aot)("Reserved class_space_rs [" INTPTR_FORMAT " - " INTPTR_FORMAT "] (%zu) bytes", p2i(class_space_rs.base()), p2i(class_space_rs.end()), class_space_rs.size()); if (MetaspaceShared::use_windows_memory_mapping()) { @@ -1331,7 +1515,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File // pointers anyway so there's no benefit to mmap. if (use_requested_addr) { assert(!total_space_rs.is_reserved(), "Should not be reserved for Windows"); - log_info(cds)("Windows mmap workaround: releasing archive space."); + aot_log_info(aot)("Windows mmap workaround: releasing archive space."); MemoryReserver::release(archive_space_rs); // Mark as not reserved archive_space_rs = {}; @@ -1345,10 +1529,10 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File if (prot_zone_size > 0) { assert(prot_zone_size >= os::vm_allocation_granularity(), "must be"); // not just page size! char* p = os::attempt_reserve_memory_at(mapped_base_address, prot_zone_size, - false, MemTag::mtClassShared); + mtClassShared); assert(p == mapped_base_address || p == nullptr, "must be"); if (p == nullptr) { - log_debug(cds)("Failed to re-reserve protection zone"); + aot_log_debug(aot)("Failed to re-reserve protection zone"); return MAP_ARCHIVE_MMAP_FAILURE; } } @@ -1373,7 +1557,7 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File // debug builds, we do it here (after all archives have possibly been // mapped), so we can thoroughly test the code for failure handling // (releasing all allocated resource, etc). - log_info(cds)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address"); + aot_log_info(aot)("ArchiveRelocationMode == 1: always map archive(s) at an alternative address"); if (static_result == MAP_ARCHIVE_SUCCESS) { static_result = MAP_ARCHIVE_MMAP_FAILURE; } @@ -1442,8 +1626,8 @@ MapArchiveResult MetaspaceShared::map_archives(FileMapInfo* static_mapinfo, File static_mapinfo->map_or_load_heap_region(); } #endif // _LP64 - log_info(cds)("initial optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); - log_info(cds)("initial full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); + log_info(aot)("initial optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); + log_info(aot)("initial full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); } else { unmap_archive(static_mapinfo); unmap_archive(dynamic_mapinfo); @@ -1537,7 +1721,8 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma archive_space_rs = MemoryReserver::reserve((char*)base_address, archive_space_size, archive_space_alignment, - os::vm_page_size()); + os::vm_page_size(), + mtNone); if (archive_space_rs.is_reserved()) { assert(base_address == nullptr || (address)archive_space_rs.base() == base_address, "Sanity"); @@ -1588,7 +1773,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma const int precomputed_narrow_klass_shift = ArchiveBuilder::precomputed_narrow_klass_shift(); if (!CompressedKlassPointers::check_klass_decode_mode(base_address, precomputed_narrow_klass_shift, total_range_size)) { - log_info(cds)("CDS initialization: Cannot use SharedBaseAddress " PTR_FORMAT " with precomputed shift %d.", + aot_log_info(aot)("CDS initialization: Cannot use SharedBaseAddress " PTR_FORMAT " with precomputed shift %d.", p2i(base_address), precomputed_narrow_klass_shift); use_archive_base_addr = false; } @@ -1605,11 +1790,13 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma archive_space_rs = MemoryReserver::reserve((char*)base_address, archive_space_size, archive_space_alignment, - os::vm_page_size()); + os::vm_page_size(), + mtNone); class_space_rs = MemoryReserver::reserve((char*)ccs_base, class_space_size, class_space_alignment, - os::vm_page_size()); + os::vm_page_size(), + mtNone); } if (!archive_space_rs.is_reserved() || !class_space_rs.is_reserved()) { release_reserved_spaces(total_space_rs, archive_space_rs, class_space_rs); @@ -1622,7 +1809,8 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma total_space_rs = MemoryReserver::reserve((char*) base_address, total_range_size, base_address_alignment, - os::vm_page_size()); + os::vm_page_size(), + mtNone); } else { // We did not manage to reserve at the preferred address, or were instructed to relocate. In that // case we reserve wherever possible, but the start address needs to be encodable as narrow Klass @@ -1669,17 +1857,17 @@ void MetaspaceShared::release_reserved_spaces(ReservedSpace& total_space_rs, ReservedSpace& archive_space_rs, ReservedSpace& class_space_rs) { if (total_space_rs.is_reserved()) { - log_debug(cds)("Released shared space (archive + class) " INTPTR_FORMAT, p2i(total_space_rs.base())); + aot_log_debug(aot)("Released shared space (archive + class) " INTPTR_FORMAT, p2i(total_space_rs.base())); MemoryReserver::release(total_space_rs); total_space_rs = {}; } else { if (archive_space_rs.is_reserved()) { - log_debug(cds)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base())); + aot_log_debug(aot)("Released shared space (archive) " INTPTR_FORMAT, p2i(archive_space_rs.base())); MemoryReserver::release(archive_space_rs); archive_space_rs = {}; } if (class_space_rs.is_reserved()) { - log_debug(cds)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base())); + aot_log_debug(aot)("Released shared space (classes) " INTPTR_FORMAT, p2i(class_space_rs.base())); MemoryReserver::release(class_space_rs); class_space_rs = {}; } @@ -1697,8 +1885,8 @@ MapArchiveResult MetaspaceShared::map_archive(FileMapInfo* mapinfo, char* mapped mapinfo->set_is_mapped(false); if (mapinfo->core_region_alignment() != (size_t)core_region_alignment()) { - log_info(cds)("Unable to map CDS archive -- core_region_alignment() expected: %zu" - " actual: %zu", mapinfo->core_region_alignment(), core_region_alignment()); + report_loading_error("Unable to map CDS archive -- core_region_alignment() expected: %zu" + " actual: %zu", mapinfo->core_region_alignment(), core_region_alignment()); return MAP_ARCHIVE_OTHER_FAILURE; } @@ -1772,6 +1960,7 @@ void MetaspaceShared::initialize_shared_spaces() { static_mapinfo->patch_heap_embedded_pointers(); ArchiveHeapLoader::finish_initialization(); Universe::load_archived_object_instances(); + AOTCodeCache::initialize(); // Close the mapinfo file static_mapinfo->close(); @@ -1788,7 +1977,7 @@ void MetaspaceShared::initialize_shared_spaces() { dynamic_mapinfo->unmap_region(MetaspaceShared::bm); } - LogStreamHandle(Info, cds) lsh; + LogStreamHandle(Info, aot) lsh; if (lsh.is_enabled()) { lsh.print("Using AOT-linked classes: %s (static archive: %s aot-linked classes", BOOL_TO_STR(CDSConfig::is_using_aot_linked_classes()), @@ -1823,6 +2012,13 @@ void MetaspaceShared::initialize_shared_spaces() { SystemDictionaryShared::print_shared_archive(tty, false/*dynamic*/); } + TrainingData::print_archived_training_data_on(tty); + + if (AOTCodeCache::is_on_for_use()) { + tty->print_cr("\n\nAOT Code"); + AOTCodeCache::print_on(tty); + } + // collect shared symbols and strings CountSharedSymbols cl; SymbolTable::shared_symbols_do(&cl); diff --git a/src/hotspot/share/cds/metaspaceShared.hpp b/src/hotspot/share/cds/metaspaceShared.hpp index e03994be1b9..130e7fe4484 100644 --- a/src/hotspot/share/cds/metaspaceShared.hpp +++ b/src/hotspot/share/cds/metaspaceShared.hpp @@ -67,8 +67,9 @@ class MetaspaceShared : AllStatic { ro = 1, // read-only shared space bm = 2, // relocation bitmaps (freed after file mapping is finished) hp = 3, // heap region + ac = 4, // aot code num_core_region = 2, // rw and ro - n_regions = 4 // total number of regions + n_regions = 5 // total number of regions }; static void preload_and_dump(TRAPS) NOT_CDS_RETURN; @@ -109,7 +110,8 @@ class MetaspaceShared : AllStatic { static bool is_shared_dynamic(void* p) NOT_CDS_RETURN_(false); static bool is_shared_static(void* p) NOT_CDS_RETURN_(false); - static void unrecoverable_loading_error(const char* message = nullptr); + static void unrecoverable_loading_error(const char* message = "unrecoverable error"); + static void report_loading_error(const char* format, ...) ATTRIBUTE_PRINTF(1, 0); static void unrecoverable_writing_error(const char* message = nullptr); static void writing_error(const char* message = nullptr); @@ -177,6 +179,7 @@ class MetaspaceShared : AllStatic { private: static void read_extra_data(JavaThread* current, const char* filename) NOT_CDS_RETURN; + static void fork_and_dump_final_static_archive(TRAPS); static bool write_static_archive(ArchiveBuilder* builder, FileMapInfo* map_info, ArchiveHeapInfo* heap_info); static FileMapInfo* open_static_archive(); static FileMapInfo* open_dynamic_archive(); diff --git a/src/hotspot/share/cds/regeneratedClasses.cpp b/src/hotspot/share/cds/regeneratedClasses.cpp index 37d5e89598a..38bf1a11952 100644 --- a/src/hotspot/share/cds/regeneratedClasses.cpp +++ b/src/hotspot/share/cds/regeneratedClasses.cpp @@ -57,7 +57,7 @@ void RegeneratedClasses::add_class(InstanceKlass* orig_klass, InstanceKlass* reg Method* regen_m = regen_klass->find_method(orig_m->name(), orig_m->signature()); if (regen_m == nullptr) { ResourceMark rm; - log_warning(cds)("Method in original class is missing from regenerated class: " INTPTR_FORMAT " %s", + log_warning(aot)("Method in original class is missing from regenerated class: " INTPTR_FORMAT " %s", p2i(orig_m), orig_m->external_name()); } else { _renegerated_objs->put((address)orig_m, (address)regen_m); diff --git a/src/hotspot/share/cds/runTimeClassInfo.hpp b/src/hotspot/share/cds/runTimeClassInfo.hpp index 8ad2efcbccb..058d5181881 100644 --- a/src/hotspot/share/cds/runTimeClassInfo.hpp +++ b/src/hotspot/share/cds/runTimeClassInfo.hpp @@ -264,7 +264,11 @@ class RunTimeClassInfo { // Used by RunTimeSharedDictionary to implement OffsetCompactHashtable::EQUALS static inline bool EQUALS( const RunTimeClassInfo* value, Symbol* key, int len_unused) { +#if INCLUDE_CDS return (value->klass()->name() == key); +#else + return false; +#endif } }; diff --git a/src/hotspot/share/cds/unregisteredClasses.cpp b/src/hotspot/share/cds/unregisteredClasses.cpp index 2e985b72310..31cfbd15d67 100644 --- a/src/hotspot/share/cds/unregisteredClasses.cpp +++ b/src/hotspot/share/cds/unregisteredClasses.cpp @@ -24,37 +24,49 @@ #include "cds/cdsConfig.hpp" #include "cds/unregisteredClasses.hpp" -#include "classfile/classFileStream.hpp" -#include "classfile/classLoader.inline.hpp" -#include "classfile/classLoaderExt.hpp" -#include "classfile/javaClasses.inline.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" -#include "memory/oopFactory.hpp" -#include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" +#include "oops/oopHandle.hpp" #include "oops/oopHandle.inline.hpp" +#include "runtime/handles.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaCalls.hpp" #include "services/threadService.hpp" -InstanceKlass* UnregisteredClasses::_UnregisteredClassLoader_klass = nullptr; +static InstanceKlass* _UnregisteredClassLoader_klass; +static InstanceKlass* _UnregisteredClassLoader_Source_klass; +static OopHandle _unregistered_class_loader; void UnregisteredClasses::initialize(TRAPS) { - if (_UnregisteredClassLoader_klass == nullptr) { - // no need for synchronization as this function is called single-threaded. - Symbol* klass_name = SymbolTable::new_symbol("jdk/internal/misc/CDS$UnregisteredClassLoader"); - Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK); - _UnregisteredClassLoader_klass = InstanceKlass::cast(k); + if (_UnregisteredClassLoader_klass != nullptr) { + return; } + + Symbol* klass_name; + Klass* k; + + // no need for synchronization as this function is called single-threaded. + klass_name = SymbolTable::new_symbol("jdk/internal/misc/CDS$UnregisteredClassLoader"); + k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK); + _UnregisteredClassLoader_klass = InstanceKlass::cast(k); + + klass_name = SymbolTable::new_symbol("jdk/internal/misc/CDS$UnregisteredClassLoader$Source"); + k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK); + _UnregisteredClassLoader_Source_klass = InstanceKlass::cast(k); + + precond(_unregistered_class_loader.is_empty()); + HandleMark hm(THREAD); + const Handle cl = JavaCalls::construct_new_instance(_UnregisteredClassLoader_klass, + vmSymbols::void_method_signature(), CHECK); + _unregistered_class_loader = OopHandle(Universe::vm_global(), cl()); } // Load the class of the given name from the location given by path. The path is specified by // the "source:" in the class list file (see classListParser.cpp), and can be a directory or // a JAR file. -InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, - Handle super_class, objArrayHandle interfaces, TRAPS) { +InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, TRAPS) { assert(name != nullptr, "invariant"); assert(CDSConfig::is_dumping_static_archive(), "this function is only used with -Xshare:dump"); @@ -62,59 +74,33 @@ InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, THREAD->get_thread_stat()->perf_timers_addr(), PerfClassTraceTime::CLASS_LOAD); - // Call CDS$UnregisteredClassLoader::load(String name, Class superClass, Class[] interfaces) + assert(!_unregistered_class_loader.is_empty(), "not initialized"); + Handle classloader(THREAD, _unregistered_class_loader.resolve()); + + // Call CDS$UnregisteredClassLoader::load(String name, String source) Symbol* methodName = SymbolTable::new_symbol("load"); - Symbol* methodSignature = SymbolTable::new_symbol("(Ljava/lang/String;Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/Class;"); - Symbol* path_symbol = SymbolTable::new_symbol(path); - Handle classloader = get_classloader(path_symbol, CHECK_NULL); + Symbol* methodSignature = SymbolTable::new_symbol("(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;"); Handle ext_class_name = java_lang_String::externalize_classname(name, CHECK_NULL); + Handle path_string = java_lang_String::create_from_str(path, CHECK_NULL); JavaValue result(T_OBJECT); - JavaCallArguments args(3); - args.set_receiver(classloader); - args.push_oop(ext_class_name); - args.push_oop(super_class); - args.push_oop(interfaces); JavaCalls::call_virtual(&result, - UnregisteredClassLoader_klass(), + classloader, + _UnregisteredClassLoader_klass, methodName, methodSignature, - &args, + ext_class_name, + path_string, CHECK_NULL); assert(result.get_type() == T_OBJECT, "just checking"); - oop obj = result.get_oop(); - return InstanceKlass::cast(java_lang_Class::as_Klass(obj)); -} - -class UnregisteredClasses::ClassLoaderTable : public ResourceHashtable< - Symbol*, OopHandle, - 137, // prime number - AnyObj::C_HEAP> {}; - -static UnregisteredClasses::ClassLoaderTable* _classloader_table = nullptr; -Handle UnregisteredClasses::create_classloader(Symbol* path, TRAPS) { - ResourceMark rm(THREAD); - JavaValue result(T_OBJECT); - Handle path_string = java_lang_String::create_from_str(path->as_C_string(), CHECK_NH); - Handle classloader = JavaCalls::construct_new_instance( - UnregisteredClassLoader_klass(), - vmSymbols::string_void_signature(), - path_string, CHECK_NH); - return classloader; + return InstanceKlass::cast(java_lang_Class::as_Klass(result.get_oop())); } -Handle UnregisteredClasses::get_classloader(Symbol* path, TRAPS) { - if (_classloader_table == nullptr) { - _classloader_table = new (mtClass)ClassLoaderTable(); - } - OopHandle* classloader_ptr = _classloader_table->get(path); - if (classloader_ptr != nullptr) { - return Handle(THREAD, (*classloader_ptr).resolve()); - } else { - Handle classloader = create_classloader(path, CHECK_NH); - _classloader_table->put(path, OopHandle(Universe::vm_global(), classloader())); - path->increment_refcount(); - return classloader; +bool UnregisteredClasses::check_for_exclusion(const InstanceKlass* k) { + if (_UnregisteredClassLoader_klass == nullptr) { + return false; // Uninitialized } + return k == _UnregisteredClassLoader_klass || + k->implements_interface(_UnregisteredClassLoader_Source_klass); } diff --git a/src/hotspot/share/cds/unregisteredClasses.hpp b/src/hotspot/share/cds/unregisteredClasses.hpp index ea3a308c2de..d61c3462504 100644 --- a/src/hotspot/share/cds/unregisteredClasses.hpp +++ b/src/hotspot/share/cds/unregisteredClasses.hpp @@ -33,22 +33,10 @@ class Symbol; class UnregisteredClasses: AllStatic { public: - static InstanceKlass* load_class(Symbol* h_name, const char* path, - Handle super_class, objArrayHandle interfaces, - TRAPS); + static InstanceKlass* load_class(Symbol* name, const char* path, TRAPS); static void initialize(TRAPS); - static InstanceKlass* UnregisteredClassLoader_klass() { - return _UnregisteredClassLoader_klass; - } - - class ClassLoaderTable; - -private: - // Don't put this in vmClasses as it's used only with CDS dumping. - static InstanceKlass* _UnregisteredClassLoader_klass; - - static Handle create_classloader(Symbol* path, TRAPS); - static Handle get_classloader(Symbol* path, TRAPS); + // Returns true if the class is loaded internally for dumping unregistered classes. + static bool check_for_exclusion(const InstanceKlass* k); }; #endif // SHARE_CDS_UNREGISTEREDCLASSES_HPP diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 3991773d86f..2de77f2828d 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1159,6 +1159,13 @@ int ciEnv::compile_id() { // ciEnv::notice_inlined_method() void ciEnv::notice_inlined_method(ciMethod* method) { _num_inlined_bytecodes += method->code_size_for_inlining(); + CompileTrainingData* ctd = task()->training_data(); + if (ctd != nullptr) { + GUARDED_VM_ENTRY({ + methodHandle mh(Thread::current(), method->get_Method()); + ctd->notice_inlined_method(task(), mh); + }); + } } // ------------------------------------------------------------------ @@ -1170,6 +1177,15 @@ int ciEnv::num_inlined_bytecodes() const { // ------------------------------------------------------------------ // ciEnv::record_failure() void ciEnv::record_failure(const char* reason) { + // record the bailout for hserr envlog + if (reason != nullptr) { + if (CompilationLog::log() != nullptr) { + CompilerThread* thread = CompilerThread::current(); + CompileTask* task = thread->task(); + CompilationLog::log()->log_failure(thread, task, reason, nullptr); + } + } + if (_failure_reason.get() == nullptr) { // Record the first failure reason. _failure_reason.set(reason); diff --git a/src/hotspot/share/ci/ciInstance.cpp b/src/hotspot/share/ci/ciInstance.cpp index ad456ba6726..9591298e3ab 100644 --- a/src/hotspot/share/ci/ciInstance.cpp +++ b/src/hotspot/share/ci/ciInstance.cpp @@ -138,3 +138,9 @@ ciKlass* ciInstance::java_lang_Class_klass() { assert(java_lang_Class::as_Klass(get_oop()) != nullptr, "klass is null"); return CURRENT_ENV->get_metadata(java_lang_Class::as_Klass(get_oop()))->as_klass(); } + +char* ciInstance::java_lang_String_str(char* buf, size_t buflen) { + VM_ENTRY_MARK; + assert(get_oop()->is_a(vmClasses::String_klass()), "not a String"); + return java_lang_String::as_utf8_string(get_oop(), buf, buflen); +} diff --git a/src/hotspot/share/ci/ciInstance.hpp b/src/hotspot/share/ci/ciInstance.hpp index 3af07edcd9e..1fb09985930 100644 --- a/src/hotspot/share/ci/ciInstance.hpp +++ b/src/hotspot/share/ci/ciInstance.hpp @@ -67,6 +67,7 @@ class ciInstance : public ciObject { ciConstant field_value_by_offset(int field_offset); ciKlass* java_lang_Class_klass(); + char* java_lang_String_str(char* buf, size_t buflen); }; #endif // SHARE_CI_CIINSTANCE_HPP diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp index 69b73152d37..92a7434e8ba 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -44,6 +44,7 @@ class ciInstanceKlass : public ciKlass { friend class ciMethod; friend class ciField; friend class ciReplay; + friend class CompileTrainingData; private: enum SubklassValue { subklass_unknown, subklass_false, subklass_true }; diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index 3b2670c3eb0..d3b8b8f13cc 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -36,6 +36,7 @@ #include "compiler/abstractCompiler.hpp" #include "compiler/compilerDefinitions.inline.hpp" #include "compiler/compilerOracle.hpp" +#include "compiler/compileTask.hpp" #include "compiler/methodLiveness.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" @@ -47,6 +48,7 @@ #include "oops/generateOopMap.hpp" #include "oops/method.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/trainingData.hpp" #include "prims/methodHandles.hpp" #include "runtime/deoptimization.hpp" #include "runtime/handles.inline.hpp" @@ -914,8 +916,14 @@ int ciMethod::scale_count(int count, float prof_factor) { method_life = counter_life; } if (counter_life > 0) { - count = (int)((double)count * prof_factor * method_life / counter_life + 0.5); - count = (count > 0) ? count : 1; + double count_d = (double)count * prof_factor * method_life / counter_life + 0.5; + if (count_d >= static_cast(INT_MAX)) { + // Clamp in case of overflowing int range. + count = INT_MAX; + } else { + count = int(count_d); + count = (count > 0) ? count : 1; + } } else { count = 1; } @@ -1142,6 +1150,28 @@ int ciMethod::code_size_for_inlining() { // Also some instructions inside the code are excluded from inline // heuristic (e.g. post call nop instructions; see InlineSkippedInstructionsCounter) int ciMethod::inline_instructions_size() { + if (_inline_instructions_size == -1) { + if (TrainingData::have_data()) { + GUARDED_VM_ENTRY( + CompLevel level = static_cast(CURRENT_ENV->comp_level()); + methodHandle top_level_mh(Thread::current(), CURRENT_ENV->task()->method()); + MethodTrainingData* mtd = MethodTrainingData::find(top_level_mh); + if (mtd != nullptr) { + CompileTrainingData* ctd = mtd->last_toplevel_compile(level); + if (ctd != nullptr) { + methodHandle mh(Thread::current(), get_Method()); + MethodTrainingData* this_mtd = MethodTrainingData::find(mh); + if (this_mtd != nullptr) { + auto r = ctd->ci_records().ciMethod__inline_instructions_size.find(this_mtd); + if (r.is_valid()) { + _inline_instructions_size = r.result(); + } + } + } + } + ); + } + } if (_inline_instructions_size == -1) { GUARDED_VM_ENTRY( nmethod* code = get_Method()->code(); @@ -1151,6 +1181,14 @@ int ciMethod::inline_instructions_size() { } else { _inline_instructions_size = 0; } + if (TrainingData::need_data()) { + CompileTrainingData* ctd = CURRENT_ENV->task()->training_data(); + if (ctd != nullptr) { + methodHandle mh(Thread::current(), get_Method()); + MethodTrainingData* this_mtd = MethodTrainingData::make(mh); + ctd->ci_records().ciMethod__inline_instructions_size.append_if_missing(_inline_instructions_size, this_mtd); + } + } ); } return _inline_instructions_size; diff --git a/src/hotspot/share/ci/ciMethodData.cpp b/src/hotspot/share/ci/ciMethodData.cpp index a37e4ba75e6..533e8659968 100644 --- a/src/hotspot/share/ci/ciMethodData.cpp +++ b/src/hotspot/share/ci/ciMethodData.cpp @@ -31,6 +31,7 @@ #include "memory/resourceArea.hpp" #include "oops/klass.inline.hpp" #include "oops/methodData.inline.hpp" +#include "oops/trainingData.hpp" #include "runtime/deoptimization.hpp" #include "utilities/copy.hpp" @@ -54,6 +55,11 @@ ciMethodData::ciMethodData(MethodData* md) _invocation_counter(0), _orig() {} + +static bool is_klass_loaded(Klass* k) { + return TrainingData::is_klass_loaded(k); +} + // Check for entries that reference an unloaded method class PrepareExtraDataClosure : public CleanExtraDataClosure { MethodData* _mdo; @@ -68,7 +74,8 @@ class PrepareExtraDataClosure : public CleanExtraDataClosure { { } bool is_live(Method* m) { - if (!m->method_holder()->is_loader_alive()) { + Klass* holder = m->method_holder(); + if (holder == nullptr || !holder->is_loader_present_and_alive() || !is_klass_loaded(holder)) { return false; } if (CURRENT_ENV->cached_metadata(m) == nullptr) { @@ -303,7 +310,7 @@ bool ciMethodData::load_data() { void ciReceiverTypeData::translate_receiver_data_from(const ProfileData* data) { for (uint row = 0; row < row_limit(); row++) { Klass* k = data->as_ReceiverTypeData()->receiver(row); - if (k != nullptr) { + if (k != nullptr && k->class_loader_data() != nullptr && is_klass_loaded(k)) { if (k->is_loader_alive()) { ciKlass* klass = CURRENT_ENV->get_klass(k); set_receiver(row, klass); @@ -321,7 +328,7 @@ void ciTypeStackSlotEntries::translate_type_data_from(const TypeStackSlotEntries for (int i = 0; i < number_of_entries(); i++) { intptr_t k = entries->type(i); Klass* klass = (Klass*)klass_part(k); - if (klass != nullptr && !klass->is_loader_alive()) { + if (klass == nullptr || !klass->is_loader_present_and_alive() || !is_klass_loaded(klass)) { // With concurrent class unloading, the MDO could have stale metadata; override it TypeStackSlotEntries::set_type(i, TypeStackSlotEntries::with_status((Klass*)nullptr, k)); } else { @@ -333,7 +340,7 @@ void ciTypeStackSlotEntries::translate_type_data_from(const TypeStackSlotEntries void ciReturnTypeEntry::translate_type_data_from(const ReturnTypeEntry* ret) { intptr_t k = ret->type(); Klass* klass = (Klass*)klass_part(k); - if (klass != nullptr && !klass->is_loader_alive()) { + if (klass == nullptr || !klass->is_loader_present_and_alive() || !is_klass_loaded(klass)) { // With concurrent class unloading, the MDO could have stale metadata; override it set_type(ReturnTypeEntry::with_status((Klass*)nullptr, k)); } else { diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp index 1fa590e4ad3..2af5d812922 100644 --- a/src/hotspot/share/ci/ciObjectFactory.cpp +++ b/src/hotspot/share/ci/ciObjectFactory.cpp @@ -44,10 +44,12 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/vmClasses.hpp" #include "compiler/compiler_globals.hpp" +#include "compiler/compileTask.hpp" #include "gc/shared/collectedHeap.inline.hpp" #include "memory/allocation.inline.hpp" #include "memory/universe.hpp" #include "oops/oop.inline.hpp" +#include "oops/trainingData.hpp" #include "runtime/handles.inline.hpp" #include "runtime/signature.hpp" #include "utilities/macros.hpp" @@ -108,7 +110,7 @@ void ciObjectFactory::initialize() { // This Arena is long lived and exists in the resource mark of the // compiler thread that initializes the initial ciObjectFactory which // creates the shared ciObjects that all later ciObjectFactories use. - Arena* arena = new (mtCompiler) Arena(mtCompiler, Arena::Tag::tag_cienv); + Arena* arena = new (mtCompiler) Arena(mtCompiler); ciEnv initial(arena); ciEnv* env = ciEnv::current(); env->_factory->init_shared_objects(); @@ -232,26 +234,40 @@ void ciObjectFactory::remove_symbols() { ciObject* ciObjectFactory::get(oop key) { ASSERT_IN_VM; - assert(Universe::heap()->is_in(key), "must be"); + Handle keyHandle(Thread::current(), key); + assert(Universe::heap()->is_in(keyHandle()), "must be"); - NonPermObject* &bucket = find_non_perm(key); + NonPermObject* &bucket = find_non_perm(keyHandle); if (bucket != nullptr) { return bucket->object(); } // The ciObject does not yet exist. Create it and insert it // into the cache. - Handle keyHandle(Thread::current(), key); ciObject* new_object = create_new_object(keyHandle()); assert(keyHandle() == new_object->get_oop(), "must be properly recorded"); init_ident_of(new_object); assert(Universe::heap()->is_in(new_object->get_oop()), "must be"); // Not a perm-space object. - insert_non_perm(bucket, keyHandle(), new_object); + insert_non_perm(bucket, keyHandle, new_object); + notice_new_object(new_object); return new_object; } +void ciObjectFactory::notice_new_object(ciBaseObject* new_object) { + if (TrainingData::need_data()) { + ciEnv* env = ciEnv::current(); + if (env->task() != nullptr) { + // Note: task will be null during init_compiler_runtime. + CompileTrainingData* td = env->task()->training_data(); + if (td != nullptr) { + td->notice_jit_observation(env, new_object); + } + } + } +} + int ciObjectFactory::metadata_compare(Metadata* const& key, ciMetadata* const& elt) { Metadata* value = elt->constant_encoding(); if (key < value) return -1; @@ -331,6 +347,7 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { } assert(!found, "no double insert"); _ci_metadata.insert_before(index, new_object); + notice_new_object(new_object); return new_object; } return _ci_metadata.at(index)->as_metadata(); @@ -636,12 +653,12 @@ static ciObjectFactory::NonPermObject* emptyBucket = nullptr; // Use a small hash table, hashed on the klass of the key. // If there is no entry in the cache corresponding to this oop, return // the null tail of the bucket into which the oop should be inserted. -ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(oop key) { - assert(Universe::heap()->is_in(key), "must be"); - ciMetadata* klass = get_metadata(key->klass()); +ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(Handle keyHandle) { + assert(Universe::heap()->is_in(keyHandle()), "must be"); + ciMetadata* klass = get_metadata(keyHandle->klass()); // This may safepoint! NonPermObject* *bp = &_non_perm_bucket[(unsigned) klass->hash() % NON_PERM_BUCKETS]; for (NonPermObject* p; (p = (*bp)) != nullptr; bp = &p->next()) { - if (is_equal(p, key)) break; + if (is_equal(p, keyHandle())) break; } return (*bp); } @@ -664,12 +681,12 @@ inline ciObjectFactory::NonPermObject::NonPermObject(ciObjectFactory::NonPermObj // ciObjectFactory::insert_non_perm // // Insert a ciObject into the non-perm table. -void ciObjectFactory::insert_non_perm(ciObjectFactory::NonPermObject* &where, oop key, ciObject* obj) { - assert(Universe::heap()->is_in_or_null(key), "must be"); +void ciObjectFactory::insert_non_perm(ciObjectFactory::NonPermObject* &where, Handle keyHandle, ciObject* obj) { + assert(Universe::heap()->is_in_or_null(keyHandle()), "must be"); assert(&where != &emptyBucket, "must not try to fill empty bucket"); - NonPermObject* p = new (arena()) NonPermObject(where, key, obj); - assert(where == p && is_equal(p, key) && p->object() == obj, "entry must match"); - assert(find_non_perm(key) == p, "must find the same spot"); + NonPermObject* p = new (arena()) NonPermObject(where, keyHandle(), obj); + assert(where == p && is_equal(p, keyHandle()) && p->object() == obj, "entry must match"); + assert(find_non_perm(keyHandle) == p, "must find the same spot"); ++_non_perm_count; } diff --git a/src/hotspot/share/ci/ciObjectFactory.hpp b/src/hotspot/share/ci/ciObjectFactory.hpp index d95a7d1ff22..15ff2e48eb6 100644 --- a/src/hotspot/share/ci/ciObjectFactory.hpp +++ b/src/hotspot/share/ci/ciObjectFactory.hpp @@ -37,6 +37,7 @@ // which ensures that for each oop, at most one ciObject is created. // This invariant allows efficient implementation of ciObject. class ciObjectFactory : public ArenaObj { + friend class VMStructs; friend class ciEnv; private: @@ -77,8 +78,8 @@ class ciObjectFactory : public ArenaObj { return p->object()->get_oop() == key; } - NonPermObject* &find_non_perm(oop key); - void insert_non_perm(NonPermObject* &where, oop key, ciObject* obj); + NonPermObject* &find_non_perm(Handle keyHandle); + void insert_non_perm(NonPermObject* &where, Handle keyHandle, ciObject* obj); void init_ident_of(ciBaseObject* obj); @@ -106,6 +107,9 @@ class ciObjectFactory : public ArenaObj { // Get the ciSymbol corresponding to one of the vmSymbols. static ciSymbol* vm_symbol_at(vmSymbolID index); + // Called on every new object made. + void notice_new_object(ciBaseObject* new_object); + // Get the ciMethod representing an unloaded/unfound method. ciMethod* get_unloaded_method(ciInstanceKlass* holder, ciSymbol* name, diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index d490b75919d..f9829e88c4a 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -802,11 +802,11 @@ class CompileReplay : public StackObj { // Make sure the existence of a prior compile doesn't stop this one nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code(); if (nm != nullptr) { - nm->make_not_entrant("CI replay"); + nm->make_not_entrant(nmethod::ChangeReason::CI_replay); } replay_state = this; CompileBroker::compile_method(methodHandle(THREAD, method), entry_bci, comp_level, - methodHandle(), 0, CompileTask::Reason_Replay, THREAD); + 0, CompileTask::Reason_Replay, THREAD); replay_state = nullptr; } diff --git a/src/hotspot/share/ci/ciTypeFlow.cpp b/src/hotspot/share/ci/ciTypeFlow.cpp index 234b4611ea1..6df090a7ce5 100644 --- a/src/hotspot/share/ci/ciTypeFlow.cpp +++ b/src/hotspot/share/ci/ciTypeFlow.cpp @@ -2924,7 +2924,7 @@ void ciTypeFlow::flow_types() { // Continue flow analysis until fixed point reached - debug_only(int max_block = _next_pre_order;) + DEBUG_ONLY(int max_block = _next_pre_order;) while (!work_list_empty()) { Block* blk = work_list_next(); diff --git a/src/hotspot/share/ci/ciTypeFlow.hpp b/src/hotspot/share/ci/ciTypeFlow.hpp index 92db6253aa0..adfb85dc17f 100644 --- a/src/hotspot/share/ci/ciTypeFlow.hpp +++ b/src/hotspot/share/ci/ciTypeFlow.hpp @@ -253,7 +253,7 @@ class ciTypeFlow : public ArenaObj { set_type_at_tos(type); } void pop() { - debug_only(set_type_at_tos(bottom_type())); + DEBUG_ONLY(set_type_at_tos(bottom_type())); _stack_size--; } ciType* pop_value() { diff --git a/src/hotspot/share/ci/ciUtilities.inline.hpp b/src/hotspot/share/ci/ciUtilities.inline.hpp index 05e73d8ca64..91f848368ac 100644 --- a/src/hotspot/share/ci/ciUtilities.inline.hpp +++ b/src/hotspot/share/ci/ciUtilities.inline.hpp @@ -37,7 +37,7 @@ ThreadInVMfromNative __tiv(thread); \ HandleMarkCleaner __hm(thread); \ JavaThread* THREAD = thread; /* For exception macros. */ \ - debug_only(VMNativeEntryWrapper __vew;) + DEBUG_ONLY(VMNativeEntryWrapper __vew;) @@ -49,10 +49,10 @@ * [TODO] The NoHandleMark line does nothing but declare a function prototype \ * The NoHandkeMark constructor is NOT executed. If the ()'s are \ * removed, causes the NoHandleMark assert to trigger. \ - * debug_only(NoHandleMark __hm();) \ + * DEBUG_ONLY(NoHandleMark __hm();) \ */ \ JavaThread* THREAD = thread; /* For exception macros. */ \ - debug_only(VMNativeEntryWrapper __vew;) + DEBUG_ONLY(VMNativeEntryWrapper __vew;) #define EXCEPTION_CONTEXT \ diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 3e6246d4aee..bfb41f8384a 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -154,6 +154,8 @@ #define JAVA_25_VERSION 69 +#define JAVA_26_VERSION 70 + 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, @@ -176,7 +178,7 @@ void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const s const ClassFileStream cfs1 = *stream; const ClassFileStream* const cfs = &cfs1; - debug_only(const u1* const old_current = stream->current();) + DEBUG_ONLY(const u1* const old_current = stream->current();) // Used for batching symbol allocations. const char* names[SymbolTable::symbol_alloc_batch_size]; @@ -5015,6 +5017,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, // Set name and CLD before adding to CLD ik->set_class_loader_data(_loader_data); + ik->set_class_loader_type(); ik->set_name(_class_name); // Add all classes to our internal class loader list here, @@ -5243,7 +5246,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, // it's official set_klass(ik); - debug_only(ik->verify();) + DEBUG_ONLY(ik->verify();) } void ClassFileParser::update_class_name(Symbol* new_class_name) { diff --git a/src/hotspot/share/classfile/classFileStream.cpp b/src/hotspot/share/classfile/classFileStream.cpp index 382bd58af2b..dc5329a65f2 100644 --- a/src/hotspot/share/classfile/classFileStream.cpp +++ b/src/hotspot/share/classfile/classFileStream.cpp @@ -23,7 +23,6 @@ */ #include "classfile/classFileStream.hpp" -#include "classfile/classLoader.hpp" #include "classfile/vmSymbols.hpp" #include "memory/resourceArea.hpp" diff --git a/src/hotspot/share/classfile/classFileStream.hpp b/src/hotspot/share/classfile/classFileStream.hpp index 135a34bdeee..7f7e4ccacd5 100644 --- a/src/hotspot/share/classfile/classFileStream.hpp +++ b/src/hotspot/share/classfile/classFileStream.hpp @@ -156,8 +156,6 @@ class ClassFileStream: public ResourceObj { // Tells whether eos is reached bool at_eos() const { return _current == _buffer_end; } - uint64_t compute_fingerprint() const; - bool from_class_file_load_hook() const { return _from_class_file_load_hook; } }; diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index a7d6cc39614..e6c10859371 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -69,7 +69,6 @@ #include "runtime/javaCalls.hpp" #include "runtime/os.hpp" #include "runtime/perfData.hpp" -#include "runtime/threadCritical.hpp" #include "runtime/timer.hpp" #include "runtime/vm_version.hpp" #include "services/management.hpp" @@ -1196,15 +1195,24 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, if (loader == nullptr) { // JFR classes ik->set_shared_classpath_index(0); - ik->set_shared_class_loader_type(ClassLoader::BOOT_LOADER); } return; } + if (!SystemDictionaryShared::is_builtin_loader(ik->class_loader_data())) { + // A class loaded by a user-defined classloader. + 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; + } + assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build"); ResourceMark rm(current); int classpath_index = -1; + bool found_invalid = false; + PackageEntry* pkg_entry = ik->package(); if (!AOTClassLocationConfig::dumptime_is_ready()) { @@ -1242,10 +1250,13 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, classpath_index = i; } else { if (cl->from_boot_classpath()) { - // The class must be from boot loader append path which consists of - // -Xbootclasspath/a and jvmti appended entries. - assert(loader == nullptr, "sanity"); - classpath_index = i; + if (loader != nullptr) { + // Probably loaded by jdk/internal/loader/ClassLoaders$BootClassLoader. Don't archive + // such classes. + found_invalid = true; + } else { + classpath_index = i; + } } } } else { @@ -1256,52 +1267,32 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, } } } - if (classpath_index >= 0) { - return false; // quit iterating + if (classpath_index >= 0 || found_invalid) { + return false; // Break the AOTClassLocationConfig::dumptime_iterate() loop. } else { return true; // Keep iterating } }); + } - // No path entry found for this class: most likely a shared class loaded by the - // user defined classloader. - 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; - } + if (found_invalid) { + assert(classpath_index == -1, "sanity"); } const char* const class_name = ik->name()->as_C_string(); const char* const file_name = file_name_for_class_name(class_name, ik->name()->utf8_length()); assert(file_name != nullptr, "invariant"); - ClassLoaderExt::record_result(checked_cast(classpath_index), ik, redefined); + ClassLoaderExt::record_result_for_builtin_loader(checked_cast(classpath_index), ik, redefined); } void ClassLoader::record_hidden_class(InstanceKlass* ik) { assert(ik->is_hidden(), "must be"); - s2 classloader_type; - if (HeapShared::is_lambda_form_klass(ik)) { - classloader_type = ClassLoader::BOOT_LOADER; - } else { - oop loader = ik->class_loader(); - - if (loader == nullptr) { - classloader_type = ClassLoader::BOOT_LOADER; - } else if (SystemDictionary::is_platform_class_loader(loader)) { - classloader_type = ClassLoader::PLATFORM_LOADER; - } else if (SystemDictionary::is_system_class_loader(loader)) { - classloader_type = ClassLoader::APP_LOADER; - } else { - // This class won't be archived, so no need to update its - // classloader_type/classpath_index. - return; - } + if (ik->defined_by_other_loaders()) { + // We don't archive hidden classes for non-builtin loaders. + return; } - ik->set_shared_class_loader_type(classloader_type); if (HeapShared::is_lambda_proxy_klass(ik)) { InstanceKlass* nest_host = ik->nest_host_not_null(); @@ -1310,7 +1301,7 @@ void ClassLoader::record_hidden_class(InstanceKlass* ik) { ik->set_shared_classpath_index(0); } else { // Generated invoker classes. - if (classloader_type == ClassLoader::APP_LOADER) { + if (ik->defined_by_app_loader()) { ik->set_shared_classpath_index(AOTClassLocationConfig::dumptime()->app_cp_start_index()); } else { ik->set_shared_classpath_index(0); @@ -1500,8 +1491,7 @@ char* ClassLoader::get_canonical_path(const char* orig, Thread* thread) { char* canonical_path = NEW_RESOURCE_ARRAY_IN_THREAD(thread, char, JVM_MAXPATHLEN); ResourceMark rm(thread); // os::native_path writes into orig_copy - char* orig_copy = NEW_RESOURCE_ARRAY_IN_THREAD(thread, char, strlen(orig)+1); - strcpy(orig_copy, orig); + char* orig_copy = ResourceArea::strdup(thread, orig); if ((CanonicalizeEntry)(os::native_path(orig_copy), canonical_path, JVM_MAXPATHLEN) < 0) { return nullptr; } diff --git a/src/hotspot/share/classfile/classLoaderDataShared.cpp b/src/hotspot/share/classfile/classLoaderDataShared.cpp index 5cfe2df61b1..94ded38f5da 100644 --- a/src/hotspot/share/classfile/classLoaderDataShared.cpp +++ b/src/hotspot/share/classfile/classLoaderDataShared.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotLogging.hpp" #include "cds/cdsConfig.hpp" #include "cds/serializeClosure.hpp" #include "classfile/classLoaderData.inline.hpp" @@ -192,7 +193,7 @@ void ClassLoaderDataShared::serialize(SerializeClosure* f) { // Must be done before ClassLoader::create_javabase() _archived_boot_loader_data.restore(null_class_loader_data(), true, false); ModuleEntryTable::set_javabase_moduleEntry(_archived_javabase_moduleEntry); - log_info(cds)("use_full_module_graph = true; java.base = " INTPTR_FORMAT, + aot_log_info(aot)("use_full_module_graph = true; java.base = " INTPTR_FORMAT, p2i(_archived_javabase_moduleEntry)); } } diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp index fb635133537..cd57f4e5e25 100644 --- a/src/hotspot/share/classfile/classLoaderExt.cpp +++ b/src/hotspot/share/classfile/classLoaderExt.cpp @@ -67,18 +67,16 @@ int ClassLoaderExt::compare_module_names(const char** p1, const char** p2) { return strcmp(*p1, *p2); } -void ClassLoaderExt::record_result(s2 classpath_index, InstanceKlass* result, bool redefined) { +void ClassLoaderExt::record_result_for_builtin_loader(s2 classpath_index, InstanceKlass* result, bool redefined) { assert(CDSConfig::is_dumping_archive(), "sanity"); - // We need to remember where the class comes from during dumping. oop loader = result->class_loader(); - s2 classloader_type = ClassLoader::BOOT_LOADER; if (SystemDictionary::is_system_class_loader(loader)) { - classloader_type = ClassLoader::APP_LOADER; AOTClassLocationConfig::dumptime_set_has_app_classes(); } else if (SystemDictionary::is_platform_class_loader(loader)) { - classloader_type = ClassLoader::PLATFORM_LOADER; AOTClassLocationConfig::dumptime_set_has_platform_classes(); + } else { + precond(loader == nullptr); } if (CDSConfig::is_dumping_preimage_static_archive() || CDSConfig::is_dumping_dynamic_archive()) { @@ -89,10 +87,9 @@ void ClassLoaderExt::record_result(s2 classpath_index, InstanceKlass* result, bo AOTClassLocationConfig::dumptime_update_max_used_index(classpath_index); result->set_shared_classpath_index(classpath_index); - result->set_shared_class_loader_type(classloader_type); #if INCLUDE_CDS_JAVA_HEAP - if (CDSConfig::is_dumping_heap() && AllowArchivingWithJavaAgent && classloader_type == ClassLoader::BOOT_LOADER && + if (CDSConfig::is_dumping_heap() && AllowArchivingWithJavaAgent && result->defined_by_boot_loader() && classpath_index < 0 && redefined) { // When dumping the heap (which happens only during static dump), classes for the built-in // loaders are always loaded from known locations (jimage, classpath or modulepath), @@ -103,7 +100,7 @@ void ClassLoaderExt::record_result(s2 classpath_index, InstanceKlass* result, bo // 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.", + log_warning(aot)("heap objects cannot be written because class %s maybe modified by ClassFileLoadHook.", result->external_name()); CDSConfig::disable_heap_dumping(); } diff --git a/src/hotspot/share/classfile/classLoaderExt.hpp b/src/hotspot/share/classfile/classLoaderExt.hpp index f4a1cf1a9c7..ee6b59bde14 100644 --- a/src/hotspot/share/classfile/classLoaderExt.hpp +++ b/src/hotspot/share/classfile/classLoaderExt.hpp @@ -40,7 +40,7 @@ class ClassLoaderExt: public ClassLoader { // AllStatic static void append_boot_classpath(ClassPathEntry* new_entry); static int compare_module_names(const char** p1, const char** p2); - static void record_result(s2 classpath_index, InstanceKlass* result, bool redefined); + static void record_result_for_builtin_loader(s2 classpath_index, InstanceKlass* result, bool redefined); #endif // INCLUDE_CDS }; diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp index 8d50e8136a3..9f7ec6bd118 100644 --- a/src/hotspot/share/classfile/compactHashtable.cpp +++ b/src/hotspot/share/classfile/compactHashtable.cpp @@ -155,7 +155,7 @@ void CompactHashtableWriter::dump(SimpleCompactHashtable *cht, const char* table cht->init(base_address, _num_entries_written, _num_buckets, _compact_buckets->data(), _compact_entries->data()); - LogMessage(cds, hashtables) msg; + LogMessage(aot, hashtables) msg; if (msg.is_info()) { double avg_cost = 0.0; if (_num_entries_written > 0) { @@ -226,7 +226,7 @@ HashtableTextDump::HashtableTextDump(const char* filename) : _fd(-1) { if (_fd < 0) { quit("Unable to open hashtable dump file", filename); } - _base = os::map_memory(_fd, filename, 0, nullptr, _size, true, false); + _base = os::map_memory(_fd, filename, 0, nullptr, _size, mtNone, true, false); if (_base == nullptr) { quit("Unable to map hashtable dump file", filename); } diff --git a/src/hotspot/share/classfile/compactHashtable.hpp b/src/hotspot/share/classfile/compactHashtable.hpp index 2985f0f9a1a..83299eda8c7 100644 --- a/src/hotspot/share/classfile/compactHashtable.hpp +++ b/src/hotspot/share/classfile/compactHashtable.hpp @@ -241,6 +241,7 @@ template < bool (*EQUALS)(V value, K key, int len) > class CompactHashtable : public SimpleCompactHashtable { + friend class VMStructs; V decode(u4 offset) const { return DECODE(_base_address, offset); @@ -282,7 +283,15 @@ class CompactHashtable : public SimpleCompactHashtable { } template - inline void iterate(ITER* iter) const { + inline void iterate(ITER* iter) const { iterate([&](V v) { iter->do_value(v); }); } + + template + inline void iterate(const Function& function) const { // lambda enabled API + iterate(const_cast(function)); + } + + template + inline void iterate(Function& function) const { // lambda enabled API for (u4 i = 0; i < _bucket_count; i++) { u4 bucket_info = _buckets[i]; u4 bucket_offset = BUCKET_OFFSET(bucket_info); @@ -290,11 +299,11 @@ class CompactHashtable : public SimpleCompactHashtable { u4* entry = _entries + bucket_offset; if (bucket_type == VALUE_ONLY_BUCKET_TYPE) { - iter->do_value(decode(entry[0])); + function(decode(entry[0])); } else { - u4*entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]); + u4* entry_max = _entries + BUCKET_OFFSET(_buckets[i + 1]); while (entry < entry_max) { - iter->do_value(decode(entry[1])); + function(decode(entry[1])); entry += 2; } } diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index 75bc33a3083..a9c694c33c1 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -237,8 +237,8 @@ class PrintHierarchy : public HierarchyVisitor { public: bool visit() { InstanceKlass* cls = current_class(); - streamIndentor si(_st, current_depth() * 2); - _st->indent().print_cr("%s", cls->name()->as_C_string()); + StreamIndentor si(_st, current_depth() * 2); + _st->print_cr("%s", cls->name()->as_C_string()); return true; } @@ -436,8 +436,8 @@ class MethodFamily : public ResourceObj { void print_selected(outputStream* str, int indent) const { assert(has_target(), "Should be called otherwise"); - streamIndentor si(str, indent * 2); - str->indent().print("Selected method: "); + StreamIndentor si(str, indent * 2); + str->print("Selected method: "); print_method(str, _selected_target); Klass* method_holder = _selected_target->method_holder(); if (!method_holder->is_interface()) { @@ -449,8 +449,8 @@ class MethodFamily : public ResourceObj { void print_exception(outputStream* str, int indent) { assert(throws_exception(), "Should be called otherwise"); assert(_exception_name != nullptr, "exception_name should be set"); - streamIndentor si(str, indent * 2); - str->indent().print_cr("%s: %s", _exception_name->as_C_string(), _exception_message->as_C_string()); + StreamIndentor si(str, indent * 2); + str->print_cr("%s: %s", _exception_name->as_C_string(), _exception_message->as_C_string()); } }; @@ -678,9 +678,8 @@ static void find_empty_vtable_slots(GrowableArray* slots, lt.print("Slots that need filling:"); ResourceMark rm; LogStream ls(lt); - streamIndentor si(&ls); + StreamIndentor si(&ls, 2); for (int i = 0; i < slots->length(); ++i) { - ls.indent(); slots->at(i)->print_on(&ls); ls.cr(); } @@ -851,8 +850,8 @@ void DefaultMethods::generate_default_methods( LogTarget(Debug, defaultmethods) lt; if (lt.is_enabled()) { LogStream ls(lt); - streamIndentor si(&ls, 2); - ls.indent().print("Looking for default methods for slot "); + StreamIndentor si(&ls, 2); + ls.print("Looking for default methods for slot "); slot->print_on(&ls); ls.cr(); } diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index a2ad1dce5e4..8d32d73fb47 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotReferenceObjSupport.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveHeapLoader.hpp" #include "cds/cdsConfig.hpp" @@ -1205,7 +1206,7 @@ bool java_lang_Class::restore_archived_mirror(Klass *k, k->clear_archived_mirror_index(); // mirror is archived, restore - log_debug(cds, mirror)("Archived mirror is: " PTR_FORMAT, p2i(m)); + log_debug(aot, mirror)("Archived mirror is: " PTR_FORMAT, p2i(m)); assert(as_Klass(m) == k, "must be"); Handle mirror(THREAD, m); @@ -1230,9 +1231,9 @@ bool java_lang_Class::restore_archived_mirror(Klass *k, set_mirror_module_field(THREAD, k, mirror, module); - if (log_is_enabled(Trace, cds, heap, mirror)) { + if (log_is_enabled(Trace, aot, heap, mirror)) { ResourceMark rm(THREAD); - log_trace(cds, heap, mirror)( + log_trace(aot, heap, mirror)( "Restored %s archived mirror " PTR_FORMAT, k->external_name(), p2i(mirror())); } @@ -1871,7 +1872,7 @@ ByteSize java_lang_Thread::thread_id_offset() { } oop java_lang_Thread::park_blocker(oop java_thread) { - return java_thread->obj_field(_park_blocker_offset); + return java_thread->obj_field_access(_park_blocker_offset); } oop java_lang_Thread::async_get_stack_trace(oop java_thread, TRAPS) { @@ -4821,7 +4822,7 @@ bool java_lang_ClassLoader::isAncestor(oop loader, oop cl) { assert(is_instance(loader), "loader must be oop"); assert(cl == nullptr || is_instance(cl), "cl argument must be oop"); oop acl = loader; - debug_only(jint loop_count = 0); + DEBUG_ONLY(jint loop_count = 0); // This loop taken verbatim from ClassLoader.java: do { acl = parent(acl); @@ -5460,9 +5461,7 @@ bool JavaClasses::is_supported_for_archiving(oop obj) { } } - if (klass->is_subclass_of(vmClasses::Reference_klass())) { - // It's problematic to archive Reference objects. One of the reasons is that - // Reference::discovered may pull in unwanted objects (see JDK-8284336) + if (!AOTReferenceObjSupport::is_enabled() && klass->is_subclass_of(vmClasses::Reference_klass())) { return false; } diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp index 28bb176ed0a..f2f31de4a37 100644 --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -31,6 +31,7 @@ #include "classfile/classLoaderData.inline.hpp" #include "classfile/classLoadInfo.hpp" #include "classfile/klassFactory.hpp" +#include "classfile/systemDictionaryShared.hpp" #include "memory/resourceArea.hpp" #include "prims/jvmtiEnvBase.hpp" #include "prims/jvmtiRedefineClasses.hpp" @@ -97,7 +98,6 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook( if (class_loader.is_null()) { new_ik->set_classpath_index(path_index); - new_ik->assign_class_loader_type(); } return new_ik; @@ -205,6 +205,9 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream, const ClassInstanceInfo* cl_inst_info = cl_info.class_hidden_info_ptr(); InstanceKlass* result = parser.create_instance_klass(old_stream != stream, *cl_inst_info, CHECK_NULL); assert(result != nullptr, "result cannot be null with no pending exception"); + if (CDSConfig::is_dumping_archive() && stream->from_class_file_load_hook()) { + SystemDictionaryShared::set_from_class_file_load_hook(result); + } if (cached_class_file != nullptr) { // JVMTI: we have an InstanceKlass now, tell it about the cached bytes diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp index 18f2abfd5f4..208c4efe035 100644 --- a/src/hotspot/share/classfile/moduleEntry.cpp +++ b/src/hotspot/share/classfile/moduleEntry.cpp @@ -427,9 +427,9 @@ ModuleEntry* ModuleEntry::allocate_archived_entry() const { // For verify_archived_module_entries() DEBUG_ONLY(_num_inited_module_entries++); - if (log_is_enabled(Info, cds, module)) { + if (log_is_enabled(Info, aot, module)) { ResourceMark rm; - LogStream ls(Log(cds, module)::info()); + LogStream ls(Log(aot, module)::info()); ls.print("Stored in archive: "); archived_entry->print(&ls); } @@ -535,9 +535,9 @@ void ModuleEntry::restore_archived_oops(ClassLoaderData* loader_data) { assert(java_lang_Module::loader(module_handle()) == loader_data->class_loader(), "must be set in dump time"); - if (log_is_enabled(Info, cds, module)) { + if (log_is_enabled(Info, aot, module)) { ResourceMark rm; - LogStream ls(Log(cds, module)::info()); + LogStream ls(Log(aot, module)::info()); ls.print("Restored from archive: "); print(&ls); } diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index 3f2ff90ccab..4b146abc06b 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotLogging.hpp" #include "cds/archiveBuilder.hpp" #include "cds/cdsConfig.hpp" #include "cds/metaspaceShared.hpp" @@ -466,13 +467,9 @@ void Modules::define_module(Handle module, jboolean is_open, jstring version, if (EnableVectorSupport && EnableVectorReboxing && FLAG_IS_DEFAULT(EnableVectorAggressiveReboxing)) { FLAG_SET_DEFAULT(EnableVectorAggressiveReboxing, true); } - if (EnableVectorSupport && FLAG_IS_DEFAULT(UseVectorStubs)) { - FLAG_SET_DEFAULT(UseVectorStubs, true); - } log_info(compilation)("EnableVectorSupport=%s", (EnableVectorSupport ? "true" : "false")); log_info(compilation)("EnableVectorReboxing=%s", (EnableVectorReboxing ? "true" : "false")); log_info(compilation)("EnableVectorAggressiveReboxing=%s", (EnableVectorAggressiveReboxing ? "true" : "false")); - log_info(compilation)("UseVectorStubs=%s", (UseVectorStubs ? "true" : "false")); } #endif // COMPILER2_OR_JVMCI } @@ -493,13 +490,13 @@ void Modules::check_archived_module_oop(oop orig_module_obj) { // java.lang.Module::ALL_UNNAMED_MODULE // java.lang.Module::EVERYONE_MODULE // jdk.internal.loader.ClassLoaders$BootClassLoader::unnamedModule - log_info(cds, module)("Archived java.lang.Module oop " PTR_FORMAT " with no ModuleEntry*", p2i(orig_module_obj)); + log_info(aot, module)("Archived java.lang.Module oop " PTR_FORMAT " with no ModuleEntry*", p2i(orig_module_obj)); assert(java_lang_Module::name(orig_module_obj) == nullptr, "must be unnamed"); } else { // This java.lang.Module oop has an ModuleEntry*. Check if the latter is archived. - if (log_is_enabled(Info, cds, module)) { + if (log_is_enabled(Info, aot, module)) { ResourceMark rm; - LogStream ls(Log(cds, module)::info()); + LogStream ls(Log(aot, module)::info()); ls.print("Archived java.lang.Module oop " PTR_FORMAT " for ", p2i(orig_module_obj)); orig_module_ent->print(&ls); } @@ -580,13 +577,15 @@ class Modules::ArchivedProperty { }; Modules::ArchivedProperty Modules::_archived_props[] = { - // numbered + // non-numbered {"jdk.module.main", false}, - // non-numbered + // numbered {"jdk.module.addexports", true}, // --add-exports {"jdk.module.addmods", true}, // --add-modules {"jdk.module.enable.native.access", true}, // --enable-native-access + {"jdk.module.addopens", true}, // --add-opens + {"jdk.module.addreads", true}, // --add-reads }; constexpr size_t Modules::num_archived_props() { @@ -601,27 +600,27 @@ Modules::ArchivedProperty& Modules::archived_prop(size_t i) { void Modules::ArchivedProperty::runtime_check() const { ResourceMark rm; const char* runtime_value = get_flattened_value(); - log_info(cds)("archived module property %s: %s", _prop, + aot_log_info(aot)("archived module property %s: %s", _prop, _archived_value != nullptr ? _archived_value : "(null)"); bool disable = false; if (runtime_value == nullptr) { if (_archived_value != nullptr) { - log_info(cds)("Mismatched values for property %s: %s specified during dump time but not during runtime", _prop, _archived_value); + MetaspaceShared::report_loading_error("Mismatched values for property %s: %s specified during dump time but not during runtime", _prop, _archived_value); disable = true; } } else { if (_archived_value == nullptr) { - log_info(cds)("Mismatched values for property %s: %s specified during runtime but not during dump time", _prop, runtime_value); + MetaspaceShared::report_loading_error("Mismatched values for property %s: %s specified during runtime but not during dump time", _prop, runtime_value); disable = true; } else if (strcmp(runtime_value, _archived_value) != 0) { - log_info(cds)("Mismatched values for property %s: runtime %s dump time %s", _prop, runtime_value, _archived_value); + MetaspaceShared::report_loading_error("Mismatched values for property %s: runtime %s dump time %s", _prop, runtime_value, _archived_value); disable = true; } } if (disable) { - log_info(cds)("Disabling optimized module handling"); + MetaspaceShared::report_loading_error("Disabling optimized module handling"); CDSConfig::stop_using_optimized_module_handling(); } } @@ -642,8 +641,7 @@ const char* Modules::ArchivedProperty::get_numbered_property_as_sorted_string() if (prop_value == nullptr) { break; } - char* p = resource_allocate_bytes(strlen(prop_value) + 1); - strcpy(p, prop_value); + char* p = ResourceArea::strdup(prop_value); while (*p == ',') p++; // skip leading commas while (*p) { char* next = strchr(p, ','); @@ -695,8 +693,8 @@ void Modules::serialize_archived_module_info(SerializeClosure* soc) { archived_prop(i).serialize(soc); } if (soc->reading()) { - log_info(cds)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); - log_info(cds)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); + aot_log_info(aot)("optimized module handling: %s", CDSConfig::is_using_optimized_module_handling() ? "enabled" : "disabled"); + aot_log_info(aot)("full module graph: %s", CDSConfig::is_using_full_module_graph() ? "enabled" : "disabled"); } } diff --git a/src/hotspot/share/classfile/modules.hpp b/src/hotspot/share/classfile/modules.hpp index 33a5ec77ccb..d6d81263449 100644 --- a/src/hotspot/share/classfile/modules.hpp +++ b/src/hotspot/share/classfile/modules.hpp @@ -29,6 +29,7 @@ #include "runtime/handles.hpp" class ModuleEntryTable; +class SerializeClosure; class Symbol; class Modules : AllStatic { diff --git a/src/hotspot/share/classfile/stackMapFrame.cpp b/src/hotspot/share/classfile/stackMapFrame.cpp index c71a278e0b8..4b847894e02 100644 --- a/src/hotspot/share/classfile/stackMapFrame.cpp +++ b/src/hotspot/share/classfile/stackMapFrame.cpp @@ -337,10 +337,10 @@ TypeOrigin StackMapFrame::stack_top_ctx() { } void StackMapFrame::print_on(outputStream* str) const { - str->indent().print_cr("bci: @%d", _offset); - str->indent().print_cr("flags: {%s }", + str->print_cr("bci: @%d", _offset); + str->print_cr("flags: {%s }", flag_this_uninit() ? " flagThisUninit" : ""); - str->indent().print("locals: {"); + str->print("locals: {"); for (int32_t i = 0; i < _locals_size; ++i) { str->print(" "); _locals[i].print_on(str); @@ -349,7 +349,7 @@ void StackMapFrame::print_on(outputStream* str) const { } } str->print_cr(" }"); - str->indent().print("stack: {"); + str->print("stack: {"); for (int32_t j = 0; j < _stack_size; ++j) { str->print(" "); _stack[j].print_on(str); diff --git a/src/hotspot/share/classfile/stackMapTable.cpp b/src/hotspot/share/classfile/stackMapTable.cpp index b452beecb00..1ed72e998fb 100644 --- a/src/hotspot/share/classfile/stackMapTable.cpp +++ b/src/hotspot/share/classfile/stackMapTable.cpp @@ -143,10 +143,10 @@ void StackMapTable::check_jump_target( } void StackMapTable::print_on(outputStream* str) const { - str->indent().print_cr("StackMapTable: frame_count = %d", _frame_count); - str->indent().print_cr("table = { "); + str->print_cr("StackMapTable: frame_count = %d", _frame_count); + str->print_cr("table = {"); { - streamIndentor si(str); + StreamIndentor si(str, 2); for (int32_t i = 0; i < _frame_count; ++i) { _frame_array->at(i)->print_on(str); } diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index 1076ffb2dd7..a9d05996ebf 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -946,6 +946,8 @@ void StringTable::allocate_shared_strings_array(TRAPS) { if (!CDSConfig::is_dumping_heap()) { return; } + assert(CDSConfig::allow_only_single_java_thread(), "No more interned strings can be added"); + if (_items_count > (size_t)max_jint) { fatal("Too many strings to be archived: %zu", _items_count); } @@ -953,13 +955,13 @@ void StringTable::allocate_shared_strings_array(TRAPS) { int total = (int)_items_count; size_t single_array_size = objArrayOopDesc::object_size(total); - log_info(cds)("allocated string table for %d strings", total); + log_info(aot)("allocated string table for %d strings", total); if (!ArchiveHeapWriter::is_too_large_to_archive(single_array_size)) { // The entire table can fit in a single array objArrayOop array = oopFactory::new_objArray(vmClasses::Object_klass(), total, CHECK); _shared_strings_array = OopHandle(Universe::vm_global(), array); - log_info(cds)("string table array (single level) length = %d", total); + log_info(aot)("string table array (single level) length = %d", total); } else { // Split the table in two levels of arrays. int primary_array_length = (total + _secondary_array_max_length - 1) / _secondary_array_max_length; @@ -970,7 +972,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) { // This can only happen if you have an extremely large number of classes that // refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern // but bail out for safety. - log_error(cds)("Too many strings to be archived: %zu", _items_count); + log_error(aot)("Too many strings to be archived: %zu", _items_count); MetaspaceShared::unrecoverable_writing_error(); } @@ -978,7 +980,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) { objArrayHandle primaryHandle(THREAD, primary); _shared_strings_array = OopHandle(Universe::vm_global(), primary); - log_info(cds)("string table array (primary) length = %d", primary_array_length); + log_info(aot)("string table array (primary) length = %d", primary_array_length); for (int i = 0; i < primary_array_length; i++) { int len; if (total > _secondary_array_max_length) { @@ -991,7 +993,7 @@ void StringTable::allocate_shared_strings_array(TRAPS) { objArrayOop secondary = oopFactory::new_objArray(vmClasses::Object_klass(), len, CHECK); primaryHandle()->obj_at_put(i, secondary); - log_info(cds)("string table array (secondary)[%d] length = %d", i, len); + log_info(aot)("string table array (secondary)[%d] length = %d", i, len); assert(!ArchiveHeapWriter::is_too_large_to_archive(secondary), "sanity"); } @@ -1026,48 +1028,61 @@ void StringTable::verify_secondary_array_index_bits() { // For each shared string: // [1] Store it into _shared_strings_array. Encode its position as a 32-bit index. // [2] Store the index and hashcode into _shared_table. -oop StringTable::init_shared_strings_array(const DumpedInternedStrings* dumped_interned_strings) { +oop StringTable::init_shared_strings_array() { assert(CDSConfig::is_dumping_heap(), "must be"); objArrayOop array = (objArrayOop)(_shared_strings_array.resolve()); verify_secondary_array_index_bits(); int index = 0; - auto copy_into_array = [&] (oop string, bool value_ignored) { - if (!_is_two_dimensional_shared_strings_array) { - assert(index < array->length(), "no strings should have been added"); - array->obj_at_put(index, string); - } else { - int primary_index = index >> _secondary_array_index_bits; - int secondary_index = index & _secondary_array_index_mask; + auto copy_into_array = [&] (WeakHandle* val) { + oop string = val->peek(); + if (string != nullptr && !ArchiveHeapWriter::is_string_too_large_to_archive(string)) { + // If string is too large, don't put it into the string table. + // - If there are no other refernences to it, it won't be stored into the archive, + // so we are all good. + // - If there's a referece to it, we will report an error inside HeapShared.cpp and + // dumping will fail. + HeapShared::add_to_dumped_interned_strings(string); + if (!_is_two_dimensional_shared_strings_array) { + assert(index < array->length(), "no strings should have been added"); + array->obj_at_put(index, string); + } else { + int primary_index = index >> _secondary_array_index_bits; + int secondary_index = index & _secondary_array_index_mask; - assert(primary_index < array->length(), "no strings should have been added"); - objArrayOop secondary = (objArrayOop)array->obj_at(primary_index); + assert(primary_index < array->length(), "no strings should have been added"); + objArrayOop secondary = (objArrayOop)array->obj_at(primary_index); - assert(secondary != nullptr && secondary->is_objArray(), "must be"); - assert(secondary_index < secondary->length(), "no strings should have been added"); - secondary->obj_at_put(secondary_index, string); + assert(secondary != nullptr && secondary->is_objArray(), "must be"); + assert(secondary_index < secondary->length(), "no strings should have been added"); + secondary->obj_at_put(secondary_index, string); + } + index ++; } - - index ++; + return true; }; - dumped_interned_strings->iterate_all(copy_into_array); + _local_table->do_safepoint_scan(copy_into_array); + log_info(aot)("Archived %d interned strings", index); return array; -} +}; -void StringTable::write_shared_table(const DumpedInternedStrings* dumped_interned_strings) { +void StringTable::write_shared_table() { _shared_table.reset(); CompactHashtableWriter writer((int)_items_count, ArchiveBuilder::string_stats()); int index = 0; - auto copy_into_shared_table = [&] (oop string, bool value_ignored) { - unsigned int hash = java_lang_String::hash_code(string); - writer.add(hash, index); - index ++; + auto copy_into_shared_table = [&] (WeakHandle* val) { + oop string = val->peek(); + if (string != nullptr && !ArchiveHeapWriter::is_string_too_large_to_archive(string)) { + unsigned int hash = java_lang_String::hash_code(string); + writer.add(hash, index); + index ++; + } + return true; }; - dumped_interned_strings->iterate_all(copy_into_shared_table); - + _local_table->do_safepoint_scan(copy_into_shared_table); writer.dump(&_shared_table, "string"); } diff --git a/src/hotspot/share/classfile/stringTable.hpp b/src/hotspot/share/classfile/stringTable.hpp index 15539009f66..bf7bb9e2cd9 100644 --- a/src/hotspot/share/classfile/stringTable.hpp +++ b/src/hotspot/share/classfile/stringTable.hpp @@ -33,7 +33,6 @@ #include "utilities/tableStatistics.hpp" class CompactHashtableWriter; -class DumpedInternedStrings; class JavaThread; class SerializeClosure; @@ -147,8 +146,8 @@ class StringTable : AllStatic { static oop lookup_shared(const jchar* name, int len) NOT_CDS_JAVA_HEAP_RETURN_(nullptr); static size_t shared_entry_count() NOT_CDS_JAVA_HEAP_RETURN_(0); static void allocate_shared_strings_array(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; - static oop init_shared_strings_array(const DumpedInternedStrings* dumped_interned_strings) NOT_CDS_JAVA_HEAP_RETURN_(nullptr); - static void write_shared_table(const DumpedInternedStrings* dumped_interned_strings) NOT_CDS_JAVA_HEAP_RETURN; + static oop init_shared_strings_array() NOT_CDS_JAVA_HEAP_RETURN_(nullptr); + static void write_shared_table() NOT_CDS_JAVA_HEAP_RETURN; static void set_shared_strings_array_index(int root_index) NOT_CDS_JAVA_HEAP_RETURN; static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index 1fd28a1d4e9..e6889e6248d 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -88,13 +88,9 @@ 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. +// are updating "lookup success history" in a global shared variable, so use built-in TLS static THREAD_LOCAL bool _lookup_shared_first = false; -#endif // Static arena for symbols that are not deallocated Arena* SymbolTable::_arena = nullptr; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 0ef4f0dcd18..b1abb2ab0fe 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -923,15 +923,15 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name, // (1) Check if we are loading into the same loader as in dump time. - if (ik->is_shared_boot_class()) { + if (ik->defined_by_boot_loader()) { if (class_loader() != nullptr) { return false; } - } else if (ik->is_shared_platform_class()) { + } else if (ik->defined_by_platform_loader()) { if (class_loader() != java_platform_loader()) { return false; } - } else if (ik->is_shared_app_class()) { + } else if (ik->defined_by_app_loader()) { if (class_loader() != java_system_loader()) { return false; } @@ -961,7 +961,7 @@ bool SystemDictionary::is_shared_class_visible_impl(Symbol* class_name, PackageEntry* pkg_entry, Handle class_loader) { int scp_index = ik->shared_classpath_index(); - assert(!ik->is_shared_unregistered_class(), "this function should be called for built-in classes only"); + assert(!ik->defined_by_other_loaders(), "this function should be called for built-in classes only"); assert(scp_index >= 0, "must be"); const AOTClassLocation* cl = AOTClassLocationConfig::runtime()->class_location_at(scp_index); if (!Universe::is_module_initialized()) { @@ -1023,7 +1023,7 @@ bool SystemDictionary::check_shared_class_super_type(InstanceKlass* klass, Insta // + Don't do it for unregistered classes -- they can be unloaded so // super_type->class_loader_data() could be stale. // + Don't check if loader data is null, ie. the super_type isn't fully loaded. - if (!super_type->is_shared_unregistered_class() && super_type->class_loader_data() != nullptr) { + if (!super_type->defined_by_other_loaders() && super_type->class_loader_data() != nullptr) { // Check if the superclass is loaded by the current class_loader Symbol* name = super_type->name(); InstanceKlass* check = find_instance_klass(THREAD, name, class_loader); @@ -1226,7 +1226,7 @@ InstanceKlass* SystemDictionary::load_instance_class_impl(Symbol* class_name, Ha { PerfTraceTime vmtimer(ClassLoader::perf_shared_classload_time()); InstanceKlass* ik = SystemDictionaryShared::find_builtin_class(class_name); - if (ik != nullptr && ik->is_shared_boot_class() && !ik->shared_loading_failed()) { + if (ik != nullptr && ik->defined_by_boot_loader() && !ik->shared_loading_failed()) { SharedClassLoadingMark slm(THREAD, ik); k = load_shared_class(ik, class_loader, Handle(), nullptr, pkg_entry, CHECK_NULL); } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 5c4ee3f9452..8bd09a0d947 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -24,6 +24,7 @@ #include "cds/aotClassFilter.hpp" #include "cds/aotClassLocation.hpp" +#include "cds/aotLogging.hpp" #include "cds/archiveBuilder.hpp" #include "cds/archiveUtils.hpp" #include "cds/cdsConfig.hpp" @@ -102,8 +103,8 @@ InstanceKlass* SystemDictionaryShared::load_shared_class_for_builtin_loader( InstanceKlass* ik = find_builtin_class(class_name); if (ik != nullptr && !ik->shared_loading_failed()) { - if ((SystemDictionary::is_system_class_loader(class_loader()) && ik->is_shared_app_class()) || - (SystemDictionary::is_platform_class_loader(class_loader()) && ik->is_shared_platform_class())) { + if ((SystemDictionary::is_system_class_loader(class_loader()) && ik->defined_by_app_loader()) || + (SystemDictionary::is_platform_class_loader(class_loader()) && ik->defined_by_platform_loader())) { SharedClassLoadingMark slm(THREAD, ik); PackageEntry* pkg_entry = CDSProtectionDomain::get_package_entry_from_class(ik, class_loader); Handle protection_domain = @@ -229,7 +230,7 @@ bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClass // Returns true so the caller can do: return warn_excluded("....."); bool SystemDictionaryShared::warn_excluded(InstanceKlass* k, const char* reason) { ResourceMark rm; - log_warning(cds)("Skipping %s: %s", k->name()->as_C_string(), reason); + aot_log_warning(aot)("Skipping %s: %s", k->name()->as_C_string(), reason); return true; } @@ -249,7 +250,7 @@ bool SystemDictionaryShared::is_early_klass(InstanceKlass* ik) { } bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { - if (CDSConfig::is_dumping_final_static_archive() && k->is_shared_unregistered_class() + if (CDSConfig::is_dumping_final_static_archive() && k->defined_by_other_loaders() && k->is_shared()) { return false; // Do not exclude: unregistered classes are passed from preimage to final image. } @@ -273,7 +274,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { k->set_shared_classpath_index(0); } else { ResourceMark rm; - log_info(cds)("Skipping %s because it is dynamically generated", k->name()->as_C_string()); + aot_log_info(aot)("Skipping %s because it is dynamically generated", k->name()->as_C_string()); return true; // exclude without warning } } else { @@ -308,7 +309,7 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { return warn_excluded(k, "Unlinked class not supported by AOTClassLinking"); } else if (CDSConfig::is_dumping_preimage_static_archive()) { // When dumping the final static archive, we will unconditionally load and link all - // classes from tje preimage. We don't want to get a VerifyError when linking this class. + // classes from the preimage. We don't want to get a VerifyError when linking this class. return warn_excluded(k, "Unlinked class not supported by AOTConfiguration"); } } else { @@ -323,10 +324,16 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { } } + if (UnregisteredClasses::check_for_exclusion(k)) { + ResourceMark rm; + aot_log_info(aot)("Skipping %s: used only when dumping CDS archive", k->name()->as_C_string()); + return true; + } + InstanceKlass* super = k->java_super(); if (super != nullptr && check_for_exclusion(super, nullptr)) { ResourceMark rm; - log_warning(cds)("Skipping %s: super class %s is excluded", k->name()->as_C_string(), super->name()->as_C_string()); + aot_log_warning(aot)("Skipping %s: super class %s is excluded", k->name()->as_C_string(), super->name()->as_C_string()); return true; } @@ -336,17 +343,11 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) { InstanceKlass* intf = interfaces->at(i); if (check_for_exclusion(intf, nullptr)) { ResourceMark rm; - log_warning(cds)("Skipping %s: interface %s is excluded", k->name()->as_C_string(), intf->name()->as_C_string()); + aot_log_warning(aot)("Skipping %s: interface %s is excluded", k->name()->as_C_string(), intf->name()->as_C_string()); return true; } } - if (k == UnregisteredClasses::UnregisteredClassLoader_klass()) { - ResourceMark rm; - log_info(cds)("Skipping %s: used only when dumping CDS archive", k->name()->as_C_string()); - return true; - } - return false; // false == k should NOT be excluded } @@ -465,6 +466,15 @@ bool SystemDictionaryShared::add_unregistered_class(Thread* current, InstanceKla return (klass == *v); } +InstanceKlass* SystemDictionaryShared::get_unregistered_class(Symbol* name) { + assert(CDSConfig::is_dumping_archive() || ClassListWriter::is_enabled(), "sanity"); + if (_unregistered_classes_table == nullptr) { + return nullptr; + } + InstanceKlass** k = _unregistered_classes_table->get(name); + return k != nullptr ? *k : nullptr; +} + void SystemDictionaryShared::copy_unregistered_class_size_and_crc32(InstanceKlass* klass) { precond(CDSConfig::is_dumping_final_static_archive()); precond(klass->is_shared()); @@ -582,11 +592,11 @@ void SystemDictionaryShared::validate_before_archiving(InstanceKlass* k) { assert(LambdaProxyClassDictionary::is_registered_lambda_proxy_class(k), "unexpected hidden class %s", name); } } - guarantee(!k->is_shared_unregistered_class(), + guarantee(!k->defined_by_other_loaders(), "Class loader type must be set for BUILTIN class %s", name); } else { - guarantee(k->is_shared_unregistered_class(), + guarantee(k->defined_by_other_loaders(), "Class loader type must not be set for UNREGISTERED class %s", name); } } @@ -649,6 +659,11 @@ bool SystemDictionaryShared::should_be_excluded(Klass* k) { } else { InstanceKlass* ik = InstanceKlass::cast(k); + if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared()) { + // ik is already part of the static archive, so it will never be considered as excluded. + return false; + } + if (!SafepointSynchronize::is_at_safepoint()) { if (!ik->is_linked()) { // check_for_exclusion() below doesn't link unlinked classes. We come @@ -734,12 +749,17 @@ bool SystemDictionaryShared::has_class_failed_verification(InstanceKlass* ik) { return (p == nullptr) ? false : p->failed_verification(); } +void SystemDictionaryShared::set_from_class_file_load_hook(InstanceKlass* ik) { + warn_excluded(ik, "From ClassFileLoadHook"); + set_excluded(ik); +} + void SystemDictionaryShared::dumptime_classes_do(MetaspaceClosure* it) { assert_lock_strong(DumpTimeTable_lock); auto do_klass = [&] (InstanceKlass* k, DumpTimeClassInfo& info) { if (CDSConfig::is_dumping_final_static_archive() && !k->is_loaded()) { - assert(k->is_shared_unregistered_class(), "must be"); + assert(k->defined_by_other_loaders(), "must be"); info.metaspace_pointers_do(it); } else if (k->is_loader_alive() && !info.is_excluded()) { info.metaspace_pointers_do(it); @@ -752,29 +772,43 @@ void SystemDictionaryShared::dumptime_classes_do(MetaspaceClosure* it) { } } -bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name, - Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) { +// Called from VerificationType::is_reference_assignable_from() before performing the assignability check of +// T1 must be assignable from T2 +// Where: +// L is the class loader of +// T1 is the type resolved by L using the name +// T2 is the type resolved by L using the name +// +// The meaning of (*skip_assignability_check): +// true: is_reference_assignable_from() should SKIP the assignability check +// false: is_reference_assignable_from() should COMPLETE the assignability check +void SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name, + Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object, + bool* skip_assignability_check) { assert(CDSConfig::is_dumping_archive(), "sanity"); DumpTimeClassInfo* info = get_info(k); info->add_verification_constraint(k, name, from_name, from_field_is_protected, from_is_array, from_is_object); - if (CDSConfig::is_dumping_dynamic_archive()) { - // For dynamic dumping, we can resolve all the constraint classes for all class loaders during - // the initial run prior to creating the archive before vm exit. We will also perform verification - // check when running with the archive. - return false; + if (CDSConfig::is_dumping_classic_static_archive() && !is_builtin(k)) { + // This applies ONLY to the "classic" CDS static dump, which reads the list of + // unregistered classes (those intended for custom class loaders) from the classlist + // and loads them using jdk.internal.misc.CDS$UnregisteredClassLoader. + // + // When the classlist contains an unregistered class k, the supertypes of k are also + // recorded in the classlist. However, the classlist does not contain information about + // any class X that's not a supertype of k but is needed in the verification of k. + // As a result, CDS$UnregisteredClassLoader will not know how to resolve X. + // + // Therefore, we tell the verifier to refrain from resolving X. Instead, X is recorded + // (symbolically) in the verification constraints of k. In the production run, + // when k is loaded, we will go through its verification constraints and resolve X to complete + // the is_reference_assignable_from() checks. + *skip_assignability_check = true; } else { - if (is_builtin(k)) { - // For builtin class loaders, we can try to complete the verification check at dump time, - // because we can resolve all the constraint classes. We will also perform verification check - // when running with the archive. - return false; - } else { - // For non-builtin class loaders, we cannot complete the verification check at dump time, - // because at dump time we don't know how to resolve classes for such loaders. - return true; - } + // In all other cases, we are using an *actual* class loader to load k, so it should be able + // to resolve any types that are needed for the verification of k. + *skip_assignability_check = false; } } @@ -796,9 +830,9 @@ void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass Symbol* name = vc->name(); Symbol* from_name = vc->from_name(); - if (log_is_enabled(Trace, cds, verification)) { + if (log_is_enabled(Trace, aot, verification)) { ResourceMark rm(THREAD); - log_trace(cds, verification)("check_verification_constraint: %s: %s must be subclass of %s [0x%x]", + log_trace(aot, verification)("check_verification_constraint: %s: %s must be subclass of %s [0x%x]", klass->external_name(), from_name->as_klass_external_name(), name->as_klass_external_name(), record->verifier_constraint_flag(i)); } @@ -911,11 +945,11 @@ void SystemDictionaryShared::record_linking_constraint(Symbol* name, InstanceKla bool SystemDictionaryShared::check_linking_constraints(Thread* current, InstanceKlass* klass) { assert(CDSConfig::is_using_archive(), "called at run time with CDS enabled only"); LogTarget(Info, class, loader, constraints) log; - if (klass->is_shared_boot_class()) { + if (klass->defined_by_boot_loader()) { // No class loader constraint check performed for boot classes. return true; } - if (klass->is_shared_platform_class() || klass->is_shared_app_class()) { + if (klass->defined_by_platform_loader() || klass->defined_by_app_loader()) { RunTimeClassInfo* info = RunTimeClassInfo::get_for(klass); assert(info != nullptr, "Sanity"); if (info->num_loader_constraints() > 0) { @@ -958,7 +992,7 @@ bool SystemDictionaryShared::check_linking_constraints(Thread* current, Instance void SystemDictionaryShared::copy_linking_constraints_from_preimage(InstanceKlass* klass) { assert(CDSConfig::is_using_archive(), "called at run time with CDS enabled only"); JavaThread* current = JavaThread::current(); - if (klass->is_shared_platform_class() || klass->is_shared_app_class()) { + if (klass->defined_by_platform_loader() || klass->defined_by_app_loader()) { RunTimeClassInfo* rt_info = RunTimeClassInfo::get_for(klass); // from preimage if (rt_info->num_loader_constraints() > 0) { @@ -974,7 +1008,7 @@ void SystemDictionaryShared::copy_linking_constraints_from_preimage(InstanceKlas } unsigned int SystemDictionaryShared::hash_for_shared_dictionary(address ptr) { - if (ArchiveBuilder::is_active()) { + if (ArchiveBuilder::is_active() && ArchiveBuilder::current()->is_in_buffer_space(ptr)) { uintx offset = ArchiveBuilder::current()->any_to_offset(ptr); unsigned int hash = primitive_hash(offset); DEBUG_ONLY({ @@ -1014,9 +1048,9 @@ class CopySharedClassInfoToArchive : StackObj { } else { _writer->add(hash, delta); } - if (log_is_enabled(Trace, cds, hashtables)) { + if (log_is_enabled(Trace, aot, hashtables)) { ResourceMark rm; - log_trace(cds,hashtables)("%s dictionary: %s", (_is_builtin ? "builtin" : "unregistered"), info._klass->external_name()); + log_trace(aot, hashtables)("%s dictionary: %s", (_is_builtin ? "builtin" : "unregistered"), info._klass->external_name()); } // Save this for quick runtime lookup of InstanceKlass* -> RunTimeClassInfo* @@ -1126,13 +1160,13 @@ const char* SystemDictionaryShared::loader_type_for_shared_class(Klass* k) { assert(k->is_shared(), "Must be"); assert(k->is_instance_klass(), "Must be"); InstanceKlass* ik = InstanceKlass::cast(k); - if (ik->is_shared_boot_class()) { + if (ik->defined_by_boot_loader()) { return "boot_loader"; - } else if (ik->is_shared_platform_class()) { + } else if (ik->defined_by_platform_loader()) { return "platform_loader"; - } else if (ik->is_shared_app_class()) { + } else if (ik->defined_by_app_loader()) { return "app_loader"; - } else if (ik->is_shared_unregistered_class()) { + } else if (ik->defined_by_other_loaders()) { return "unregistered_loader"; } else { return "unknown loader"; diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index 22fc3fd825d..4343bd5f0e8 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -233,9 +233,10 @@ class SystemDictionaryShared: public SystemDictionary { // ensures that you cannot load a shared class if its super type(s) are changed. However, // we need an additional check to ensure that the verification_constraints did not change // between dump time and runtime. - static bool add_verification_constraint(InstanceKlass* k, Symbol* name, + static void add_verification_constraint(InstanceKlass* k, Symbol* name, Symbol* from_name, bool from_field_is_protected, - bool from_is_array, bool from_is_object) NOT_CDS_RETURN_(false); + bool from_is_array, bool from_is_object, + bool* skip_assignability_check); static void check_verification_constraints(InstanceKlass* klass, TRAPS) NOT_CDS_RETURN; static void add_enum_klass_static_field(InstanceKlass* ik, int root_index); @@ -248,6 +249,7 @@ class SystemDictionaryShared: public SystemDictionary { return (k->shared_classpath_index() != UNREGISTERED_INDEX); } static bool add_unregistered_class(Thread* current, InstanceKlass* k); + static InstanceKlass* get_unregistered_class(Symbol* name); static void copy_unregistered_class_size_and_crc32(InstanceKlass* klass); static void finish_exclusion_checks(); @@ -259,6 +261,7 @@ class SystemDictionaryShared: public SystemDictionary { static bool is_excluded_class(InstanceKlass* k); static void set_excluded(InstanceKlass* k); static void set_excluded_locked(InstanceKlass* k); + static void set_from_class_file_load_hook(InstanceKlass* k) NOT_CDS_RETURN; static bool warn_excluded(InstanceKlass* k, const char* reason); static void dumptime_classes_do(class MetaspaceClosure* it); static void write_to_archive(bool is_static_archive = true); diff --git a/src/hotspot/share/classfile/verificationType.cpp b/src/hotspot/share/classfile/verificationType.cpp index d0541a0d20f..aedb620aabe 100644 --- a/src/hotspot/share/classfile/verificationType.cpp +++ b/src/hotspot/share/classfile/verificationType.cpp @@ -48,41 +48,50 @@ VerificationType VerificationType::from_tag(u1 tag) { } } -bool VerificationType::resolve_and_check_assignability(InstanceKlass* klass, Symbol* name, - Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object, TRAPS) { +// Potentially resolve the target class and from class, and check whether the from class is assignable +// to the target class. The current_klass is the class being verified - it could also be the target in some +// cases, and otherwise is needed to obtain the correct classloader for resolving the other classes. +bool VerificationType::resolve_and_check_assignability(InstanceKlass* current_klass, Symbol* target_name, Symbol* from_name, + bool from_field_is_protected, bool from_is_array, + bool from_is_object, bool* target_is_interface, TRAPS) { HandleMark hm(THREAD); - Klass* this_class; - if (klass->is_hidden() && klass->name() == name) { - this_class = klass; + Klass* target_klass; + if (current_klass->is_hidden() && current_klass->name() == target_name) { + target_klass = current_klass; } else { - this_class = SystemDictionary::resolve_or_fail( - name, Handle(THREAD, klass->class_loader()), true, CHECK_false); + target_klass = SystemDictionary::resolve_or_fail( + target_name, Handle(THREAD, current_klass->class_loader()), true, CHECK_false); if (log_is_enabled(Debug, class, resolve)) { - Verifier::trace_class_resolution(this_class, klass); + Verifier::trace_class_resolution(target_klass, current_klass); } } - if (this_class->is_interface() && (!from_field_is_protected || + bool is_intf = target_klass->is_interface(); + if (target_is_interface != nullptr) { + *target_is_interface = is_intf; + } + + if (is_intf && (!from_field_is_protected || from_name != vmSymbols::java_lang_Object())) { // If we are not trying to access a protected field or method in // java.lang.Object then, for arrays, we only allow assignability // to interfaces java.lang.Cloneable and java.io.Serializable. // Otherwise, we treat interfaces as java.lang.Object. return !from_is_array || - this_class == vmClasses::Cloneable_klass() || - this_class == vmClasses::Serializable_klass(); + target_klass == vmClasses::Cloneable_klass() || + target_klass == vmClasses::Serializable_klass(); } else if (from_is_object) { - Klass* from_class; - if (klass->is_hidden() && klass->name() == from_name) { - from_class = klass; + Klass* from_klass; + if (current_klass->is_hidden() && current_klass->name() == from_name) { + from_klass = current_klass; } else { - from_class = SystemDictionary::resolve_or_fail( - from_name, Handle(THREAD, klass->class_loader()), true, CHECK_false); + from_klass = SystemDictionary::resolve_or_fail( + from_name, Handle(THREAD, current_klass->class_loader()), true, CHECK_false); if (log_is_enabled(Debug, class, resolve)) { - Verifier::trace_class_resolution(from_class, klass); + Verifier::trace_class_resolution(from_klass, current_klass); } } - return from_class->is_subclass_of(this_class); + return from_klass->is_subclass_of(target_klass); } return false; @@ -90,8 +99,8 @@ bool VerificationType::resolve_and_check_assignability(InstanceKlass* klass, Sym bool VerificationType::is_reference_assignable_from( const VerificationType& from, ClassVerifier* context, - bool from_field_is_protected, TRAPS) const { - InstanceKlass* klass = context->current_class(); + bool from_field_is_protected, bool* this_is_interface, TRAPS) const { + if (from.is_null()) { // null is assignable to any reference return true; @@ -106,18 +115,22 @@ bool VerificationType::is_reference_assignable_from( return true; } +#if INCLUDE_CDS if (CDSConfig::is_dumping_archive()) { - if (SystemDictionaryShared::add_verification_constraint(klass, + bool skip_assignability_check = false; + SystemDictionaryShared::add_verification_constraint(context->current_class(), name(), from.name(), from_field_is_protected, from.is_array(), - from.is_object())) { - // If add_verification_constraint() returns true, the resolution/check should be - // delayed until runtime. + from.is_object(), &skip_assignability_check); + if (skip_assignability_check) { + // We are not able to resolve name() or from.name(). The actual assignability check + // will be delayed until runtime. return true; } } - - return resolve_and_check_assignability(klass, name(), from.name(), - from_field_is_protected, from.is_array(), from.is_object(), THREAD); +#endif + return resolve_and_check_assignability(context->current_class(), name(), from.name(), + from_field_is_protected, from.is_array(), + from.is_object(), this_is_interface, THREAD); } else if (is_array() && from.is_array()) { VerificationType comp_this = get_component(context); VerificationType comp_from = from.get_component(context); diff --git a/src/hotspot/share/classfile/verificationType.hpp b/src/hotspot/share/classfile/verificationType.hpp index 4f0609f0cce..788e0029fad 100644 --- a/src/hotspot/share/classfile/verificationType.hpp +++ b/src/hotspot/share/classfile/verificationType.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -288,7 +288,7 @@ class VerificationType { if (is_reference() && from.is_reference()) { return is_reference_assignable_from(from, context, from_field_is_protected, - THREAD); + nullptr, THREAD); } else { return false; } @@ -327,17 +327,24 @@ class VerificationType { void print_on(outputStream* st) const; - private: + bool is_reference_assignable_from(const VerificationType& from, ClassVerifier* context, + bool from_field_is_protected, bool* this_is_interface, TRAPS) const; - bool is_reference_assignable_from( - const VerificationType&, ClassVerifier*, bool from_field_is_protected, - TRAPS) const; + static bool resolve_and_check_assignability(InstanceKlass* current_klass, Symbol* target_name, + Symbol* from_name, bool from_field_is_protected, + bool from_is_array, bool from_is_object, + TRAPS) { + return resolve_and_check_assignability(current_klass, target_name, from_name, from_field_is_protected, + from_is_array, from_is_object, nullptr, THREAD); + } - public: - static bool resolve_and_check_assignability(InstanceKlass* klass, Symbol* name, + private: + static bool resolve_and_check_assignability(InstanceKlass* current_klass, Symbol* target_name, Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object, + bool* target_is_interface, TRAPS); + }; #endif // SHARE_CLASSFILE_VERIFICATIONTYPE_HPP diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index d8f9b8589ef..0f1468f0309 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -223,12 +223,9 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) { split_verifier.verify_class(THREAD); exception_name = split_verifier.result(); - // If dumping static archive then don't fall back to the old verifier on - // verification failure. If a class fails verification with the split verifier, - // it might fail the CDS runtime verifier constraint check. In that case, we - // don't want to share the class. We only archive classes that pass the split - // verifier. - bool can_failover = !CDSConfig::is_dumping_static_archive() && + // If dumping {classic, final} static archive, don't bother to run the old verifier, as + // the class will be excluded from the archive anyway. + bool can_failover = !(CDSConfig::is_dumping_classic_static_archive() || CDSConfig::is_dumping_final_static_archive()) && klass->major_version() < NOFAILOVER_MAJOR_VERSION; if (can_failover && !HAS_PENDING_EXCEPTION && // Split verifier doesn't set PENDING_EXCEPTION for failure @@ -237,9 +234,10 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) { log_info(verification)("Fail over class verification to old verifier for: %s", klass->external_name()); log_info(class, init)("Fail over class verification to old verifier for: %s", klass->external_name()); #if INCLUDE_CDS - // Exclude any classes that fail over during dynamic dumping - if (CDSConfig::is_dumping_dynamic_archive()) { - SystemDictionaryShared::warn_excluded(klass, "Failed over class verification while dynamic dumping"); + // Exclude any classes that are verified with the old verifier, as the old verifier + // doesn't call SystemDictionaryShared::add_verification_constraint() + if (CDSConfig::is_dumping_archive()) { + SystemDictionaryShared::warn_excluded(klass, "Verified with old verifier"); SystemDictionaryShared::set_excluded(klass); } #endif @@ -446,10 +444,10 @@ void ErrorContext::details(outputStream* ss, const Method* method) const { } void ErrorContext::reason_details(outputStream* ss) const { - streamIndentor si(ss); - ss->indent().print_cr("Reason:"); - streamIndentor si2(ss); - ss->indent().print("%s", ""); + StreamIndentor si(ss, 2); + ss->print_cr("Reason:"); + + StreamIndentor si2(ss, 2); switch (_fault) { case INVALID_BYTECODE: ss->print("Error exists in the bytecode"); @@ -507,7 +505,6 @@ void ErrorContext::reason_details(outputStream* ss) const { void ErrorContext::location_details(outputStream* ss, const Method* method) const { if (_bci != -1 && method != nullptr) { - streamIndentor si(ss); const char* bytecode_name = ""; if (method->validate_bci(_bci) != -1) { Bytecodes::Code code = Bytecodes::code_or_bp_at(method->bcp_from(_bci)); @@ -518,46 +515,50 @@ void ErrorContext::location_details(outputStream* ss, const Method* method) cons } } InstanceKlass* ik = method->method_holder(); - ss->indent().print_cr("Location:"); - streamIndentor si2(ss); - ss->indent().print_cr("%s.%s%s @%d: %s", + + StreamIndentor si(ss, 2); + ss->print_cr("Location:"); + + StreamIndentor si2(ss, 2); + ss->print_cr("%s.%s%s @%d: %s", ik->name()->as_C_string(), method->name()->as_C_string(), method->signature()->as_C_string(), _bci, bytecode_name); } } void ErrorContext::frame_details(outputStream* ss) const { - streamIndentor si(ss); + StreamIndentor si(ss, 2); if (_type.is_valid() && _type.frame() != nullptr) { - ss->indent().print_cr("Current Frame:"); - streamIndentor si2(ss); + ss->print_cr("Current Frame:"); + StreamIndentor si2(ss, 2); _type.frame()->print_on(ss); } if (_expected.is_valid() && _expected.frame() != nullptr) { - ss->indent().print_cr("Stackmap Frame:"); - streamIndentor si2(ss); + ss->print_cr("Stackmap Frame:"); + StreamIndentor si2(ss, 2); _expected.frame()->print_on(ss); } } void ErrorContext::bytecode_details(outputStream* ss, const Method* method) const { if (method != nullptr) { - streamIndentor si(ss); - ss->indent().print_cr("Bytecode:"); - streamIndentor si2(ss); + StreamIndentor si(ss, 2); + ss->print_cr("Bytecode:"); + StreamIndentor si2(ss, 2); ss->print_data(method->code_base(), method->code_size(), false); } } void ErrorContext::handler_details(outputStream* ss, const Method* method) const { if (method != nullptr) { - streamIndentor si(ss); + StreamIndentor si(ss, 2); + ExceptionTable table(method); if (table.length() > 0) { - ss->indent().print_cr("Exception Handler Table:"); - streamIndentor si2(ss); + ss->print_cr("Exception Handler Table:"); + StreamIndentor si2(ss, 2); for (int i = 0; i < table.length(); ++i) { - ss->indent().print_cr("bci [%d, %d] => handler: %d", table.start_pc(i), + ss->print_cr("bci [%d, %d] => handler: %d", table.start_pc(i), table.end_pc(i), table.handler_pc(i)); } } @@ -566,17 +567,16 @@ void ErrorContext::handler_details(outputStream* ss, const Method* method) const void ErrorContext::stackmap_details(outputStream* ss, const Method* method) const { if (method != nullptr && method->has_stackmap_table()) { - streamIndentor si(ss); - ss->indent().print_cr("Stackmap Table:"); + StreamIndentor si(ss, 2); + ss->print_cr("Stackmap Table:"); Array* data = method->stackmap_data(); stack_map_table* sm_table = stack_map_table::at((address)data->adr_at(0)); stack_map_frame* sm_frame = sm_table->entries(); - streamIndentor si2(ss); + StreamIndentor si2(ss, 2); int current_offset = -1; address end_of_sm_table = (address)sm_table + method->stackmap_data()->length(); for (u2 i = 0; i < sm_table->number_of_entries(); ++i) { - ss->indent(); if (!sm_frame->verify((address)sm_frame, end_of_sm_table)) { sm_frame->print_truncated(ss, current_offset); return; @@ -2891,26 +2891,43 @@ void ClassVerifier::verify_invoke_instructions( "Illegal call to internal method"); return; } - } else if (opcode == Bytecodes::_invokespecial - && !is_same_or_direct_interface(current_class(), current_type(), ref_class_type) - && !ref_class_type.equals(VerificationType::reference_type( - current_class()->super()->name()))) { - bool subtype = false; - bool have_imr_indirect = cp->tag_at(index).value() == JVM_CONSTANT_InterfaceMethodref; - subtype = ref_class_type.is_assignable_from( - current_type(), this, false, CHECK_VERIFY(this)); - if (!subtype) { - verify_error(ErrorContext::bad_code(bci), - "Bad invokespecial instruction: " - "current class isn't assignable to reference class."); - return; - } else if (have_imr_indirect) { + } + // invokespecial, when not , must be to a method in the current class, a direct superinterface, + // or any superclass (including Object). + else if (opcode == Bytecodes::_invokespecial + && !is_same_or_direct_interface(current_class(), current_type(), ref_class_type) + && !ref_class_type.equals(VerificationType::reference_type(current_class()->super()->name()))) { + + // We know it is not current class, direct superinterface or immediate superclass. That means it + // could be: + // - a totally unrelated class or interface + // - an indirect superinterface + // - an indirect superclass (including Object) + // We use the assignability test to see if it is a superclass, or else an interface, and keep track + // of the latter. Note that subtype can be true if we are dealing with an interface that is not actually + // implemented as assignability treats all interfaces as Object. + + bool is_interface = false; // This can only be set true if the assignability check will return true + // and we loaded the class. For any other "true" returns (e.g. same class + // or Object) we either can't get here (same class already excluded above) + // or we know it is not an interface (i.e. Object). + bool subtype = ref_class_type.is_reference_assignable_from(current_type(), this, false, + &is_interface, CHECK_VERIFY(this)); + if (!subtype) { // Totally unrelated class verify_error(ErrorContext::bad_code(bci), - "Bad invokespecial instruction: " - "interface method reference is in an indirect superinterface."); + "Bad invokespecial instruction: " + "current class isn't assignable to reference class."); return; + } else { + // Indirect superclass (including Object), indirect interface, or unrelated interface. + // Any interface use is an error. + if (is_interface) { + verify_error(ErrorContext::bad_code(bci), + "Bad invokespecial instruction: " + "interface method to invoke is not in a direct superinterface."); + return; + } } - } // Get the verification types for the method's arguments. diff --git a/src/hotspot/share/classfile/vmClassMacros.hpp b/src/hotspot/share/classfile/vmClassMacros.hpp index 351b9b0b53f..1edc13054d4 100644 --- a/src/hotspot/share/classfile/vmClassMacros.hpp +++ b/src/hotspot/share/classfile/vmClassMacros.hpp @@ -114,6 +114,7 @@ do_klass(VarHandle_klass, java_lang_invoke_VarHandle ) \ do_klass(MemberName_klass, java_lang_invoke_MemberName ) \ do_klass(ResolvedMethodName_klass, java_lang_invoke_ResolvedMethodName ) \ + do_klass(MethodHandleImpl_klass, java_lang_invoke_MethodHandleImpl ) \ do_klass(MethodHandleNatives_klass, java_lang_invoke_MethodHandleNatives ) \ do_klass(LambdaForm_klass, java_lang_invoke_LambdaForm ) \ do_klass(MethodType_klass, java_lang_invoke_MethodType ) \ diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index ac359d4cacb..813926e51a2 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -81,7 +81,7 @@ bool vmClasses::resolve(vmClassID id, TRAPS) { #if INCLUDE_CDS if (CDSConfig::is_using_archive() && !JvmtiExport::should_post_class_prepare()) { InstanceKlass* k = *klassp; - assert(k->is_shared_boot_class(), "must be"); + assert(k->defined_by_boot_loader(), "must be"); ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data(); resolve_shared_class(k, loader_data, Handle(), CHECK_false); diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index e23720f3ae0..6fd5c07e137 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -92,6 +92,7 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) { case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: case vmIntrinsics::_dtanh: + case vmIntrinsics::_dcbrt: case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: case vmIntrinsics::_dexp: @@ -144,6 +145,7 @@ bool vmIntrinsics::can_trap(vmIntrinsics::ID id) { case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: case vmIntrinsics::_dtanh: + case vmIntrinsics::_dcbrt: case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: case vmIntrinsics::_dexp: @@ -288,6 +290,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: case vmIntrinsics::_dtanh: + case vmIntrinsics::_dcbrt: case vmIntrinsics::_dlog: case vmIntrinsics::_dexp: case vmIntrinsics::_dpow: @@ -496,6 +499,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_kyber12To16: case vmIntrinsics::_kyberBarrettReduce: if (!UseKyberIntrinsics) return true; + break; case vmIntrinsics::_dilithiumAlmostNtt: case vmIntrinsics::_dilithiumAlmostInverseNtt: case vmIntrinsics::_dilithiumNttMult: diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 68de40f1788..eeefddfedfc 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -135,7 +135,7 @@ class methodHandle; do_name(log_name,"log") do_name(log10_name,"log10") do_name(pow_name,"pow") \ do_name(exp_name,"exp") do_name(min_name,"min") do_name(max_name,"max") \ do_name(floor_name, "floor") do_name(ceil_name, "ceil") do_name(rint_name, "rint") \ - do_name(round_name, "round") do_name(tanh_name,"tanh") \ + do_name(round_name, "round") do_name(tanh_name,"tanh") do_name(cbrt_name,"cbrt") \ \ do_name(addExact_name,"addExact") \ do_name(decrementExact_name,"decrementExact") \ @@ -161,7 +161,8 @@ class methodHandle; do_intrinsic(_dcos, java_lang_Math, cos_name, double_double_signature, F_S) \ do_intrinsic(_dtan, java_lang_Math, tan_name, double_double_signature, F_S) \ do_intrinsic(_datan2, java_lang_Math, atan2_name, double2_double_signature, F_S) \ - do_intrinsic(_dtanh, java_lang_Math, tanh_name, double_double_signature, F_S) \ + do_intrinsic(_dtanh, java_lang_Math, tanh_name, double_double_signature, F_S) \ + do_intrinsic(_dcbrt, java_lang_Math, cbrt_name, double_double_signature, F_S) \ do_intrinsic(_dsqrt, java_lang_Math, sqrt_name, double_double_signature, F_S) \ do_intrinsic(_dlog, java_lang_Math, log_name, double_double_signature, F_S) \ do_intrinsic(_dlog10, java_lang_Math, log10_name, double_double_signature, F_S) \ @@ -1001,7 +1002,8 @@ class methodHandle; do_intrinsic(_VectorUnaryOp, jdk_internal_vm_vector_VectorSupport, vector_unary_op_name, vector_unary_op_sig, F_S) \ do_signature(vector_unary_op_sig, "(I" \ "Ljava/lang/Class;" \ - "Ljava/lang/Class;Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ "I" \ "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ "Ljdk/internal/vm/vector/VectorSupport$VectorMask;" \ @@ -1022,6 +1024,29 @@ class methodHandle; "Ljdk/internal/vm/vector/VectorSupport$VectorPayload;") \ do_name(vector_binary_op_name, "binaryOp") \ \ + do_intrinsic(_VectorUnaryLibOp, jdk_internal_vm_vector_VectorSupport, vector_unary_lib_op_name, vector_unary_lib_op_sig, F_S) \ + do_signature(vector_unary_lib_op_sig,"(J" \ + "Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "I" \ + "Ljava/lang/String;" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$UnaryOperation;)" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ + do_name(vector_unary_lib_op_name, "libraryUnaryOp") \ + \ + do_intrinsic(_VectorBinaryLibOp, jdk_internal_vm_vector_VectorSupport, vector_binary_lib_op_name, vector_binary_lib_op_sig, F_S) \ + do_signature(vector_binary_lib_op_sig,"(J" \ + "Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "I" \ + "Ljava/lang/String;" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorPayload;" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorPayload;" \ + "Ljdk/internal/vm/vector/VectorSupport$BinaryOperation;)" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorPayload;") \ + do_name(vector_binary_lib_op_name, "libraryBinaryOp") \ + \ do_intrinsic(_VectorTernaryOp, jdk_internal_vm_vector_VectorSupport, vector_ternary_op_name, vector_ternary_op_sig, F_S) \ do_signature(vector_ternary_op_sig, "(I" \ "Ljava/lang/Class;" \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index e66066738ef..dc9ce61627b 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -719,7 +719,6 @@ class SerializeClosure; JFR_TEMPLATES(template) \ \ /* CDS */ \ - template(createArchivedObjects, "createArchivedObjects") \ template(dumpSharedArchive, "dumpSharedArchive") \ template(dumpSharedArchive_signature, "(ZLjava/lang/String;)Ljava/lang/String;") \ template(generateLambdaFormHolderClasses, "generateLambdaFormHolderClasses") \ @@ -743,6 +742,12 @@ class SerializeClosure; template(jdk_internal_vm_ThreadDumper, "jdk/internal/vm/ThreadDumper") \ template(dumpThreads_name, "dumpThreads") \ template(dumpThreadsToJson_name, "dumpThreadsToJson") \ + template(jdk_internal_vm_ThreadSnapshot, "jdk/internal/vm/ThreadSnapshot") \ + template(jdk_internal_vm_ThreadLock, "jdk/internal/vm/ThreadSnapshot$ThreadLock") \ + template(jdk_internal_vm_ThreadLock_signature, "Ljdk/internal/vm/ThreadSnapshot$ThreadLock;") \ + template(jdk_internal_vm_ThreadLock_array, "[Ljdk/internal/vm/ThreadSnapshot$ThreadLock;") \ + template(java_lang_StackTraceElement_of_name, "of") \ + template(java_lang_StackTraceElement_of_signature, "([Ljava/lang/StackTraceElement;)[Ljava/lang/StackTraceElement;") \ \ /* jcmd Thread.vthread_scheduler and Thread.vthread_pollers */ \ template(jdk_internal_vm_JcmdVThreadCommands, "jdk/internal/vm/JcmdVThreadCommands") \ diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp new file mode 100644 index 00000000000..d0692ee678b --- /dev/null +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -0,0 +1,1716 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +#include "asm/macroAssembler.hpp" +#include "cds/aotCacheAccess.hpp" +#include "cds/cds_globals.hpp" +#include "cds/cdsConfig.hpp" +#include "cds/heapShared.hpp" +#include "cds/metaspaceShared.hpp" +#include "classfile/javaAssertions.hpp" +#include "code/aotCodeCache.hpp" +#include "code/codeCache.hpp" +#include "gc/shared/gcConfig.hpp" +#include "logging/logStream.hpp" +#include "memory/memoryReserver.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/flags/flagSetting.hpp" +#include "runtime/globals_extension.hpp" +#include "runtime/java.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/os.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "utilities/copy.hpp" +#ifdef COMPILER1 +#include "c1/c1_Runtime1.hpp" +#endif +#ifdef COMPILER2 +#include "opto/runtime.hpp" +#endif +#if INCLUDE_G1GC +#include "gc/g1/g1BarrierSetRuntime.hpp" +#endif +#if INCLUDE_SHENANDOAHGC +#include "gc/shenandoah/shenandoahRuntime.hpp" +#endif +#if INCLUDE_ZGC +#include "gc/z/zBarrierSetRuntime.hpp" +#endif + +#include +#include + +const char* aot_code_entry_kind_name[] = { +#define DECL_KIND_STRING(kind) XSTR(kind), + DO_AOTCODEENTRY_KIND(DECL_KIND_STRING) +#undef DECL_KIND_STRING +}; + +static void report_load_failure() { + if (AbortVMOnAOTCodeFailure) { + vm_exit_during_initialization("Unable to use AOT Code Cache.", nullptr); + } + log_info(aot, codecache, init)("Unable to use AOT Code Cache."); + AOTAdapterCaching = false; + AOTStubCaching = false; +} + +static void report_store_failure() { + if (AbortVMOnAOTCodeFailure) { + tty->print_cr("Unable to create AOT Code Cache."); + vm_abort(false); + } + log_info(aot, codecache, exit)("Unable to create AOT Code Cache."); + AOTAdapterCaching = false; + AOTStubCaching = false; +} + +bool AOTCodeCache::is_dumping_adapter() { + return AOTAdapterCaching && is_on_for_dump(); +} + +bool AOTCodeCache::is_using_adapter() { + return AOTAdapterCaching && is_on_for_use(); +} + +bool AOTCodeCache::is_dumping_stub() { + return AOTStubCaching && is_on_for_dump(); +} + +bool AOTCodeCache::is_using_stub() { + return AOTStubCaching && is_on_for_use(); +} + +static uint32_t encode_id(AOTCodeEntry::Kind kind, int id) { + assert(AOTCodeEntry::is_valid_entry_kind(kind), "invalid AOTCodeEntry kind %d", (int)kind); + // There can be a conflict of id between an Adapter and *Blob, but that should not cause any functional issue + // becasue both id and kind are used to find an entry, and that combination should be unique + if (kind == AOTCodeEntry::Adapter) { + return id; + } else if (kind == AOTCodeEntry::SharedBlob) { + return id; + } else if (kind == AOTCodeEntry::C1Blob) { + return (int)SharedStubId::NUM_STUBIDS + id; + } else { + // kind must be AOTCodeEntry::C2Blob + return (int)SharedStubId::NUM_STUBIDS + COMPILER1_PRESENT((int)C1StubId::NUM_STUBIDS) + id; + } +} + +static uint _max_aot_code_size = 0; +uint AOTCodeCache::max_aot_code_size() { + return _max_aot_code_size; +} + +// This method is called during universe_init() +// and does final AOT state and flags settings. +void AOTCodeCache::initialize() { +#if defined(ZERO) || !(defined(AMD64) || defined(AARCH64)) + log_info(aot, codecache, init)("AOT Code Cache is not supported on this platform."); + AOTAdapterCaching = false; + AOTStubCaching = false; + return; +#else + if (FLAG_IS_DEFAULT(AOTCache)) { + log_info(aot, codecache, init)("AOT Code Cache is not used: AOTCache is not specified."); + AOTAdapterCaching = false; + AOTStubCaching = false; + return; // AOTCache must be specified to dump and use AOT code + } + + // Disable stubs caching until JDK-8357398 is fixed. + FLAG_SET_ERGO(AOTStubCaching, false); + + if (VerifyOops) { + // Disable AOT stubs caching when VerifyOops flag is on. + // Verify oops code generated a lot of C strings which overflow + // AOT C string table (which has fixed size). + // AOT C string table will be reworked later to handle such cases. + // + // Note: AOT adapters are not affected - they don't have oop operations. + log_info(aot, codecache, init)("AOT Stubs Caching is not supported with VerifyOops."); + FLAG_SET_ERGO(AOTStubCaching, false); + } + + bool is_dumping = false; + bool is_using = false; + if (CDSConfig::is_dumping_final_static_archive() && CDSConfig::is_dumping_aot_linked_classes()) { + FLAG_SET_ERGO_IF_DEFAULT(AOTAdapterCaching, true); + FLAG_SET_ERGO_IF_DEFAULT(AOTStubCaching, true); + is_dumping = true; + } else if (CDSConfig::is_using_archive() && CDSConfig::is_using_aot_linked_classes()) { + FLAG_SET_ERGO_IF_DEFAULT(AOTAdapterCaching, true); + FLAG_SET_ERGO_IF_DEFAULT(AOTStubCaching, true); + is_using = true; + } else { + log_info(aot, codecache, init)("AOT Code Cache is not used: AOT Class Linking is not used."); + return; // nothing to do + } + if (!AOTAdapterCaching && !AOTStubCaching) { + return; // AOT code caching disabled on command line + } + _max_aot_code_size = AOTCodeMaxSize; + if (!FLAG_IS_DEFAULT(AOTCodeMaxSize)) { + if (!is_aligned(AOTCodeMaxSize, os::vm_allocation_granularity())) { + _max_aot_code_size = align_up(AOTCodeMaxSize, os::vm_allocation_granularity()); + log_debug(aot,codecache,init)("Max AOT Code Cache size is aligned up to %uK", (int)(max_aot_code_size()/K)); + } + } + size_t aot_code_size = is_using ? AOTCacheAccess::get_aot_code_region_size() : 0; + if (is_using && aot_code_size == 0) { + log_info(aot, codecache, init)("AOT Code Cache is empty"); + return; + } + if (!open_cache(is_dumping, is_using)) { + if (is_using) { + report_load_failure(); + } else { + report_store_failure(); + } + return; + } + if (is_dumping) { + FLAG_SET_DEFAULT(ForceUnreachable, true); + } + FLAG_SET_DEFAULT(DelayCompilerStubsGeneration, false); +#endif // defined(AMD64) || defined(AARCH64) +} + +static AOTCodeCache* opened_cache = nullptr; // Use this until we verify the cache +AOTCodeCache* AOTCodeCache::_cache = nullptr; + +// This method is called after universe_init() +// when all GC settings are finalized. +void AOTCodeCache::init2() { + if (opened_cache == nullptr) { + return; + } + if (!opened_cache->verify_config()) { + delete opened_cache; + opened_cache = nullptr; + report_load_failure(); + return; + } + + // initialize the table of external routines so we can save + // generated code blobs that reference them + AOTCodeAddressTable* table = opened_cache->_table; + assert(table != nullptr, "should be initialized already"); + table->init_extrs(); + table->init_early_stubs(); + + // Now cache and address table are ready for AOT code generation + _cache = opened_cache; +} + +bool AOTCodeCache::open_cache(bool is_dumping, bool is_using) { + opened_cache = new AOTCodeCache(is_dumping, is_using); + if (opened_cache->failed()) { + delete opened_cache; + opened_cache = nullptr; + return false; + } + return true; +} + +void AOTCodeCache::close() { + if (is_on()) { + delete _cache; // Free memory + _cache = nullptr; + opened_cache = nullptr; + } +} + +#define DATA_ALIGNMENT HeapWordSize + +AOTCodeCache::AOTCodeCache(bool is_dumping, bool is_using) : + _load_header(nullptr), + _load_buffer(nullptr), + _store_buffer(nullptr), + _C_store_buffer(nullptr), + _write_position(0), + _load_size(0), + _store_size(0), + _for_use(is_using), + _for_dump(is_dumping), + _closing(false), + _failed(false), + _lookup_failed(false), + _table(nullptr), + _load_entries(nullptr), + _search_entries(nullptr), + _store_entries(nullptr), + _C_strings_buf(nullptr), + _store_entries_cnt(0) +{ + // Read header at the begining of cache + if (_for_use) { + // Read cache + size_t load_size = AOTCacheAccess::get_aot_code_region_size(); + ReservedSpace rs = MemoryReserver::reserve(load_size, mtCode); + if (!rs.is_reserved()) { + log_warning(aot, codecache, init)("Failed to reserved %u bytes of memory for mapping AOT code region into AOT Code Cache", (uint)load_size); + set_failed(); + return; + } + if (!AOTCacheAccess::map_aot_code_region(rs)) { + log_warning(aot, codecache, init)("Failed to read/mmap cached code region into AOT Code Cache"); + set_failed(); + return; + } + + _load_size = (uint)load_size; + _load_buffer = (char*)rs.base(); + assert(is_aligned(_load_buffer, DATA_ALIGNMENT), "load_buffer is not aligned"); + log_debug(aot, codecache, init)("Mapped %u bytes at address " INTPTR_FORMAT " at AOT Code Cache", _load_size, p2i(_load_buffer)); + + _load_header = (Header*)addr(0); + if (!_load_header->verify(_load_size)) { + set_failed(); + return; + } + log_info (aot, codecache, init)("Loaded %u AOT code entries from AOT Code Cache", _load_header->entries_count()); + log_debug(aot, codecache, init)(" Adapters: total=%u", _load_header->adapters_count()); + log_debug(aot, codecache, init)(" Shared Blobs: total=%u", _load_header->shared_blobs_count()); + log_debug(aot, codecache, init)(" C1 Blobs: total=%u", _load_header->C1_blobs_count()); + log_debug(aot, codecache, init)(" C2 Blobs: total=%u", _load_header->C2_blobs_count()); + log_debug(aot, codecache, init)(" AOT code cache size: %u bytes", _load_header->cache_size()); + + // Read strings + load_strings(); + } + if (_for_dump) { + _C_store_buffer = NEW_C_HEAP_ARRAY(char, max_aot_code_size() + DATA_ALIGNMENT, mtCode); + _store_buffer = align_up(_C_store_buffer, DATA_ALIGNMENT); + // Entries allocated at the end of buffer in reverse (as on stack). + _store_entries = (AOTCodeEntry*)align_up(_C_store_buffer + max_aot_code_size(), DATA_ALIGNMENT); + log_debug(aot, codecache, init)("Allocated store buffer at address " INTPTR_FORMAT " of size %u", p2i(_store_buffer), max_aot_code_size()); + } + _table = new AOTCodeAddressTable(); +} + +void AOTCodeCache::init_shared_blobs_table() { + AOTCodeAddressTable* table = addr_table(); + if (table != nullptr) { + table->init_shared_blobs(); + } +} + +void AOTCodeCache::init_early_c1_table() { + AOTCodeAddressTable* table = addr_table(); + if (table != nullptr) { + table->init_early_c1(); + } +} + +AOTCodeCache::~AOTCodeCache() { + if (_closing) { + return; // Already closed + } + // Stop any further access to cache. + _closing = true; + + MutexLocker ml(Compile_lock); + if (for_dump()) { // Finalize cache + finish_write(); + } + _load_buffer = nullptr; + if (_C_store_buffer != nullptr) { + FREE_C_HEAP_ARRAY(char, _C_store_buffer); + _C_store_buffer = nullptr; + _store_buffer = nullptr; + } + if (_table != nullptr) { + delete _table; + _table = nullptr; + } +} + +void AOTCodeCache::Config::record() { + _flags = 0; +#ifdef ASSERT + _flags |= debugVM; +#endif + if (UseCompressedOops) { + _flags |= compressedOops; + } + if (UseCompressedClassPointers) { + _flags |= compressedClassPointers; + } + if (UseTLAB) { + _flags |= useTLAB; + } + if (JavaAssertions::systemClassDefault()) { + _flags |= systemClassAssertions; + } + if (JavaAssertions::userClassDefault()) { + _flags |= userClassAssertions; + } + if (EnableContended) { + _flags |= enableContendedPadding; + } + if (RestrictContended) { + _flags |= restrictContendedPadding; + } + _compressedOopShift = CompressedOops::shift(); + _compressedOopBase = CompressedOops::base(); + _compressedKlassShift = CompressedKlassPointers::shift(); + _contendedPaddingWidth = ContendedPaddingWidth; + _gc = (uint)Universe::heap()->kind(); +} + +bool AOTCodeCache::Config::verify() const { + // First checks affect all cached AOT code +#ifdef ASSERT + if ((_flags & debugVM) == 0) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created by product VM, it can't be used by debug VM"); + return false; + } +#else + if ((_flags & debugVM) != 0) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created by debug VM, it can't be used by product VM"); + return false; + } +#endif + + CollectedHeap::Name aot_gc = (CollectedHeap::Name)_gc; + if (aot_gc != Universe::heap()->kind()) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with different GC: %s vs current %s", GCConfig::hs_err_name(aot_gc), GCConfig::hs_err_name()); + return false; + } + + if (((_flags & compressedClassPointers) != 0) != UseCompressedClassPointers) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with UseCompressedClassPointers = %s", UseCompressedClassPointers ? "false" : "true"); + return false; + } + if (_compressedKlassShift != (uint)CompressedKlassPointers::shift()) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with CompressedKlassPointers::shift() = %d vs current %d", _compressedKlassShift, CompressedKlassPointers::shift()); + return false; + } + + // The following checks do not affect AOT adapters caching + + if (((_flags & compressedOops) != 0) != UseCompressedOops) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with UseCompressedOops = %s", UseCompressedOops ? "false" : "true"); + AOTStubCaching = false; + } + if (_compressedOopShift != (uint)CompressedOops::shift()) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: it was created with different CompressedOops::shift(): %d vs current %d", _compressedOopShift, CompressedOops::shift()); + AOTStubCaching = false; + } + + // This should be the last check as it only disables AOTStubCaching + if ((_compressedOopBase == nullptr || CompressedOops::base() == nullptr) && (_compressedOopBase != CompressedOops::base())) { + log_debug(aot, codecache, init)("AOTStubCaching is disabled: incompatible CompressedOops::base(): %p vs current %p", _compressedOopBase, CompressedOops::base()); + AOTStubCaching = false; + } + + return true; +} + +bool AOTCodeCache::Header::verify(uint load_size) const { + if (_version != AOT_CODE_VERSION) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: different AOT Code version %d vs %d recorded in AOT Code header", AOT_CODE_VERSION, _version); + return false; + } + if (load_size < _cache_size) { + log_debug(aot, codecache, init)("AOT Code Cache disabled: AOT Code Cache size %d < %d recorded in AOT Code header", load_size, _cache_size); + return false; + } + return true; +} + +AOTCodeCache* AOTCodeCache::open_for_use() { + if (AOTCodeCache::is_on_for_use()) { + return AOTCodeCache::cache(); + } + return nullptr; +} + +AOTCodeCache* AOTCodeCache::open_for_dump() { + if (AOTCodeCache::is_on_for_dump()) { + AOTCodeCache* cache = AOTCodeCache::cache(); + cache->clear_lookup_failed(); // Reset bit + return cache; + } + return nullptr; +} + +void copy_bytes(const char* from, address to, uint size) { + assert((int)size > 0, "sanity"); + memcpy(to, from, size); + log_trace(aot, codecache)("Copied %d bytes from " INTPTR_FORMAT " to " INTPTR_FORMAT, size, p2i(from), p2i(to)); +} + +AOTCodeReader::AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry) { + _cache = cache; + _entry = entry; + _load_buffer = cache->cache_buffer(); + _read_position = 0; + _lookup_failed = false; +} + +void AOTCodeReader::set_read_position(uint pos) { + if (pos == _read_position) { + return; + } + assert(pos < _cache->load_size(), "offset:%d >= file size:%d", pos, _cache->load_size()); + _read_position = pos; +} + +bool AOTCodeCache::set_write_position(uint pos) { + if (pos == _write_position) { + return true; + } + if (_store_size < _write_position) { + _store_size = _write_position; // Adjust during write + } + assert(pos < _store_size, "offset:%d >= file size:%d", pos, _store_size); + _write_position = pos; + return true; +} + +static char align_buffer[256] = { 0 }; + +bool AOTCodeCache::align_write() { + // We are not executing code from cache - we copy it by bytes first. + // No need for big alignment (or at all). + uint padding = DATA_ALIGNMENT - (_write_position & (DATA_ALIGNMENT - 1)); + if (padding == DATA_ALIGNMENT) { + return true; + } + uint n = write_bytes((const void*)&align_buffer, padding); + if (n != padding) { + return false; + } + log_trace(aot, codecache)("Adjust write alignment in AOT Code Cache"); + return true; +} + +// Check to see if AOT code cache has required space to store "nbytes" of data +address AOTCodeCache::reserve_bytes(uint nbytes) { + assert(for_dump(), "Code Cache file is not created"); + uint new_position = _write_position + nbytes; + if (new_position >= (uint)((char*)_store_entries - _store_buffer)) { + log_warning(aot,codecache)("Failed to ensure %d bytes at offset %d in AOT Code Cache. Increase AOTCodeMaxSize.", + nbytes, _write_position); + set_failed(); + report_store_failure(); + return nullptr; + } + address buffer = (address)(_store_buffer + _write_position); + log_trace(aot, codecache)("Reserved %d bytes at offset %d in AOT Code Cache", nbytes, _write_position); + _write_position += nbytes; + if (_store_size < _write_position) { + _store_size = _write_position; + } + return buffer; +} + +uint AOTCodeCache::write_bytes(const void* buffer, uint nbytes) { + assert(for_dump(), "Code Cache file is not created"); + if (nbytes == 0) { + return 0; + } + uint new_position = _write_position + nbytes; + if (new_position >= (uint)((char*)_store_entries - _store_buffer)) { + log_warning(aot, codecache)("Failed to write %d bytes at offset %d to AOT Code Cache. Increase AOTCodeMaxSize.", + nbytes, _write_position); + set_failed(); + report_store_failure(); + return 0; + } + copy_bytes((const char* )buffer, (address)(_store_buffer + _write_position), nbytes); + log_trace(aot, codecache)("Wrote %d bytes at offset %d to AOT Code Cache", nbytes, _write_position); + _write_position += nbytes; + if (_store_size < _write_position) { + _store_size = _write_position; + } + return nbytes; +} + +void* AOTCodeEntry::operator new(size_t x, AOTCodeCache* cache) { + return (void*)(cache->add_entry()); +} + +static bool check_entry(AOTCodeEntry::Kind kind, uint id, AOTCodeEntry* entry) { + if (entry->kind() == kind) { + assert(entry->id() == id, "sanity"); + return true; // Found + } + return false; +} + +AOTCodeEntry* AOTCodeCache::find_entry(AOTCodeEntry::Kind kind, uint id) { + assert(_for_use, "sanity"); + uint count = _load_header->entries_count(); + if (_load_entries == nullptr) { + // Read it + _search_entries = (uint*)addr(_load_header->entries_offset()); // [id, index] + _load_entries = (AOTCodeEntry*)(_search_entries + 2 * count); + log_debug(aot, codecache, init)("Read %d entries table at offset %d from AOT Code Cache", count, _load_header->entries_offset()); + } + // Binary search + int l = 0; + int h = count - 1; + while (l <= h) { + int mid = (l + h) >> 1; + int ix = mid * 2; + uint is = _search_entries[ix]; + if (is == id) { + int index = _search_entries[ix + 1]; + AOTCodeEntry* entry = &(_load_entries[index]); + if (check_entry(kind, id, entry)) { + return entry; // Found + } + // Linear search around to handle id collission + for (int i = mid - 1; i >= l; i--) { // search back + ix = i * 2; + is = _search_entries[ix]; + if (is != id) { + break; + } + index = _search_entries[ix + 1]; + AOTCodeEntry* entry = &(_load_entries[index]); + if (check_entry(kind, id, entry)) { + return entry; // Found + } + } + for (int i = mid + 1; i <= h; i++) { // search forward + ix = i * 2; + is = _search_entries[ix]; + if (is != id) { + break; + } + index = _search_entries[ix + 1]; + AOTCodeEntry* entry = &(_load_entries[index]); + if (check_entry(kind, id, entry)) { + return entry; // Found + } + } + break; // Not found match + } else if (is < id) { + l = mid + 1; + } else { + h = mid - 1; + } + } + return nullptr; +} + +extern "C" { + static int uint_cmp(const void *i, const void *j) { + uint a = *(uint *)i; + uint b = *(uint *)j; + return a > b ? 1 : a < b ? -1 : 0; + } +} + +bool AOTCodeCache::finish_write() { + if (!align_write()) { + return false; + } + uint strings_offset = _write_position; + int strings_count = store_strings(); + if (strings_count < 0) { + return false; + } + if (!align_write()) { + return false; + } + uint strings_size = _write_position - strings_offset; + + uint entries_count = 0; // Number of entrant (useful) code entries + uint entries_offset = _write_position; + + uint store_count = _store_entries_cnt; + if (store_count > 0) { + uint header_size = (uint)align_up(sizeof(AOTCodeCache::Header), DATA_ALIGNMENT); + uint code_count = store_count; + uint search_count = code_count * 2; + uint search_size = search_count * sizeof(uint); + uint entries_size = (uint)align_up(code_count * sizeof(AOTCodeEntry), DATA_ALIGNMENT); // In bytes + // _write_position includes size of code and strings + uint code_alignment = code_count * DATA_ALIGNMENT; // We align_up code size when storing it. + uint total_size = header_size + _write_position + code_alignment + search_size + entries_size; + assert(total_size < max_aot_code_size(), "AOT Code size (" UINT32_FORMAT " bytes) is greater than AOTCodeMaxSize(" UINT32_FORMAT " bytes).", total_size, max_aot_code_size()); + + // Create ordered search table for entries [id, index]; + uint* search = NEW_C_HEAP_ARRAY(uint, search_count, mtCode); + // Allocate in AOT Cache buffer + char* buffer = (char *)AOTCacheAccess::allocate_aot_code_region(total_size + DATA_ALIGNMENT); + char* start = align_up(buffer, DATA_ALIGNMENT); + char* current = start + header_size; // Skip header + + AOTCodeEntry* entries_address = _store_entries; // Pointer to latest entry + uint adapters_count = 0; + uint shared_blobs_count = 0; + uint C1_blobs_count = 0; + uint C2_blobs_count = 0; + uint max_size = 0; + // AOTCodeEntry entries were allocated in reverse in store buffer. + // Process them in reverse order to cache first code first. + for (int i = store_count - 1; i >= 0; i--) { + entries_address[i].set_next(nullptr); // clear pointers before storing data + uint size = align_up(entries_address[i].size(), DATA_ALIGNMENT); + if (size > max_size) { + max_size = size; + } + copy_bytes((_store_buffer + entries_address[i].offset()), (address)current, size); + entries_address[i].set_offset(current - start); // New offset + current += size; + uint n = write_bytes(&(entries_address[i]), sizeof(AOTCodeEntry)); + if (n != sizeof(AOTCodeEntry)) { + FREE_C_HEAP_ARRAY(uint, search); + return false; + } + search[entries_count*2 + 0] = entries_address[i].id(); + search[entries_count*2 + 1] = entries_count; + entries_count++; + AOTCodeEntry::Kind kind = entries_address[i].kind(); + if (kind == AOTCodeEntry::Adapter) { + adapters_count++; + } else if (kind == AOTCodeEntry::SharedBlob) { + shared_blobs_count++; + } else if (kind == AOTCodeEntry::C1Blob) { + C1_blobs_count++; + } else if (kind == AOTCodeEntry::C2Blob) { + C2_blobs_count++; + } + } + if (entries_count == 0) { + log_info(aot, codecache, exit)("AOT Code Cache was not created: no entires"); + FREE_C_HEAP_ARRAY(uint, search); + return true; // Nothing to write + } + assert(entries_count <= store_count, "%d > %d", entries_count, store_count); + // Write strings + if (strings_count > 0) { + copy_bytes((_store_buffer + strings_offset), (address)current, strings_size); + strings_offset = (current - start); // New offset + current += strings_size; + } + + uint new_entries_offset = (current - start); // New offset + // Sort and store search table + qsort(search, entries_count, 2*sizeof(uint), uint_cmp); + search_size = 2 * entries_count * sizeof(uint); + copy_bytes((const char*)search, (address)current, search_size); + FREE_C_HEAP_ARRAY(uint, search); + current += search_size; + + // Write entries + entries_size = entries_count * sizeof(AOTCodeEntry); // New size + copy_bytes((_store_buffer + entries_offset), (address)current, entries_size); + current += entries_size; + uint size = (current - start); + assert(size <= total_size, "%d > %d", size , total_size); + + log_debug(aot, codecache, exit)(" Adapters: total=%u", adapters_count); + log_debug(aot, codecache, exit)(" Shared Blobs: total=%d", shared_blobs_count); + log_debug(aot, codecache, exit)(" C1 Blobs: total=%d", C1_blobs_count); + log_debug(aot, codecache, exit)(" C2 Blobs: total=%d", C2_blobs_count); + log_debug(aot, codecache, exit)(" AOT code cache size: %u bytes, max entry's size: %u bytes", size, max_size); + + // Finalize header + AOTCodeCache::Header* header = (AOTCodeCache::Header*)start; + header->init(size, (uint)strings_count, strings_offset, + entries_count, new_entries_offset, + adapters_count, shared_blobs_count, + C1_blobs_count, C2_blobs_count); + + log_info(aot, codecache, exit)("Wrote %d AOT code entries to AOT Code Cache", entries_count); + } + return true; +} + +//------------------Store/Load AOT code ---------------------- + +bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind, uint id, const char* name, int entry_offset_count, int* entry_offsets) { + AOTCodeCache* cache = open_for_dump(); + if (cache == nullptr) { + return false; + } + assert(AOTCodeEntry::is_valid_entry_kind(entry_kind), "invalid entry_kind %d", entry_kind); + + if (AOTCodeEntry::is_adapter(entry_kind) && !is_dumping_adapter()) { + return false; + } + if (AOTCodeEntry::is_blob(entry_kind) && !is_dumping_stub()) { + return false; + } + log_debug(aot, codecache, stubs)("Writing blob '%s' (id=%u, kind=%s) to AOT Code Cache", name, id, aot_code_entry_kind_name[entry_kind]); + +#ifdef ASSERT + LogStreamHandle(Trace, aot, codecache, stubs) log; + if (log.is_enabled()) { + FlagSetting fs(PrintRelocations, true); + blob.print_on(&log); + } +#endif + // we need to take a lock to prevent race between compiler threads generating AOT code + // and the main thread generating adapter + MutexLocker ml(Compile_lock); + if (!cache->align_write()) { + return false; + } + uint entry_position = cache->_write_position; + + // Write name + uint name_offset = cache->_write_position - entry_position; + uint name_size = (uint)strlen(name) + 1; // Includes '/0' + uint n = cache->write_bytes(name, name_size); + if (n != name_size) { + return false; + } + + // Write CodeBlob + if (!cache->align_write()) { + return false; + } + uint blob_offset = cache->_write_position - entry_position; + address archive_buffer = cache->reserve_bytes(blob.size()); + if (archive_buffer == nullptr) { + return false; + } + CodeBlob::archive_blob(&blob, archive_buffer); + + uint reloc_data_size = blob.relocation_size(); + n = cache->write_bytes((address)blob.relocation_begin(), reloc_data_size); + if (n != reloc_data_size) { + return false; + } + + bool has_oop_maps = false; + if (blob.oop_maps() != nullptr) { + if (!cache->write_oop_map_set(blob)) { + return false; + } + has_oop_maps = true; + } + +#ifndef PRODUCT + // Write asm remarks + if (!cache->write_asm_remarks(blob)) { + return false; + } + if (!cache->write_dbg_strings(blob)) { + return false; + } +#endif /* PRODUCT */ + + if (!cache->write_relocations(blob)) { + if (!cache->failed()) { + // We may miss an address in AOT table - skip this code blob. + cache->set_write_position(entry_position); + } + return false; + } + + // Write entries offsets + n = cache->write_bytes(&entry_offset_count, sizeof(int)); + if (n != sizeof(int)) { + return false; + } + for (int i = 0; i < entry_offset_count; i++) { + uint32_t off = (uint32_t)entry_offsets[i]; + n = cache->write_bytes(&off, sizeof(uint32_t)); + if (n != sizeof(uint32_t)) { + return false; + } + } + uint entry_size = cache->_write_position - entry_position; + AOTCodeEntry* entry = new(cache) AOTCodeEntry(entry_kind, encode_id(entry_kind, id), + entry_position, entry_size, name_offset, name_size, + blob_offset, has_oop_maps, blob.content_begin()); + log_debug(aot, codecache, stubs)("Wrote code blob '%s' (id=%u, kind=%s) to AOT Code Cache", name, id, aot_code_entry_kind_name[entry_kind]); + return true; +} + +CodeBlob* AOTCodeCache::load_code_blob(AOTCodeEntry::Kind entry_kind, uint id, const char* name, int entry_offset_count, int* entry_offsets) { + AOTCodeCache* cache = open_for_use(); + if (cache == nullptr) { + return nullptr; + } + assert(AOTCodeEntry::is_valid_entry_kind(entry_kind), "invalid entry_kind %d", entry_kind); + + if (AOTCodeEntry::is_adapter(entry_kind) && !is_using_adapter()) { + return nullptr; + } + if (AOTCodeEntry::is_blob(entry_kind) && !is_using_stub()) { + return nullptr; + } + log_debug(aot, codecache, stubs)("Reading blob '%s' (id=%u, kind=%s) from AOT Code Cache", name, id, aot_code_entry_kind_name[entry_kind]); + + AOTCodeEntry* entry = cache->find_entry(entry_kind, encode_id(entry_kind, id)); + if (entry == nullptr) { + return nullptr; + } + AOTCodeReader reader(cache, entry); + CodeBlob* blob = reader.compile_code_blob(name, entry_offset_count, entry_offsets); + + log_debug(aot, codecache, stubs)("%sRead blob '%s' (id=%u, kind=%s) from AOT Code Cache", + (blob == nullptr? "Failed to " : ""), name, id, aot_code_entry_kind_name[entry_kind]); + return blob; +} + +CodeBlob* AOTCodeReader::compile_code_blob(const char* name, int entry_offset_count, int* entry_offsets) { + uint entry_position = _entry->offset(); + + // Read name + uint name_offset = entry_position + _entry->name_offset(); + uint name_size = _entry->name_size(); // Includes '/0' + const char* stored_name = addr(name_offset); + + if (strncmp(stored_name, name, (name_size - 1)) != 0) { + log_warning(aot, codecache, stubs)("Saved blob's name '%s' is different from the expected name '%s'", + stored_name, name); + set_lookup_failed(); // Skip this blob + return nullptr; + } + + // Read archived code blob + uint offset = entry_position + _entry->blob_offset(); + CodeBlob* archived_blob = (CodeBlob*)addr(offset); + offset += archived_blob->size(); + + address reloc_data = (address)addr(offset); + offset += archived_blob->relocation_size(); + set_read_position(offset); + + ImmutableOopMapSet* oop_maps = nullptr; + if (_entry->has_oop_maps()) { + oop_maps = read_oop_map_set(); + } + + CodeBlob* code_blob = CodeBlob::create(archived_blob, + stored_name, + reloc_data, + oop_maps + ); + if (code_blob == nullptr) { // no space left in CodeCache + return nullptr; + } + +#ifndef PRODUCT + code_blob->asm_remarks().init(); + read_asm_remarks(code_blob->asm_remarks()); + code_blob->dbg_strings().init(); + read_dbg_strings(code_blob->dbg_strings()); +#endif // PRODUCT + + fix_relocations(code_blob); + + // Read entries offsets + offset = read_position(); + int stored_count = *(int*)addr(offset); + assert(stored_count == entry_offset_count, "entry offset count mismatch, count in AOT code cache=%d, expected=%d", stored_count, entry_offset_count); + offset += sizeof(int); + set_read_position(offset); + for (int i = 0; i < stored_count; i++) { + uint32_t off = *(uint32_t*)addr(offset); + offset += sizeof(uint32_t); + const char* entry_name = (_entry->kind() == AOTCodeEntry::Adapter) ? AdapterHandlerEntry::entry_name(i) : ""; + log_trace(aot, codecache, stubs)("Reading adapter '%s:%s' (0x%x) offset: 0x%x from AOT Code Cache", + stored_name, entry_name, _entry->id(), off); + entry_offsets[i] = off; + } + +#ifdef ASSERT + LogStreamHandle(Trace, aot, codecache, stubs) log; + if (log.is_enabled()) { + FlagSetting fs(PrintRelocations, true); + code_blob->print_on(&log); + } +#endif + return code_blob; +} + +// ------------ process code and data -------------- + +// Can't use -1. It is valid value for jump to iteself destination +// used by static call stub: see NativeJump::jump_destination(). +#define BAD_ADDRESS_ID -2 + +bool AOTCodeCache::write_relocations(CodeBlob& code_blob) { + GrowableArray reloc_data; + RelocIterator iter(&code_blob); + LogStreamHandle(Trace, aot, codecache, reloc) log; + while (iter.next()) { + int idx = reloc_data.append(0); // default value + switch (iter.type()) { + case relocInfo::none: + break; + case relocInfo::runtime_call_type: { + // Record offset of runtime destination + CallRelocation* r = (CallRelocation*)iter.reloc(); + address dest = r->destination(); + if (dest == r->addr()) { // possible call via trampoline on Aarch64 + dest = (address)-1; // do nothing in this case when loading this relocation + } + int id = _table->id_for_address(dest, iter, &code_blob); + if (id == BAD_ADDRESS_ID) { + return false; + } + reloc_data.at_put(idx, id); + break; + } + case relocInfo::runtime_call_w_cp_type: + log_debug(aot, codecache, reloc)("runtime_call_w_cp_type relocation is not implemented"); + return false; + case relocInfo::external_word_type: { + // Record offset of runtime target + address target = ((external_word_Relocation*)iter.reloc())->target(); + int id = _table->id_for_address(target, iter, &code_blob); + if (id == BAD_ADDRESS_ID) { + return false; + } + reloc_data.at_put(idx, id); + break; + } + case relocInfo::internal_word_type: + break; + case relocInfo::section_word_type: + break; + case relocInfo::post_call_nop_type: + break; + default: + log_debug(aot, codecache, reloc)("relocation %d unimplemented", (int)iter.type()); + return false; + break; + } + if (log.is_enabled()) { + iter.print_current_on(&log); + } + } + + // Write additional relocation data: uint per relocation + // Write the count first + int count = reloc_data.length(); + write_bytes(&count, sizeof(int)); + for (GrowableArrayIterator iter = reloc_data.begin(); + iter != reloc_data.end(); ++iter) { + uint value = *iter; + int n = write_bytes(&value, sizeof(uint)); + if (n != sizeof(uint)) { + return false; + } + } + return true; +} + +void AOTCodeReader::fix_relocations(CodeBlob* code_blob) { + LogStreamHandle(Trace, aot, reloc) log; + uint offset = read_position(); + int count = *(int*)addr(offset); + offset += sizeof(int); + if (log.is_enabled()) { + log.print_cr("======== extra relocations count=%d", count); + } + uint* reloc_data = (uint*)addr(offset); + offset += (count * sizeof(uint)); + set_read_position(offset); + + RelocIterator iter(code_blob); + int j = 0; + while (iter.next()) { + switch (iter.type()) { + case relocInfo::none: + break; + case relocInfo::runtime_call_type: { + address dest = _cache->address_for_id(reloc_data[j]); + if (dest != (address)-1) { + ((CallRelocation*)iter.reloc())->set_destination(dest); + } + break; + } + case relocInfo::runtime_call_w_cp_type: + // this relocation should not be in cache (see write_relocations) + assert(false, "runtime_call_w_cp_type relocation is not implemented"); + break; + case relocInfo::external_word_type: { + address target = _cache->address_for_id(reloc_data[j]); + // Add external address to global table + int index = ExternalsRecorder::find_index(target); + // Update index in relocation + Relocation::add_jint(iter.data(), index); + external_word_Relocation* reloc = (external_word_Relocation*)iter.reloc(); + assert(reloc->target() == target, "sanity"); + reloc->set_value(target); // Patch address in the code + break; + } + case relocInfo::internal_word_type: { + internal_word_Relocation* r = (internal_word_Relocation*)iter.reloc(); + r->fix_relocation_after_aot_load(aot_code_entry()->dumptime_content_start_addr(), code_blob->content_begin()); + break; + } + case relocInfo::section_word_type: { + section_word_Relocation* r = (section_word_Relocation*)iter.reloc(); + r->fix_relocation_after_aot_load(aot_code_entry()->dumptime_content_start_addr(), code_blob->content_begin()); + break; + } + case relocInfo::post_call_nop_type: + break; + default: + assert(false,"relocation %d unimplemented", (int)iter.type()); + break; + } + if (log.is_enabled()) { + iter.print_current_on(&log); + } + j++; + } + assert(j == count, "sanity"); +} + +bool AOTCodeCache::write_oop_map_set(CodeBlob& cb) { + ImmutableOopMapSet* oopmaps = cb.oop_maps(); + int oopmaps_size = oopmaps->nr_of_bytes(); + if (!write_bytes(&oopmaps_size, sizeof(int))) { + return false; + } + uint n = write_bytes(oopmaps, oopmaps->nr_of_bytes()); + if (n != (uint)oopmaps->nr_of_bytes()) { + return false; + } + return true; +} + +ImmutableOopMapSet* AOTCodeReader::read_oop_map_set() { + uint offset = read_position(); + int size = *(int *)addr(offset); + offset += sizeof(int); + ImmutableOopMapSet* oopmaps = (ImmutableOopMapSet *)addr(offset); + offset += size; + set_read_position(offset); + return oopmaps; +} + +#ifndef PRODUCT +bool AOTCodeCache::write_asm_remarks(CodeBlob& cb) { + // Write asm remarks + uint* count_ptr = (uint *)reserve_bytes(sizeof(uint)); + if (count_ptr == nullptr) { + return false; + } + uint count = 0; + bool result = cb.asm_remarks().iterate([&] (uint offset, const char* str) -> bool { + log_trace(aot, codecache, stubs)("asm remark offset=%d, str='%s'", offset, str); + uint n = write_bytes(&offset, sizeof(uint)); + if (n != sizeof(uint)) { + return false; + } + const char* cstr = add_C_string(str); + int id = _table->id_for_C_string((address)cstr); + assert(id != -1, "asm remark string '%s' not found in AOTCodeAddressTable", str); + n = write_bytes(&id, sizeof(int)); + if (n != sizeof(int)) { + return false; + } + count += 1; + return true; + }); + *count_ptr = count; + return result; +} + +void AOTCodeReader::read_asm_remarks(AsmRemarks& asm_remarks) { + // Read asm remarks + uint offset = read_position(); + uint count = *(uint *)addr(offset); + offset += sizeof(uint); + for (uint i = 0; i < count; i++) { + uint remark_offset = *(uint *)addr(offset); + offset += sizeof(uint); + int remark_string_id = *(uint *)addr(offset); + offset += sizeof(int); + const char* remark = (const char*)_cache->address_for_C_string(remark_string_id); + asm_remarks.insert(remark_offset, remark); + } + set_read_position(offset); +} + +bool AOTCodeCache::write_dbg_strings(CodeBlob& cb) { + // Write dbg strings + uint* count_ptr = (uint *)reserve_bytes(sizeof(uint)); + if (count_ptr == nullptr) { + return false; + } + uint count = 0; + bool result = cb.dbg_strings().iterate([&] (const char* str) -> bool { + log_trace(aot, codecache, stubs)("dbg string=%s", str); + const char* cstr = add_C_string(str); + int id = _table->id_for_C_string((address)cstr); + assert(id != -1, "db string '%s' not found in AOTCodeAddressTable", str); + uint n = write_bytes(&id, sizeof(int)); + if (n != sizeof(int)) { + return false; + } + count += 1; + return true; + }); + *count_ptr = count; + return result; +} + +void AOTCodeReader::read_dbg_strings(DbgStrings& dbg_strings) { + // Read dbg strings + uint offset = read_position(); + uint count = *(uint *)addr(offset); + offset += sizeof(uint); + for (uint i = 0; i < count; i++) { + int string_id = *(uint *)addr(offset); + offset += sizeof(int); + const char* str = (const char*)_cache->address_for_C_string(string_id); + dbg_strings.insert(str); + } + set_read_position(offset); +} +#endif // PRODUCT + +//======================= AOTCodeAddressTable =============== + +// address table ids for generated routines, external addresses and C +// string addresses are partitioned into positive integer ranges +// defined by the following positive base and max values +// i.e. [_extrs_base, _extrs_base + _extrs_max -1], +// [_blobs_base, _blobs_base + _blobs_max -1], +// ... +// [_c_str_base, _c_str_base + _c_str_max -1], + +#define _extrs_max 100 +#define _stubs_max 3 + +#define _shared_blobs_max 20 +#define _C1_blobs_max 10 +#define _blobs_max (_shared_blobs_max+_C1_blobs_max) +#define _all_max (_extrs_max+_stubs_max+_blobs_max) + +#define _extrs_base 0 +#define _stubs_base (_extrs_base + _extrs_max) +#define _shared_blobs_base (_stubs_base + _stubs_max) +#define _C1_blobs_base (_shared_blobs_base + _shared_blobs_max) +#define _blobs_end (_shared_blobs_base + _blobs_max) + +#define SET_ADDRESS(type, addr) \ + { \ + type##_addr[type##_length++] = (address) (addr); \ + assert(type##_length <= type##_max, "increase size"); \ + } + +static bool initializing_extrs = false; + +void AOTCodeAddressTable::init_extrs() { + if (_extrs_complete || initializing_extrs) return; // Done already + + assert(_blobs_end <= _all_max, "AOTCodeAddress table ranges need adjusting"); + + initializing_extrs = true; + _extrs_addr = NEW_C_HEAP_ARRAY(address, _extrs_max, mtCode); + + _extrs_length = 0; + + // Record addresses of VM runtime methods + SET_ADDRESS(_extrs, SharedRuntime::fixup_callers_callsite); + SET_ADDRESS(_extrs, SharedRuntime::handle_wrong_method); + SET_ADDRESS(_extrs, SharedRuntime::handle_wrong_method_abstract); + SET_ADDRESS(_extrs, SharedRuntime::handle_wrong_method_ic_miss); +#if defined(AARCH64) && !defined(ZERO) + SET_ADDRESS(_extrs, JavaThread::aarch64_get_thread_helper); +#endif + { + // Required by Shared blobs + SET_ADDRESS(_extrs, Deoptimization::fetch_unroll_info); + SET_ADDRESS(_extrs, Deoptimization::unpack_frames); + SET_ADDRESS(_extrs, SafepointSynchronize::handle_polling_page_exception); + SET_ADDRESS(_extrs, SharedRuntime::resolve_opt_virtual_call_C); + SET_ADDRESS(_extrs, SharedRuntime::resolve_virtual_call_C); + SET_ADDRESS(_extrs, SharedRuntime::resolve_static_call_C); + SET_ADDRESS(_extrs, SharedRuntime::throw_delayed_StackOverflowError); + SET_ADDRESS(_extrs, SharedRuntime::throw_AbstractMethodError); + SET_ADDRESS(_extrs, SharedRuntime::throw_IncompatibleClassChangeError); + SET_ADDRESS(_extrs, SharedRuntime::throw_NullPointerException_at_call); + } + +#ifdef COMPILER1 + { + // Required by C1 blobs + SET_ADDRESS(_extrs, static_cast(SharedRuntime::dtrace_object_alloc)); + SET_ADDRESS(_extrs, SharedRuntime::exception_handler_for_return_address); + SET_ADDRESS(_extrs, SharedRuntime::register_finalizer); + SET_ADDRESS(_extrs, Runtime1::is_instance_of); + SET_ADDRESS(_extrs, Runtime1::exception_handler_for_pc); + SET_ADDRESS(_extrs, Runtime1::check_abort_on_vm_exception); + SET_ADDRESS(_extrs, Runtime1::new_instance); + SET_ADDRESS(_extrs, Runtime1::counter_overflow); + SET_ADDRESS(_extrs, Runtime1::new_type_array); + SET_ADDRESS(_extrs, Runtime1::new_object_array); + SET_ADDRESS(_extrs, Runtime1::new_multi_array); + SET_ADDRESS(_extrs, Runtime1::throw_range_check_exception); + SET_ADDRESS(_extrs, Runtime1::throw_index_exception); + SET_ADDRESS(_extrs, Runtime1::throw_div0_exception); + SET_ADDRESS(_extrs, Runtime1::throw_null_pointer_exception); + SET_ADDRESS(_extrs, Runtime1::throw_array_store_exception); + SET_ADDRESS(_extrs, Runtime1::throw_class_cast_exception); + SET_ADDRESS(_extrs, Runtime1::throw_incompatible_class_change_error); + SET_ADDRESS(_extrs, Runtime1::is_instance_of); + SET_ADDRESS(_extrs, Runtime1::monitorenter); + SET_ADDRESS(_extrs, Runtime1::monitorexit); + SET_ADDRESS(_extrs, Runtime1::deoptimize); + SET_ADDRESS(_extrs, Runtime1::access_field_patching); + SET_ADDRESS(_extrs, Runtime1::move_klass_patching); + SET_ADDRESS(_extrs, Runtime1::move_mirror_patching); + SET_ADDRESS(_extrs, Runtime1::move_appendix_patching); + SET_ADDRESS(_extrs, Runtime1::predicate_failed_trap); + SET_ADDRESS(_extrs, Runtime1::unimplemented_entry); + SET_ADDRESS(_extrs, Thread::current); + SET_ADDRESS(_extrs, CompressedKlassPointers::base_addr()); +#ifndef PRODUCT + SET_ADDRESS(_extrs, os::breakpoint); +#endif + } +#endif + +#ifdef COMPILER2 + { + // Required by C2 blobs + SET_ADDRESS(_extrs, Deoptimization::uncommon_trap); + SET_ADDRESS(_extrs, OptoRuntime::handle_exception_C); + SET_ADDRESS(_extrs, OptoRuntime::new_instance_C); + SET_ADDRESS(_extrs, OptoRuntime::new_array_C); + SET_ADDRESS(_extrs, OptoRuntime::new_array_nozero_C); + SET_ADDRESS(_extrs, OptoRuntime::multianewarray2_C); + SET_ADDRESS(_extrs, OptoRuntime::multianewarray3_C); + SET_ADDRESS(_extrs, OptoRuntime::multianewarray4_C); + SET_ADDRESS(_extrs, OptoRuntime::multianewarray5_C); + SET_ADDRESS(_extrs, OptoRuntime::multianewarrayN_C); +#if INCLUDE_JVMTI + SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_start); + SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_end); + SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_mount); + SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_unmount); +#endif + SET_ADDRESS(_extrs, OptoRuntime::complete_monitor_locking_C); + SET_ADDRESS(_extrs, OptoRuntime::monitor_notify_C); + SET_ADDRESS(_extrs, OptoRuntime::monitor_notifyAll_C); + SET_ADDRESS(_extrs, OptoRuntime::rethrow_C); + SET_ADDRESS(_extrs, OptoRuntime::slow_arraycopy_C); + SET_ADDRESS(_extrs, OptoRuntime::register_finalizer_C); +#if defined(AARCH64) + SET_ADDRESS(_extrs, JavaThread::verify_cross_modify_fence_failure); +#endif // AARCH64 + } +#endif // COMPILER2 + +#if INCLUDE_G1GC + SET_ADDRESS(_extrs, G1BarrierSetRuntime::write_ref_field_post_entry); + SET_ADDRESS(_extrs, G1BarrierSetRuntime::write_ref_field_pre_entry); +#endif +#if INCLUDE_SHENANDOAHGC + SET_ADDRESS(_extrs, ShenandoahRuntime::write_ref_field_pre); + SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom); + SET_ADDRESS(_extrs, ShenandoahRuntime::load_reference_barrier_phantom_narrow); +#endif +#if INCLUDE_ZGC + SET_ADDRESS(_extrs, ZBarrierSetRuntime::load_barrier_on_phantom_oop_field_preloaded_addr()); +#if defined(AMD64) + SET_ADDRESS(_extrs, &ZPointerLoadShift); +#endif +#endif +#ifndef ZERO +#if defined(AMD64) || defined(AARCH64) || defined(RISCV64) + SET_ADDRESS(_extrs, MacroAssembler::debug64); +#endif +#endif // ZERO + + _extrs_complete = true; + log_debug(aot, codecache, init)("External addresses recorded"); +} + +static bool initializing_early_stubs = false; + +void AOTCodeAddressTable::init_early_stubs() { + if (_complete || initializing_early_stubs) return; // Done already + initializing_early_stubs = true; + _stubs_addr = NEW_C_HEAP_ARRAY(address, _stubs_max, mtCode); + _stubs_length = 0; + SET_ADDRESS(_stubs, StubRoutines::forward_exception_entry()); + + { + // Required by C1 blobs +#if defined(AMD64) && !defined(ZERO) + SET_ADDRESS(_stubs, StubRoutines::x86::double_sign_flip()); + SET_ADDRESS(_stubs, StubRoutines::x86::d2l_fixup()); +#endif // AMD64 + } + + _early_stubs_complete = true; + log_info(aot, codecache, init)("Early stubs recorded"); +} + +static bool initializing_shared_blobs = false; + +void AOTCodeAddressTable::init_shared_blobs() { + if (_complete || initializing_shared_blobs) return; // Done already + initializing_shared_blobs = true; + address* blobs_addr = NEW_C_HEAP_ARRAY(address, _blobs_max, mtCode); + + // Divide _shared_blobs_addr array to chunks because they could be initialized in parrallel + _shared_blobs_addr = blobs_addr; + _C1_blobs_addr = _shared_blobs_addr + _shared_blobs_max; + + _shared_blobs_length = 0; + _C1_blobs_length = 0; + + // clear the address table + memset(blobs_addr, 0, sizeof(address)* _blobs_max); + + // Record addresses of generated code blobs + SET_ADDRESS(_shared_blobs, SharedRuntime::get_handle_wrong_method_stub()); + SET_ADDRESS(_shared_blobs, SharedRuntime::get_ic_miss_stub()); + SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->unpack()); + SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->unpack_with_exception()); + SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->unpack_with_reexecution()); + SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->unpack_with_exception_in_tls()); +#if INCLUDE_JVMCI + if (EnableJVMCI) { + SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->uncommon_trap()); + SET_ADDRESS(_shared_blobs, SharedRuntime::deopt_blob()->implicit_exception_uncommon_trap()); + } +#endif + + _shared_blobs_complete = true; + log_debug(aot, codecache, init)("Early shared blobs recorded"); + _complete = true; +} + +void AOTCodeAddressTable::init_early_c1() { +#ifdef COMPILER1 + // Runtime1 Blobs + for (int i = 0; i <= (int)C1StubId::forward_exception_id; i++) { + C1StubId id = (C1StubId)i; + if (Runtime1::blob_for(id) == nullptr) { + log_info(aot, codecache, init)("C1 blob %s is missing", Runtime1::name_for(id)); + continue; + } + if (Runtime1::entry_for(id) == nullptr) { + log_info(aot, codecache, init)("C1 blob %s is missing entry", Runtime1::name_for(id)); + continue; + } + address entry = Runtime1::entry_for(id); + SET_ADDRESS(_C1_blobs, entry); + } +#endif // COMPILER1 + assert(_C1_blobs_length <= _C1_blobs_max, "increase _C1_blobs_max to %d", _C1_blobs_length); + _early_c1_complete = true; +} + +#undef SET_ADDRESS + +AOTCodeAddressTable::~AOTCodeAddressTable() { + if (_extrs_addr != nullptr) { + FREE_C_HEAP_ARRAY(address, _extrs_addr); + } + if (_shared_blobs_addr != nullptr) { + FREE_C_HEAP_ARRAY(address, _shared_blobs_addr); + } +} + +#ifdef PRODUCT +#define MAX_STR_COUNT 200 +#else +#define MAX_STR_COUNT 500 +#endif +#define _c_str_max MAX_STR_COUNT +static const int _c_str_base = _all_max; + +static const char* _C_strings_in[MAX_STR_COUNT] = {nullptr}; // Incoming strings +static const char* _C_strings[MAX_STR_COUNT] = {nullptr}; // Our duplicates +static int _C_strings_count = 0; +static int _C_strings_s[MAX_STR_COUNT] = {0}; +static int _C_strings_id[MAX_STR_COUNT] = {0}; +static int _C_strings_used = 0; + +void AOTCodeCache::load_strings() { + uint strings_count = _load_header->strings_count(); + if (strings_count == 0) { + return; + } + uint strings_offset = _load_header->strings_offset(); + uint* string_lengths = (uint*)addr(strings_offset); + strings_offset += (strings_count * sizeof(uint)); + uint strings_size = _load_header->entries_offset() - strings_offset; + // We have to keep cached strings longer than _cache buffer + // because they are refernced from compiled code which may + // still be executed on VM exit after _cache is freed. + char* p = NEW_C_HEAP_ARRAY(char, strings_size+1, mtCode); + memcpy(p, addr(strings_offset), strings_size); + _C_strings_buf = p; + assert(strings_count <= MAX_STR_COUNT, "sanity"); + for (uint i = 0; i < strings_count; i++) { + _C_strings[i] = p; + uint len = string_lengths[i]; + _C_strings_s[i] = i; + _C_strings_id[i] = i; + p += len; + } + assert((uint)(p - _C_strings_buf) <= strings_size, "(" INTPTR_FORMAT " - " INTPTR_FORMAT ") = %d > %d ", p2i(p), p2i(_C_strings_buf), (uint)(p - _C_strings_buf), strings_size); + _C_strings_count = strings_count; + _C_strings_used = strings_count; + log_debug(aot, codecache, init)(" Loaded %d C strings of total length %d at offset %d from AOT Code Cache", _C_strings_count, strings_size, strings_offset); +} + +int AOTCodeCache::store_strings() { + if (_C_strings_used > 0) { + uint offset = _write_position; + uint length = 0; + uint* lengths = (uint *)reserve_bytes(sizeof(uint) * _C_strings_used); + if (lengths == nullptr) { + return -1; + } + for (int i = 0; i < _C_strings_used; i++) { + const char* str = _C_strings[_C_strings_s[i]]; + uint len = (uint)strlen(str) + 1; + length += len; + assert(len < 1000, "big string: %s", str); + lengths[i] = len; + uint n = write_bytes(str, len); + if (n != len) { + return -1; + } + } + log_debug(aot, codecache, exit)(" Wrote %d C strings of total length %d at offset %d to AOT Code Cache", + _C_strings_used, length, offset); + } + return _C_strings_used; +} + +const char* AOTCodeCache::add_C_string(const char* str) { + if (is_on_for_dump() && str != nullptr) { + return _cache->_table->add_C_string(str); + } + return str; +} + +const char* AOTCodeAddressTable::add_C_string(const char* str) { + if (_extrs_complete) { + LogStreamHandle(Trace, aot, codecache, stringtable) log; // ctor outside lock + MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag); + // Check previous strings address + for (int i = 0; i < _C_strings_count; i++) { + if (_C_strings_in[i] == str) { + return _C_strings[i]; // Found previous one - return our duplicate + } else if (strcmp(_C_strings[i], str) == 0) { + return _C_strings[i]; + } + } + // Add new one + if (_C_strings_count < MAX_STR_COUNT) { + // Passed in string can be freed and used space become inaccessible. + // Keep original address but duplicate string for future compare. + _C_strings_id[_C_strings_count] = -1; // Init + _C_strings_in[_C_strings_count] = str; + const char* dup = os::strdup(str); + _C_strings[_C_strings_count++] = dup; + if (log.is_enabled()) { + log.print_cr("add_C_string: [%d] " INTPTR_FORMAT " '%s'", _C_strings_count, p2i(dup), dup); + } + return dup; + } else { + assert(false, "Number of C strings >= MAX_STR_COUNT"); + } + } + return str; +} + +int AOTCodeAddressTable::id_for_C_string(address str) { + if (str == nullptr) { + return -1; + } + MutexLocker ml(AOTCodeCStrings_lock, Mutex::_no_safepoint_check_flag); + for (int i = 0; i < _C_strings_count; i++) { + if (_C_strings[i] == (const char*)str) { // found + int id = _C_strings_id[i]; + if (id >= 0) { + assert(id < _C_strings_used, "%d >= %d", id , _C_strings_used); + return id; // Found recorded + } + // Not found in recorded, add new + id = _C_strings_used++; + _C_strings_s[id] = i; + _C_strings_id[i] = id; + return id; + } + } + return -1; +} + +address AOTCodeAddressTable::address_for_C_string(int idx) { + assert(idx < _C_strings_count, "sanity"); + return (address)_C_strings[idx]; +} + +static int search_address(address addr, address* table, uint length) { + for (int i = 0; i < (int)length; i++) { + if (table[i] == addr) { + return i; + } + } + return BAD_ADDRESS_ID; +} + +address AOTCodeAddressTable::address_for_id(int idx) { + assert(_extrs_complete, "AOT Code Cache VM runtime addresses table is not complete"); + if (idx == -1) { + return (address)-1; + } + uint id = (uint)idx; + // special case for symbols based relative to os::init + if (id > (_c_str_base + _c_str_max)) { + return (address)os::init + idx; + } + if (idx < 0) { + fatal("Incorrect id %d for AOT Code Cache addresses table", id); + return nullptr; + } + // no need to compare unsigned id against 0 + if (/* id >= _extrs_base && */ id < _extrs_length) { + return _extrs_addr[id - _extrs_base]; + } + if (id >= _stubs_base && id < _stubs_base + _stubs_length) { + return _stubs_addr[id - _stubs_base]; + } + if (id >= _shared_blobs_base && id < _shared_blobs_base + _shared_blobs_length) { + return _shared_blobs_addr[id - _shared_blobs_base]; + } + if (id >= _C1_blobs_base && id < _C1_blobs_base + _C1_blobs_length) { + return _C1_blobs_addr[id - _C1_blobs_base]; + } + if (id >= _c_str_base && id < (_c_str_base + (uint)_C_strings_count)) { + return address_for_C_string(id - _c_str_base); + } + fatal("Incorrect id %d for AOT Code Cache addresses table", id); + return nullptr; +} + +int AOTCodeAddressTable::id_for_address(address addr, RelocIterator reloc, CodeBlob* code_blob) { + assert(_extrs_complete, "AOT Code Cache VM runtime addresses table is not complete"); + int id = -1; + if (addr == (address)-1) { // Static call stub has jump to itself + return id; + } + // Seach for C string + id = id_for_C_string(addr); + if (id >= 0) { + return id + _c_str_base; + } + if (StubRoutines::contains(addr)) { + // Search in stubs + id = search_address(addr, _stubs_addr, _stubs_length); + if (id < 0) { + StubCodeDesc* desc = StubCodeDesc::desc_for(addr); + if (desc == nullptr) { + desc = StubCodeDesc::desc_for(addr + frame::pc_return_offset); + } + const char* sub_name = (desc != nullptr) ? desc->name() : ""; + assert(false, "Address " INTPTR_FORMAT " for Stub:%s is missing in AOT Code Cache addresses table", p2i(addr), sub_name); + } else { + return id + _stubs_base; + } + } else { + CodeBlob* cb = CodeCache::find_blob(addr); + if (cb != nullptr) { + // Search in code blobs + int id_base = _shared_blobs_base; + id = search_address(addr, _shared_blobs_addr, _blobs_max); + if (id < 0) { + assert(false, "Address " INTPTR_FORMAT " for Blob:%s is missing in AOT Code Cache addresses table", p2i(addr), cb->name()); + } else { + return id_base + id; + } + } else { + // Search in runtime functions + id = search_address(addr, _extrs_addr, _extrs_length); + if (id < 0) { + ResourceMark rm; + const int buflen = 1024; + char* func_name = NEW_RESOURCE_ARRAY(char, buflen); + int offset = 0; + if (os::dll_address_to_function_name(addr, func_name, buflen, &offset)) { + if (offset > 0) { + // Could be address of C string + uint dist = (uint)pointer_delta(addr, (address)os::init, 1); + log_debug(aot, codecache)("Address " INTPTR_FORMAT " (offset %d) for runtime target '%s' is missing in AOT Code Cache addresses table", + p2i(addr), dist, (const char*)addr); + assert(dist > (uint)(_all_max + MAX_STR_COUNT), "change encoding of distance"); + return dist; + } +#ifdef ASSERT + reloc.print_current_on(tty); + code_blob->print_on(tty); + code_blob->print_code_on(tty); + assert(false, "Address " INTPTR_FORMAT " for runtime target '%s+%d' is missing in AOT Code Cache addresses table", p2i(addr), func_name, offset); +#endif + } else { +#ifdef ASSERT + reloc.print_current_on(tty); + code_blob->print_on(tty); + code_blob->print_code_on(tty); + os::find(addr, tty); + assert(false, "Address " INTPTR_FORMAT " for /('%s') is missing in AOT Code Cache addresses table", p2i(addr), (const char*)addr); +#endif + } + } else { + return _extrs_base + id; + } + } + } + return id; +} + +void AOTCodeCache::print_on(outputStream* st) { + AOTCodeCache* cache = open_for_use(); + if (cache != nullptr) { + uint count = cache->_load_header->entries_count(); + uint* search_entries = (uint*)cache->addr(cache->_load_header->entries_offset()); // [id, index] + AOTCodeEntry* load_entries = (AOTCodeEntry*)(search_entries + 2 * count); + + for (uint i = 0; i < count; i++) { + // Use search_entries[] to order ouput + int index = search_entries[2*i + 1]; + AOTCodeEntry* entry = &(load_entries[index]); + + uint entry_position = entry->offset(); + uint name_offset = entry->name_offset() + entry_position; + const char* saved_name = cache->addr(name_offset); + + st->print_cr("%4u: entry_idx:%4u Kind:%u Id:%u size=%u '%s'", + i, index, entry->kind(), entry->id(), entry->size(), saved_name); + } + } else { + st->print_cr("failed to map code cache"); + } +} diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp new file mode 100644 index 00000000000..e7b056ac974 --- /dev/null +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_CODE_AOTCODECACHE_HPP +#define SHARE_CODE_AOTCODECACHE_HPP + +/* + * AOT Code Cache collects code from Code Cache and corresponding metadata + * during application training run. + * In following "production" runs this code and data can be loaded into + * Code Cache skipping its generation. + */ + +class CodeBuffer; +class RelocIterator; +class AOTCodeCache; +class AdapterBlob; +class ExceptionBlob; +class ImmutableOopMapSet; +class AsmRemarks; +class DbgStrings; + +enum class vmIntrinsicID : int; +enum CompLevel : signed char; + +#define DO_AOTCODEENTRY_KIND(Fn) \ + Fn(None) \ + Fn(Adapter) \ + Fn(SharedBlob) \ + Fn(C1Blob) \ + Fn(C2Blob) \ + +// Descriptor of AOT Code Cache's entry +class AOTCodeEntry { +public: + enum Kind : s1 { +#define DECL_KIND_ENUM(kind) kind, + DO_AOTCODEENTRY_KIND(DECL_KIND_ENUM) +#undef DECL_KIND_ENUM + Kind_count + }; + +private: + AOTCodeEntry* _next; + Kind _kind; + uint _id; // Adapter's id, vmIntrinsic::ID for stub or name's hash for nmethod + uint _offset; // Offset to entry + uint _size; // Entry size + uint _name_offset; // Code blob name + uint _name_size; + uint _blob_offset; // Start of code in cache + bool _has_oop_maps; + address _dumptime_content_start_addr; // CodeBlob::content_begin() at dump time; used for applying relocations + +public: + AOTCodeEntry(Kind kind, uint id, + uint offset, uint size, + uint name_offset, uint name_size, + uint blob_offset, bool has_oop_maps, + address dumptime_content_start_addr) { + _next = nullptr; + _kind = kind; + _id = id; + _offset = offset; + _size = size; + _name_offset = name_offset; + _name_size = name_size; + _blob_offset = blob_offset; + _has_oop_maps = has_oop_maps; + _dumptime_content_start_addr = dumptime_content_start_addr; + } + void* operator new(size_t x, AOTCodeCache* cache); + // Delete is a NOP + void operator delete( void *ptr ) {} + + AOTCodeEntry* next() const { return _next; } + void set_next(AOTCodeEntry* next) { _next = next; } + + Kind kind() const { return _kind; } + uint id() const { return _id; } + + uint offset() const { return _offset; } + void set_offset(uint off) { _offset = off; } + + uint size() const { return _size; } + uint name_offset() const { return _name_offset; } + uint name_size() const { return _name_size; } + uint blob_offset() const { return _blob_offset; } + bool has_oop_maps() const { return _has_oop_maps; } + address dumptime_content_start_addr() const { return _dumptime_content_start_addr; } + + static bool is_valid_entry_kind(Kind kind) { return kind > None && kind < Kind_count; } + static bool is_blob(Kind kind) { return kind == SharedBlob || kind == C1Blob || kind == C2Blob; } + static bool is_adapter(Kind kind) { return kind == Adapter; } +}; + +// Addresses of stubs, blobs and runtime finctions called from compiled code. +class AOTCodeAddressTable : public CHeapObj { +private: + address* _extrs_addr; + address* _stubs_addr; + address* _shared_blobs_addr; + address* _C1_blobs_addr; + uint _extrs_length; + uint _stubs_length; + uint _shared_blobs_length; + uint _C1_blobs_length; + + bool _extrs_complete; + bool _early_stubs_complete; + bool _shared_blobs_complete; + bool _early_c1_complete; + bool _complete; + +public: + AOTCodeAddressTable() : + _extrs_addr(nullptr), + _shared_blobs_addr(nullptr), + _C1_blobs_addr(nullptr), + _extrs_length(0), + _stubs_length(0), + _shared_blobs_length(0), + _C1_blobs_length(0), + _extrs_complete(false), + _early_stubs_complete(false), + _shared_blobs_complete(false), + _early_c1_complete(false), + _complete(false) + { } + ~AOTCodeAddressTable(); + void init_extrs(); + void init_early_stubs(); + void init_shared_blobs(); + void init_early_c1(); + const char* add_C_string(const char* str); + int id_for_C_string(address str); + address address_for_C_string(int idx); + int id_for_address(address addr, RelocIterator iter, CodeBlob* code_blob); + address address_for_id(int id); +}; + +class AOTCodeCache : public CHeapObj { + +// Classes used to describe AOT code cache. +protected: + class Config { + address _compressedOopBase; + uint _compressedOopShift; + uint _compressedKlassShift; + uint _contendedPaddingWidth; + uint _gc; + enum Flags { + none = 0, + debugVM = 1, + compressedOops = 2, + compressedClassPointers = 4, + useTLAB = 8, + systemClassAssertions = 16, + userClassAssertions = 32, + enableContendedPadding = 64, + restrictContendedPadding = 128 + }; + uint _flags; + + public: + void record(); + bool verify() const; + }; + + class Header : public CHeapObj { + private: + enum { + AOT_CODE_VERSION = 1 + }; + uint _version; // AOT code version (should match when reading code cache) + uint _cache_size; // cache size in bytes + uint _strings_count; // number of recorded C strings + uint _strings_offset; // offset to recorded C strings + uint _entries_count; // number of recorded entries + uint _entries_offset; // offset of AOTCodeEntry array describing entries + uint _adapters_count; + uint _shared_blobs_count; + uint _C1_blobs_count; + uint _C2_blobs_count; + Config _config; + + public: + void init(uint cache_size, + uint strings_count, uint strings_offset, + uint entries_count, uint entries_offset, + uint adapters_count, uint shared_blobs_count, + uint C1_blobs_count, uint C2_blobs_count) { + _version = AOT_CODE_VERSION; + _cache_size = cache_size; + _strings_count = strings_count; + _strings_offset = strings_offset; + _entries_count = entries_count; + _entries_offset = entries_offset; + _adapters_count = adapters_count; + _shared_blobs_count = shared_blobs_count; + _C1_blobs_count = C1_blobs_count; + _C2_blobs_count = C2_blobs_count; + _config.record(); + } + + + uint cache_size() const { return _cache_size; } + uint strings_count() const { return _strings_count; } + uint strings_offset() const { return _strings_offset; } + uint entries_count() const { return _entries_count; } + uint entries_offset() const { return _entries_offset; } + uint adapters_count() const { return _adapters_count; } + uint shared_blobs_count() const { return _shared_blobs_count; } + uint C1_blobs_count() const { return _C1_blobs_count; } + uint C2_blobs_count() const { return _C2_blobs_count; } + + bool verify(uint load_size) const; + bool verify_config() const { // Called after Universe initialized + return _config.verify(); + } + }; + +// Continue with AOTCodeCache class definition. +private: + Header* _load_header; + char* _load_buffer; // Aligned buffer for loading cached code + char* _store_buffer; // Aligned buffer for storing cached code + char* _C_store_buffer; // Original unaligned buffer + + uint _write_position; // Position in _store_buffer + uint _load_size; // Used when reading cache + uint _store_size; // Used when writing cache + bool _for_use; // AOT cache is open for using AOT code + bool _for_dump; // AOT cache is open for dumping AOT code + bool _closing; // Closing cache file + bool _failed; // Failed read/write to/from cache (cache is broken?) + bool _lookup_failed; // Failed to lookup for info (skip only this code load) + + AOTCodeAddressTable* _table; + + AOTCodeEntry* _load_entries; // Used when reading cache + uint* _search_entries; // sorted by ID table [id, index] + AOTCodeEntry* _store_entries; // Used when writing cache + const char* _C_strings_buf; // Loaded buffer for _C_strings[] table + uint _store_entries_cnt; + + static AOTCodeCache* open_for_use(); + static AOTCodeCache* open_for_dump(); + + bool set_write_position(uint pos); + bool align_write(); + address reserve_bytes(uint nbytes); + uint write_bytes(const void* buffer, uint nbytes); + const char* addr(uint offset) const { return _load_buffer + offset; } + static AOTCodeAddressTable* addr_table() { + return is_on() && (cache()->_table != nullptr) ? cache()->_table : nullptr; + } + + void set_lookup_failed() { _lookup_failed = true; } + void clear_lookup_failed() { _lookup_failed = false; } + bool lookup_failed() const { return _lookup_failed; } + +public: + AOTCodeCache(bool is_dumping, bool is_using); + ~AOTCodeCache(); + + const char* cache_buffer() const { return _load_buffer; } + bool failed() const { return _failed; } + void set_failed() { _failed = true; } + + static uint max_aot_code_size(); + + uint load_size() const { return _load_size; } + uint write_position() const { return _write_position; } + + void load_strings(); + int store_strings(); + + static void init_shared_blobs_table() NOT_CDS_RETURN; + static void init_early_c1_table() NOT_CDS_RETURN; + + address address_for_C_string(int idx) const { return _table->address_for_C_string(idx); } + address address_for_id(int id) const { return _table->address_for_id(id); } + + bool for_use() const { return _for_use && !_failed; } + bool for_dump() const { return _for_dump && !_failed; } + + bool closing() const { return _closing; } + + AOTCodeEntry* add_entry() { + _store_entries_cnt++; + _store_entries -= 1; + return _store_entries; + } + + AOTCodeEntry* find_entry(AOTCodeEntry::Kind kind, uint id); + + bool finish_write(); + + bool write_relocations(CodeBlob& code_blob); + bool write_oop_map_set(CodeBlob& cb); +#ifndef PRODUCT + bool write_asm_remarks(CodeBlob& cb); + bool write_dbg_strings(CodeBlob& cb); +#endif // PRODUCT + + static bool store_code_blob(CodeBlob& blob, + AOTCodeEntry::Kind entry_kind, + uint id, const char* name, + int entry_offset_count = 0, + int* entry_offsets = nullptr) NOT_CDS_RETURN_(false); + + static CodeBlob* load_code_blob(AOTCodeEntry::Kind kind, + uint id, const char* name, + int entry_offset_count = 0, + int* entry_offsets = nullptr) NOT_CDS_RETURN_(nullptr); + + static uint store_entries_cnt() { + if (is_on_for_dump()) { + return cache()->_store_entries_cnt; + } + return -1; + } + +// Static access + +private: + static AOTCodeCache* _cache; + + static bool open_cache(bool is_dumping, bool is_using); + bool verify_config() { + if (for_use()) { + return _load_header->verify_config(); + } + return true; + } +public: + static AOTCodeCache* cache() { return _cache; } + static void initialize() NOT_CDS_RETURN; + static void init2() NOT_CDS_RETURN; + static void close() NOT_CDS_RETURN; + static bool is_on() CDS_ONLY({ return _cache != nullptr && !_cache->closing(); }) NOT_CDS_RETURN_(false); + static bool is_on_for_use() { return is_on() && _cache->for_use(); } + static bool is_on_for_dump() { return is_on() && _cache->for_dump(); } + + static bool is_dumping_adapter() NOT_CDS_RETURN_(false); + static bool is_using_adapter() NOT_CDS_RETURN_(false); + + static bool is_dumping_stub() NOT_CDS_RETURN_(false); + static bool is_using_stub() NOT_CDS_RETURN_(false); + + static const char* add_C_string(const char* str) NOT_CDS_RETURN_(str); + + static void print_on(outputStream* st) NOT_CDS_RETURN; +}; + +// Concurent AOT code reader +class AOTCodeReader { +private: + const AOTCodeCache* _cache; + const AOTCodeEntry* _entry; + const char* _load_buffer; // Loaded cached code buffer + uint _read_position; // Position in _load_buffer + uint read_position() const { return _read_position; } + void set_read_position(uint pos); + const char* addr(uint offset) const { return _load_buffer + offset; } + + bool _lookup_failed; // Failed to lookup for info (skip only this code load) + void set_lookup_failed() { _lookup_failed = true; } + void clear_lookup_failed() { _lookup_failed = false; } + bool lookup_failed() const { return _lookup_failed; } + + AOTCodeEntry* aot_code_entry() { return (AOTCodeEntry*)_entry; } +public: + AOTCodeReader(AOTCodeCache* cache, AOTCodeEntry* entry); + + CodeBlob* compile_code_blob(const char* name, int entry_offset_count, int* entry_offsets); + + ImmutableOopMapSet* read_oop_map_set(); + + void fix_relocations(CodeBlob* code_blob); +#ifndef PRODUCT + void read_asm_remarks(AsmRemarks& asm_remarks); + void read_dbg_strings(DbgStrings& dbg_strings); +#endif // PRODUCT +}; + +#endif // SHARE_CODE_AOTCODECACHE_HPP diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 4ae4ccbc858..5bb37c198d0 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -78,9 +78,12 @@ const BufferBlob::Vptr BufferBlob::_vpntr; const RuntimeStub::Vptr RuntimeStub::_vpntr; const SingletonBlob::Vptr SingletonBlob::_vpntr; const DeoptimizationBlob::Vptr DeoptimizationBlob::_vpntr; +#ifdef COMPILER2 +const ExceptionBlob::Vptr ExceptionBlob::_vpntr; +#endif // COMPILER2 const UpcallStub::Vptr UpcallStub::_vpntr; -const CodeBlob::Vptr* CodeBlob::vptr() const { +const CodeBlob::Vptr* CodeBlob::vptr(CodeBlobKind kind) { constexpr const CodeBlob::Vptr* array[(size_t)CodeBlobKind::Number_Of_Kinds] = { nullptr/* None */, &nmethod::_vpntr, @@ -98,7 +101,11 @@ const CodeBlob::Vptr* CodeBlob::vptr() const { &UpcallStub::_vpntr }; - return array[(size_t)_kind]; + return array[(size_t)kind]; +} + +const CodeBlob::Vptr* CodeBlob::vptr() const { + return vptr(_kind); } unsigned int CodeBlob::align_code_offset(int offset) { @@ -181,6 +188,19 @@ CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t heade assert(_mutable_data = blob_end(), "sanity"); } +void CodeBlob::restore_mutable_data(address reloc_data) { + // Relocation data is now stored as part of the mutable data area; allocate it before copy relocations + if (_mutable_data_size > 0) { + _mutable_data = (address)os::malloc(_mutable_data_size, mtCode); + if (_mutable_data == nullptr) { + vm_exit_out_of_memory(_mutable_data_size, OOM_MALLOC_ERROR, "codebuffer: no space for mutable data"); + } + } + if (_relocation_size > 0) { + memcpy((address)relocation_begin(), reloc_data, relocation_size()); + } +} + void CodeBlob::purge() { assert(_mutable_data != nullptr, "should never be null"); if (_mutable_data != blob_end()) { @@ -215,6 +235,81 @@ void CodeBlob::print_code_on(outputStream* st) { Disassembler::decode(this, st); } +void CodeBlob::prepare_for_archiving_impl() { + set_name(nullptr); + _oop_maps = nullptr; + _mutable_data = nullptr; +#ifndef PRODUCT + asm_remarks().clear(); + dbg_strings().clear(); +#endif /* PRODUCT */ +} + +void CodeBlob::prepare_for_archiving() { + vptr(_kind)->prepare_for_archiving(this); +} + +void CodeBlob::archive_blob(CodeBlob* blob, address archive_buffer) { + blob->copy_to(archive_buffer); + CodeBlob* archived_blob = (CodeBlob*)archive_buffer; + archived_blob->prepare_for_archiving(); +} + +void CodeBlob::post_restore_impl() { + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); +} + +void CodeBlob::post_restore() { + vptr(_kind)->post_restore(this); +} + +CodeBlob* CodeBlob::restore(address code_cache_buffer, + const char* name, + address archived_reloc_data, + ImmutableOopMapSet* archived_oop_maps) +{ + copy_to(code_cache_buffer); + CodeBlob* code_blob = (CodeBlob*)code_cache_buffer; + code_blob->set_name(name); + code_blob->restore_mutable_data(archived_reloc_data); + code_blob->set_oop_maps(archived_oop_maps); + return code_blob; +} + +CodeBlob* CodeBlob::create(CodeBlob* archived_blob, + const char* name, + address archived_reloc_data, + ImmutableOopMapSet* archived_oop_maps + ) +{ + ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + + CodeCache::gc_on_allocation(); + + CodeBlob* blob = nullptr; + unsigned int size = archived_blob->size(); + { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + address code_cache_buffer = (address)CodeCache::allocate(size, CodeBlobType::NonNMethod); + if (code_cache_buffer != nullptr) { + blob = archived_blob->restore(code_cache_buffer, + name, + archived_reloc_data, + archived_oop_maps); + assert(blob != nullptr, "sanity check"); + + // Flush the code block + ICache::invalidate_range(blob->code_begin(), blob->code_size()); + CodeCache::commit(blob); // Count adapters + } + } + if (blob != nullptr) { + blob->post_restore(); + } + return blob; +} + //----------------------------------------------------------------------------------------- // Creates a RuntimeBlob from a CodeBuffer and copy code and relocation info. @@ -720,7 +815,7 @@ void CodeBlob::print_value_on(outputStream* st) const { } void CodeBlob::print_on_impl(outputStream* st) const { - st->print_cr("[CodeBlob (" INTPTR_FORMAT ")]", p2i(this)); + st->print_cr("[CodeBlob kind:%d (" INTPTR_FORMAT ")]", (int)_kind, p2i(this)); st->print_cr("Framesize: %d", _frame_size); } diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 1daa35c16b5..f1920a829fc 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -97,11 +97,19 @@ enum class CodeBlobKind : u1 { class UpcallStub; // for as_upcall_stub() class RuntimeStub; // for as_runtime_stub() class JavaFrameAnchor; // for UpcallStub::jfa_for_frame +class AdapterBlob; +class ExceptionBlob; +class DeoptimizationBlob; +class SafepointBlob; +class UncommonTrapBlob; class CodeBlob { friend class VMStructs; friend class JVMCIVMStructs; +private: + void restore_mutable_data(address reloc_data); + protected: // order fields from large to small to minimize padding between fields ImmutableOopMapSet* _oop_maps; // OopMap for this CodeBlob @@ -140,8 +148,15 @@ class CodeBlob { public: virtual void print_on(const CodeBlob* instance, outputStream* st) const = 0; virtual void print_value_on(const CodeBlob* instance, outputStream* st) const = 0; + virtual void prepare_for_archiving(CodeBlob* instance) const { + instance->prepare_for_archiving_impl(); + }; + virtual void post_restore(CodeBlob* instance) const { + instance->post_restore_impl(); + }; }; + static const Vptr* vptr(CodeBlobKind kind); const Vptr* vptr() const; CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size, uint16_t header_size, @@ -151,8 +166,12 @@ class CodeBlob { // Simple CodeBlob used for simple BufferBlob. CodeBlob(const char* name, CodeBlobKind kind, int size, uint16_t header_size); + void operator delete(void* p) { } + void prepare_for_archiving_impl(); + void post_restore_impl(); + public: ~CodeBlob() { @@ -188,8 +207,13 @@ class CodeBlob { nmethod* as_nmethod_or_null() const { return is_nmethod() ? (nmethod*) this : nullptr; } nmethod* as_nmethod() const { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; } CodeBlob* as_codeblob() const { return (CodeBlob*) this; } + AdapterBlob* as_adapter_blob() const { assert(is_adapter_blob(), "must be adapter blob"); return (AdapterBlob*) this; } + ExceptionBlob* as_exception_blob() const { assert(is_exception_stub(), "must be exception stub"); return (ExceptionBlob*) this; } + DeoptimizationBlob* as_deoptimization_blob() const { assert(is_deoptimization_stub(), "must be deopt stub"); return (DeoptimizationBlob*) this; } + SafepointBlob* as_safepoint_blob() const { assert(is_safepoint_stub(), "must be safepoint stub"); return (SafepointBlob*) this; } UpcallStub* as_upcall_stub() const { assert(is_upcall_stub(), "must be upcall stub"); return (UpcallStub*) this; } RuntimeStub* as_runtime_stub() const { assert(is_runtime_stub(), "must be runtime blob"); return (RuntimeStub*) this; } + UncommonTrapBlob* as_uncommon_trap_blob() const { assert(is_uncommon_trap_stub(), "must be uncommon trap stub"); return (UncommonTrapBlob*) this; } // Boundaries address header_begin() const { return (address) this; } @@ -244,6 +268,7 @@ class CodeBlob { // OopMap for frame ImmutableOopMapSet* oop_maps() const { return _oop_maps; } void set_oop_maps(OopMapSet* p); + void set_oop_maps(ImmutableOopMapSet* p) { _oop_maps = p; } const ImmutableOopMap* oop_map_for_slot(int slot, address return_address) const; const ImmutableOopMap* oop_map_for_return_address(address return_address) const; @@ -278,6 +303,22 @@ class CodeBlob { void use_remarks(AsmRemarks &remarks) { _asm_remarks.share(remarks); } void use_strings(DbgStrings &strings) { _dbg_strings.share(strings); } #endif + + void copy_to(address buffer) { + memcpy(buffer, this, this->size()); + } + + // methods to archive a blob into AOT code cache + void prepare_for_archiving(); + static void archive_blob(CodeBlob* blob, address archive_buffer); + + // methods to restore a blob from AOT code cache into the CodeCache + void post_restore(); + CodeBlob* restore(address code_cache_buffer, const char* name, address archived_reloc_data, ImmutableOopMapSet* archived_oop_maps); + static CodeBlob* create(CodeBlob* archived_blob, + const char* name, + address archived_reloc_data, + ImmutableOopMapSet* archived_oop_maps); }; //---------------------------------------------------------------------------------------------------- @@ -617,6 +658,18 @@ class ExceptionBlob: public SingletonBlob { OopMapSet* oop_maps, int frame_size ); + + void post_restore_impl() { + trace_new_stub(this, "ExceptionBlob"); + } + + class Vptr : public SingletonBlob::Vptr { + void post_restore(CodeBlob* instance) const override { + ((ExceptionBlob*)instance)->post_restore_impl(); + } + }; + + static const Vptr _vpntr; }; #endif // COMPILER2 diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 902d4345622..3a5da1d7cd2 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1361,7 +1361,7 @@ void CodeCache::make_marked_nmethods_deoptimized() { while(iter.next()) { nmethod* nm = iter.method(); if (nm->is_marked_for_deoptimization() && !nm->has_been_deoptimized() && nm->can_be_deoptimized()) { - nm->make_not_entrant("marked for deoptimization"); + nm->make_not_entrant(nmethod::ChangeReason::marked_for_deoptimization); nm->make_deoptimized(); } } diff --git a/src/hotspot/share/code/debugInfoRec.cpp b/src/hotspot/share/code/debugInfoRec.cpp index 02cd23407bf..8449f5d6929 100644 --- a/src/hotspot/share/code/debugInfoRec.cpp +++ b/src/hotspot/share/code/debugInfoRec.cpp @@ -140,7 +140,7 @@ DebugInformationRecorder::DebugInformationRecorder(OopRecorder* oop_recorder) add_new_pc_offset(PcDesc::lower_offset_limit); // sentinel record - debug_only(_recording_state = rs_null); + DEBUG_ONLY(_recording_state = rs_null); } @@ -159,7 +159,7 @@ void DebugInformationRecorder::add_safepoint(int pc_offset, OopMap* map) { add_new_pc_offset(pc_offset); assert(_recording_state == rs_null, "nesting of recording calls"); - debug_only(_recording_state = rs_safepoint); + DEBUG_ONLY(_recording_state = rs_safepoint); } void DebugInformationRecorder::add_non_safepoint(int pc_offset) { @@ -169,7 +169,7 @@ void DebugInformationRecorder::add_non_safepoint(int pc_offset) { add_new_pc_offset(pc_offset); assert(_recording_state == rs_null, "nesting of recording calls"); - debug_only(_recording_state = rs_non_safepoint); + DEBUG_ONLY(_recording_state = rs_non_safepoint); } void DebugInformationRecorder::add_new_pc_offset(int pc_offset) { @@ -360,7 +360,7 @@ void DebugInformationRecorder::dump_object_pool(GrowableArray* obje void DebugInformationRecorder::end_scopes(int pc_offset, bool is_safepoint) { assert(_recording_state == (is_safepoint? rs_safepoint: rs_non_safepoint), "nesting of recording calls"); - debug_only(_recording_state = rs_null); + DEBUG_ONLY(_recording_state = rs_null); // Try to compress away an equivalent non-safepoint predecessor. // (This only works because we have previously recognized redundant @@ -413,13 +413,13 @@ DebugToken* DebugInformationRecorder::create_monitor_values(GrowableArrayposition(); } int DebugInformationRecorder::pcs_size() { - debug_only(mark_recorders_frozen()); // mark it "frozen" for asserts + DEBUG_ONLY(mark_recorders_frozen()); // mark it "frozen" for asserts if (last_pc()->pc_offset() != PcDesc::upper_offset_limit) add_new_pc_offset(PcDesc::upper_offset_limit); return _pcs_length * sizeof(PcDesc); diff --git a/src/hotspot/share/code/dependencyContext.cpp b/src/hotspot/share/code/dependencyContext.cpp index 2b3253030c5..a8ef707978d 100644 --- a/src/hotspot/share/code/dependencyContext.cpp +++ b/src/hotspot/share/code/dependencyContext.cpp @@ -91,18 +91,40 @@ void DependencyContext::mark_dependent_nmethods(DeoptimizationScope* deopt_scope // void DependencyContext::add_dependent_nmethod(nmethod* nm) { assert_lock_strong(CodeCache_lock); - for (nmethodBucket* b = dependencies_not_unloading(); b != nullptr; b = b->next_not_unloading()) { - if (nm == b->get_nmethod()) { - return; - } + assert(nm->is_not_installed(), "Precondition: new nmethod"); + + // This method tries to add never before seen nmethod, holding the CodeCache_lock + // until all dependencies are added. The caller code can call multiple times + // with the same nmethod, but always under the same lock hold. + // + // This means the buckets list is guaranteed to be in either of two states, with + // regards to the newly added nmethod: + // 1. The nmethod is not in the list, and can be just added to the head of the list. + // 2. The nmethod is in the list, and it is already at the head of the list. + // + // This path is the only path that adds to the list. There can be concurrent removals + // from the list, but they do not break this invariant. This invariant allows us + // to skip list scans. The individual method checks are cheap, but walking the large + // list of dependencies gets expensive. + + nmethodBucket* head = Atomic::load(_dependency_context_addr); + if (head != nullptr && nm == head->get_nmethod()) { + return; + } + +#ifdef ASSERT + for (nmethodBucket* b = head; b != nullptr; b = b->next()) { + assert(nm != b->get_nmethod(), "Invariant: should not be in the list yet"); } +#endif + nmethodBucket* new_head = new nmethodBucket(nm, nullptr); for (;;) { - nmethodBucket* head = Atomic::load(_dependency_context_addr); new_head->set_next(head); if (Atomic::cmpxchg(_dependency_context_addr, head, new_head) == head) { break; } + head = Atomic::load(_dependency_context_addr); } if (UsePerfData) { _perf_total_buckets_allocated_count->inc(); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 01ace66f4de..acebaae6ba4 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -28,6 +28,7 @@ #include "code/dependencies.hpp" #include "code/nativeInst.hpp" #include "code/nmethod.inline.hpp" +#include "code/relocInfo.hpp" #include "code/scopeDesc.hpp" #include "compiler/abstractCompiler.hpp" #include "compiler/compilationLog.hpp" @@ -112,7 +113,7 @@ // Cast from int value to narrow type #define CHECKED_CAST(result, T, thing) \ result = static_cast(thing); \ - assert(static_cast(result) == thing, "failed: %d != %d", static_cast(result), thing); + guarantee(static_cast(result) == thing, "failed: %d != %d", static_cast(result), thing); //--------------------------------------------------------------------------------- // NMethod statistics @@ -392,7 +393,9 @@ static inline bool match_desc(PcDesc* pc, int pc_offset, bool approximate) { if (!approximate) { return pc->pc_offset() == pc_offset; } else { - return (pc-1)->pc_offset() < pc_offset && pc_offset <= pc->pc_offset(); + // Do not look before the sentinel + assert(pc_offset > PcDesc::lower_offset_limit, "illegal pc_offset"); + return pc_offset <= pc->pc_offset() && (pc-1)->pc_offset() < pc_offset; } } @@ -785,6 +788,8 @@ class CheckClass : public MetadataClosure { klass = ((Method*)md)->method_holder(); } else if (md->is_methodData()) { klass = ((MethodData*)md)->method()->method_holder(); + } else if (md->is_methodCounters()) { + klass = ((MethodCounters*)md)->method()->method_holder(); } else { md->print(); ShouldNotReachHere(); @@ -1122,7 +1127,7 @@ nmethod* nmethod::new_native_nmethod(const methodHandle& method, if (nm != nullptr) { // verify nmethod - debug_only(nm->verify();) // might block + DEBUG_ONLY(nm->verify();) // might block nm->log_new_nmethod(); } @@ -1269,7 +1274,7 @@ void nmethod::post_init() { finalize_relocations(); Universe::heap()->register_nmethod(this); - debug_only(Universe::heap()->verify_nmethod(this)); + DEBUG_ONLY(Universe::heap()->verify_nmethod(this)); CodeCache::commit(this); } @@ -1296,7 +1301,7 @@ nmethod::nmethod( _native_basic_lock_sp_offset(basic_lock_sp_offset) { { - debug_only(NoSafepointVerifier nsv;) + DEBUG_ONLY(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); init_defaults(code_buffer, offsets); @@ -1323,8 +1328,9 @@ nmethod::nmethod( _unwind_handler_offset = 0; CHECKED_CAST(_oops_size, uint16_t, align_up(code_buffer->total_oop_size(), oopSize)); - int metadata_size = align_up(code_buffer->total_metadata_size(), wordSize); - JVMCI_ONLY( _jvmci_data_size = 0; ) + uint16_t metadata_size; + CHECKED_CAST(metadata_size, uint16_t, align_up(code_buffer->total_metadata_size(), wordSize)); + JVMCI_ONLY( _metadata_size = metadata_size; ) assert(_mutable_data_size == _relocation_size + metadata_size, "wrong mutable data size: %d != %d + %d", _mutable_data_size, _relocation_size, metadata_size); @@ -1437,7 +1443,7 @@ nmethod::nmethod( { assert(debug_info->oop_recorder() == code_buffer->oop_recorder(), "shared OR"); { - debug_only(NoSafepointVerifier nsv;) + DEBUG_ONLY(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); init_defaults(code_buffer, offsets); @@ -1497,9 +1503,10 @@ nmethod::nmethod( } CHECKED_CAST(_oops_size, uint16_t, align_up(code_buffer->total_oop_size(), oopSize)); - uint16_t metadata_size = (uint16_t)align_up(code_buffer->total_metadata_size(), wordSize); - JVMCI_ONLY(CHECKED_CAST(_jvmci_data_size, uint16_t, align_up(compiler->is_jvmci() ? jvmci_data->size() : 0, oopSize))); - int jvmci_data_size = 0 JVMCI_ONLY(+ _jvmci_data_size); + uint16_t metadata_size; + CHECKED_CAST(metadata_size, uint16_t, align_up(code_buffer->total_metadata_size(), wordSize)); + JVMCI_ONLY( _metadata_size = metadata_size; ) + int jvmci_data_size = 0 JVMCI_ONLY( + align_up(compiler->is_jvmci() ? jvmci_data->size() : 0, oopSize)); assert(_mutable_data_size == _relocation_size + metadata_size + jvmci_data_size, "wrong mutable data size: %d != %d + %d + %d", _mutable_data_size, _relocation_size, metadata_size, jvmci_data_size); @@ -1646,6 +1653,10 @@ void nmethod::maybe_print_nmethod(const DirectiveSet* directive) { } void nmethod::print_nmethod(bool printmethod) { + // Enter a critical section to prevent a race with deopts that patch code and updates the relocation info. + // Unfortunately, we have to lock the NMethodState_lock before the tty lock due to the deadlock rules and + // cannot lock in a more finely grained manner. + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); ttyLocker ttyl; // keep the following output all in one block if (xtty != nullptr) { xtty->begin_head("print_nmethod"); @@ -1964,14 +1975,12 @@ void nmethod::invalidate_osr_method() { } } -void nmethod::log_state_change(const char* reason) const { - assert(reason != nullptr, "Must provide a reason"); - +void nmethod::log_state_change(ChangeReason change_reason) const { if (LogCompilation) { if (xtty != nullptr) { ttyLocker ttyl; // keep the following output all in one block xtty->begin_elem("make_not_entrant thread='%zu' reason='%s'", - os::current_thread_id(), reason); + os::current_thread_id(), change_reason_to_string(change_reason)); log_identity(xtty); xtty->stamp(); xtty->end_elem(); @@ -1980,7 +1989,7 @@ void nmethod::log_state_change(const char* reason) const { ResourceMark rm; stringStream ss(NEW_RESOURCE_ARRAY(char, 256), 256); - ss.print("made not entrant: %s", reason); + ss.print("made not entrant: %s", change_reason_to_string(change_reason)); CompileTask::print_ul(this, ss.freeze()); if (PrintCompilation) { @@ -1995,9 +2004,7 @@ void nmethod::unlink_from_method() { } // Invalidate code -bool nmethod::make_not_entrant(const char* reason) { - assert(reason != nullptr, "Must provide a reason"); - +bool nmethod::make_not_entrant(ChangeReason change_reason) { // This can be called while the system is already at a safepoint which is ok NoSafepointVerifier nsv; @@ -2035,6 +2042,17 @@ bool nmethod::make_not_entrant(const char* reason) { // cache call. NativeJump::patch_verified_entry(entry_point(), verified_entry_point(), SharedRuntime::get_handle_wrong_method_stub()); + + // Update the relocation info for the patched entry. + // First, get the old relocation info... + RelocIterator iter(this, verified_entry_point(), verified_entry_point() + 8); + if (iter.next() && iter.addr() == verified_entry_point()) { + Relocation* old_reloc = iter.reloc(); + // ...then reset the iterator to update it. + RelocIterator iter(this, verified_entry_point(), verified_entry_point() + 8); + relocInfo::change_reloc_info_for_address(&iter, verified_entry_point(), old_reloc->type(), + relocInfo::relocType::runtime_call_type); + } } if (update_recompile_counts()) { @@ -2055,7 +2073,7 @@ bool nmethod::make_not_entrant(const char* reason) { assert(success, "Transition can't fail"); // Log the transition once - log_state_change(reason); + log_state_change(change_reason); // Remove nmethod from method. unlink_from_method(); @@ -2123,10 +2141,19 @@ void nmethod::purge(bool unregister_nmethod) { // completely deallocate this method Events::log_nmethod_flush(Thread::current(), "flushing %s nmethod " INTPTR_FORMAT, is_osr_method() ? "osr" : "", p2i(this)); - log_debug(codecache)("*flushing %s nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT - "/Free CodeCache:%zuKb", - is_osr_method() ? "osr" : "",_compile_id, p2i(this), CodeCache::blob_count(), - CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(this))/1024); + + LogTarget(Debug, codecache) lt; + if (lt.is_enabled()) { + ResourceMark rm; + LogStream ls(lt); + const char* method_name = method()->name()->as_C_string(); + const size_t codecache_capacity = CodeCache::capacity()/1024; + const size_t codecache_free_space = CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(this))/1024; + ls.print("Flushing nmethod %6d/" INTPTR_FORMAT ", level=%d, osr=%d, cold=%d, epoch=" UINT64_FORMAT ", cold_count=" UINT64_FORMAT ". " + "Cache capacity: %zuKb, free space: %zuKb. method %s (%s)", + _compile_id, p2i(this), _comp_level, is_osr_method(), is_cold(), _gc_epoch, CodeCache::cold_gc_count(), + codecache_capacity, codecache_free_space, method_name, compiler_name()); + } // We need to deallocate any ExceptionCache data. // Note that we do not need to grab the nmethod lock for this, it @@ -2802,7 +2829,7 @@ PcDesc* PcDescContainer::find_pc_desc_internal(address pc, bool approximate, add } // Take giant steps at first (4096, then 256, then 16, then 1) - const int LOG2_RADIX = 4 /*smaller steps in debug mode:*/ debug_only(-1); + const int LOG2_RADIX = 4 /*smaller steps in debug mode:*/ DEBUG_ONLY(-1); const int RADIX = (1 << LOG2_RADIX); for (int step = (1 << (LOG2_RADIX*3)); step > 1; step >>= LOG2_RADIX) { while ((mid = lower + step) < upper) { @@ -3243,7 +3270,7 @@ void nmethod::print_relocations() { ResourceMark m; // in case methods get printed via the debugger tty->print_cr("relocations:"); RelocIterator iter(this); - iter.print(); + iter.print_on(tty); } #endif diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 7b19cf75a76..7453bdfa0ef 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -100,7 +100,7 @@ class PcDescCache { typedef PcDesc* PcDescPtr; volatile PcDescPtr _pc_descs[cache_size]; // last cache_size pc_descs found public: - PcDescCache() { debug_only(_pc_descs[0] = nullptr); } + PcDescCache() { DEBUG_ONLY(_pc_descs[0] = nullptr); } void init_to(PcDesc* initial_pc_desc); PcDesc* find_pc_desc(int pc_offset, bool approximate); void add_pc_desc(PcDesc* pc_desc); @@ -237,7 +237,9 @@ class nmethod : public CodeBlob { uint16_t _oops_size; #if INCLUDE_JVMCI - uint16_t _jvmci_data_size; + // _metadata_size is not specific to JVMCI. In the non-JVMCI case, it can be derived as: + // _metadata_size = mutable_data_size - relocation_size + uint16_t _metadata_size; #endif // Offset in immutable data section @@ -469,6 +471,85 @@ class nmethod : public CodeBlob { void oops_do_set_strong_done(nmethod* old_head); public: + enum class ChangeReason : u1 { + C1_codepatch, + C1_deoptimize, + C1_deoptimize_for_patching, + C1_predicate_failed_trap, + CI_replay, + JVMCI_invalidate_nmethod, + JVMCI_invalidate_nmethod_mirror, + JVMCI_materialize_virtual_object, + JVMCI_new_installation, + JVMCI_register_method, + JVMCI_replacing_with_new_code, + JVMCI_reprofile, + marked_for_deoptimization, + missing_exception_handler, + not_used, + OSR_invalidation_back_branch, + OSR_invalidation_for_compiling_with_C1, + OSR_invalidation_of_lower_level, + set_native_function, + uncommon_trap, + whitebox_deoptimization, + zombie, + }; + + + static const char* change_reason_to_string(ChangeReason change_reason) { + switch (change_reason) { + case ChangeReason::C1_codepatch: + return "C1 code patch"; + case ChangeReason::C1_deoptimize: + return "C1 deoptimized"; + case ChangeReason::C1_deoptimize_for_patching: + return "C1 deoptimize for patching"; + case ChangeReason::C1_predicate_failed_trap: + return "C1 predicate failed trap"; + case ChangeReason::CI_replay: + return "CI replay"; + case ChangeReason::JVMCI_invalidate_nmethod: + return "JVMCI invalidate nmethod"; + case ChangeReason::JVMCI_invalidate_nmethod_mirror: + return "JVMCI invalidate nmethod mirror"; + case ChangeReason::JVMCI_materialize_virtual_object: + return "JVMCI materialize virtual object"; + case ChangeReason::JVMCI_new_installation: + return "JVMCI new installation"; + case ChangeReason::JVMCI_register_method: + return "JVMCI register method"; + case ChangeReason::JVMCI_replacing_with_new_code: + return "JVMCI replacing with new code"; + case ChangeReason::JVMCI_reprofile: + return "JVMCI reprofile"; + case ChangeReason::marked_for_deoptimization: + return "marked for deoptimization"; + case ChangeReason::missing_exception_handler: + return "missing exception handler"; + case ChangeReason::not_used: + return "not used"; + case ChangeReason::OSR_invalidation_back_branch: + return "OSR invalidation back branch"; + case ChangeReason::OSR_invalidation_for_compiling_with_C1: + return "OSR invalidation for compiling with C1"; + case ChangeReason::OSR_invalidation_of_lower_level: + return "OSR invalidation of lower level"; + case ChangeReason::set_native_function: + return "set native function"; + case ChangeReason::uncommon_trap: + return "uncommon trap"; + case ChangeReason::whitebox_deoptimization: + return "whitebox deoptimization"; + case ChangeReason::zombie: + return "zombie"; + default: { + assert(false, "Unhandled reason"); + return "Unknown"; + } + } + } + // create nmethod with entry_bci static nmethod* new_nmethod(const methodHandle& method, int compile_id, @@ -537,8 +618,8 @@ class nmethod : public CodeBlob { // mutable data Metadata** metadata_begin () const { return (Metadata**) (mutable_data_begin() + _relocation_size); } #if INCLUDE_JVMCI - Metadata** metadata_end () const { return (Metadata**) (mutable_data_end() - _jvmci_data_size); } - address jvmci_data_begin () const { return mutable_data_end() - _jvmci_data_size; } + Metadata** metadata_end () const { return (Metadata**) (mutable_data_begin() + _relocation_size + _metadata_size); } + address jvmci_data_begin () const { return mutable_data_begin() + _relocation_size + _metadata_size; } address jvmci_data_end () const { return mutable_data_end(); } #else Metadata** metadata_end () const { return (Metadata**) mutable_data_end(); } @@ -631,8 +712,8 @@ class nmethod : public CodeBlob { // alive. It is used when an uncommon trap happens. Returns true // if this thread changed the state of the nmethod or false if // another thread performed the transition. - bool make_not_entrant(const char* reason); - bool make_not_used() { return make_not_entrant("not used"); } + bool make_not_entrant(ChangeReason change_reason); + bool make_not_used() { return make_not_entrant(ChangeReason::not_used); } bool is_marked_for_deoptimization() const { return deoptimization_status() != not_marked; } bool has_been_deoptimized() const { return deoptimization_status() == deoptimize_done; } @@ -945,7 +1026,7 @@ class nmethod : public CodeBlob { // Logging void log_identity(xmlStream* log) const; void log_new_nmethod() const; - void log_state_change(const char* reason) const; + void log_state_change(ChangeReason change_reason) const; // Prints block-level comments, including nmethod specific block labels: void print_nmethod_labels(outputStream* stream, address block_begin, bool print_section_labels=true) const; diff --git a/src/hotspot/share/code/nmethod.inline.hpp b/src/hotspot/share/code/nmethod.inline.hpp index 49af1e0b95f..1e556b68250 100644 --- a/src/hotspot/share/code/nmethod.inline.hpp +++ b/src/hotspot/share/code/nmethod.inline.hpp @@ -33,21 +33,12 @@ inline bool nmethod::is_deopt_pc(address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } -// When using JVMCI the address might be off by the size of a call instruction. inline bool nmethod::is_deopt_entry(address pc) { - return pc == deopt_handler_begin() -#if INCLUDE_JVMCI - || (is_compiled_by_jvmci() && pc == (deopt_handler_begin() + NativeCall::byte_size())) -#endif - ; + return pc == deopt_handler_begin(); } inline bool nmethod::is_deopt_mh_entry(address pc) { - return pc == deopt_mh_handler_begin() -#if INCLUDE_JVMCI - || (is_compiled_by_jvmci() && pc == (deopt_mh_handler_begin() + NativeCall::byte_size())) -#endif - ; + return pc == deopt_mh_handler_begin(); } // class ExceptionCache methods diff --git a/src/hotspot/share/code/oopRecorder.cpp b/src/hotspot/share/code/oopRecorder.cpp index af23bf12b43..c37651892cc 100644 --- a/src/hotspot/share/code/oopRecorder.cpp +++ b/src/hotspot/share/code/oopRecorder.cpp @@ -122,7 +122,7 @@ template int ValueRecorder::add_handle(T h, bool make_findable) { template int ValueRecorder::maybe_find_index(T h) { - debug_only(_find_index_calls++); + DEBUG_ONLY(_find_index_calls++); assert(!_complete, "cannot allocate more elements after size query"); maybe_initialize(); if (h == nullptr) return null_index; @@ -134,7 +134,7 @@ template int ValueRecorder::maybe_find_index(T h) { return -1; // We know this handle is completely new. } if (cindex >= first_index && _handles->at(cindex - first_index) == h) { - debug_only(_hit_indexes++); + DEBUG_ONLY(_hit_indexes++); return cindex; } if (!_indexes->cache_location_collision(cloc)) { @@ -151,7 +151,7 @@ template int ValueRecorder::maybe_find_index(T h) { if (cloc != nullptr) { _indexes->set_cache_location_index(cloc, findex); } - debug_only(_missed_indexes++); + DEBUG_ONLY(_missed_indexes++); return findex; } } diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index ad194c71bb2..8fc22596d01 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -78,7 +78,7 @@ relocInfo* relocInfo::finish_prefix(short* prefix_limit) { assert(prefix_limit >= p, "must be a valid span of data"); int plen = checked_cast(prefix_limit - p); if (plen == 0) { - debug_only(_value = 0xFFFF); + DEBUG_ONLY(_value = 0xFFFF); return this; // no data: remove self completely } if (plen == 1 && fits_into_immediate(p[0])) { @@ -179,8 +179,34 @@ RelocIterator::RelocIterator(CodeSection* cs, address begin, address limit) { set_limits(begin, limit); } +RelocIterator::RelocIterator(CodeBlob* cb) { + initialize_misc(); + if (cb->is_nmethod()) { + _code = cb->as_nmethod(); + } else { + _code = nullptr; + } + _current = cb->relocation_begin() - 1; + _end = cb->relocation_end(); + _addr = cb->content_begin(); + + _section_start[CodeBuffer::SECT_CONSTS] = cb->content_begin(); + _section_start[CodeBuffer::SECT_INSTS ] = cb->code_begin(); + _section_start[CodeBuffer::SECT_STUBS ] = cb->code_end(); + + _section_end [CodeBuffer::SECT_CONSTS] = cb->code_begin(); + _section_end [CodeBuffer::SECT_INSTS ] = cb->code_end(); + _section_end [CodeBuffer::SECT_STUBS ] = cb->code_end(); + + assert(!has_current(), "just checking"); + set_limits(nullptr, nullptr); +} + bool RelocIterator::addr_in_const() const { const int n = CodeBuffer::SECT_CONSTS; + if (_section_start[n] == nullptr) { + return false; + } return section_start(n) <= addr() && addr() < section_end(n); } @@ -342,7 +368,7 @@ address Relocation::old_addr_for(address newa, address Relocation::new_addr_for(address olda, const CodeBuffer* src, CodeBuffer* dest) { - debug_only(const CodeBuffer* src0 = src); + DEBUG_ONLY(const CodeBuffer* src0 = src); int sect = CodeBuffer::SECT_NONE; // Look for olda in the source buffer, and all previous incarnations // if the source buffer has been expanded. @@ -471,7 +497,9 @@ void trampoline_stub_Relocation::unpack_data() { void external_word_Relocation::pack_data_to(CodeSection* dest) { short* p = (short*) dest->locs_end(); int index = ExternalsRecorder::find_index(_target); - p = pack_1_int_to(p, index); + // Use 4 bytes to store index to be able patch it when + // updating relocations in AOTCodeReader::read_relocations(). + p = add_jint(p, index); dest->set_locs_end((relocInfo*) p); } @@ -766,6 +794,14 @@ void internal_word_Relocation::fix_relocation_after_move(const CodeBuffer* src, set_value(target); } +void internal_word_Relocation::fix_relocation_after_aot_load(address orig_base_addr, address current_base_addr) { + address target = _target; + if (target == nullptr) { + target = this->target(); + target = current_base_addr + (target - orig_base_addr); + } + set_value(target); +} address internal_word_Relocation::target() { address target = _target; @@ -779,12 +815,7 @@ address internal_word_Relocation::target() { return target; } -//--------------------------------------------------------------------------------- -// Non-product code - -#ifndef PRODUCT - -static const char* reloc_type_string(relocInfo::relocType t) { +const char* relocInfo::type_name(relocInfo::relocType t) { switch (t) { #define EACH_CASE(name) \ case relocInfo::name##_type: \ @@ -802,26 +833,25 @@ static const char* reloc_type_string(relocInfo::relocType t) { } } - -void RelocIterator::print_current() { +void RelocIterator::print_current_on(outputStream* st) { if (!has_current()) { - tty->print_cr("(no relocs)"); + st->print_cr("(no relocs)"); return; } - tty->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d", - p2i(_current), type(), reloc_type_string((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset()); + st->print("relocInfo@" INTPTR_FORMAT " [type=%d(%s) addr=" INTPTR_FORMAT " offset=%d", + p2i(_current), type(), relocInfo::type_name((relocInfo::relocType) type()), p2i(_addr), _current->addr_offset()); if (current()->format() != 0) - tty->print(" format=%d", current()->format()); + st->print(" format=%d", current()->format()); if (datalen() == 1) { - tty->print(" data=%d", data()[0]); + st->print(" data=%d", data()[0]); } else if (datalen() > 0) { - tty->print(" data={"); + st->print(" data={"); for (int i = 0; i < datalen(); i++) { - tty->print("%04x", data()[i] & 0xFFFF); + st->print("%04x", data()[i] & 0xFFFF); } - tty->print("}"); + st->print("}"); } - tty->print("]"); + st->print("]"); switch (type()) { case relocInfo::oop_type: { @@ -834,14 +864,14 @@ void RelocIterator::print_current() { raw_oop = *oop_addr; oop_value = r->oop_value(); } - tty->print(" | [oop_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT "]", + st->print(" | [oop_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT "]", p2i(oop_addr), p2i(raw_oop)); // Do not print the oop by default--we want this routine to // work even during GC or other inconvenient times. if (WizardMode && oop_value != nullptr) { - tty->print("oop_value=" INTPTR_FORMAT ": ", p2i(oop_value)); + st->print("oop_value=" INTPTR_FORMAT ": ", p2i(oop_value)); if (oopDesc::is_oop(oop_value)) { - oop_value->print_value_on(tty); + oop_value->print_value_on(st); } } break; @@ -857,11 +887,11 @@ void RelocIterator::print_current() { raw_metadata = *metadata_addr; metadata_value = r->metadata_value(); } - tty->print(" | [metadata_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT "]", + st->print(" | [metadata_addr=" INTPTR_FORMAT " *=" INTPTR_FORMAT "]", p2i(metadata_addr), p2i(raw_metadata)); if (metadata_value != nullptr) { - tty->print("metadata_value=" INTPTR_FORMAT ": ", p2i(metadata_value)); - metadata_value->print_value_on(tty); + st->print("metadata_value=" INTPTR_FORMAT ": ", p2i(metadata_value)); + metadata_value->print_value_on(st); } break; } @@ -870,17 +900,17 @@ void RelocIterator::print_current() { case relocInfo::section_word_type: { DataRelocation* r = (DataRelocation*) reloc(); - tty->print(" | [target=" INTPTR_FORMAT "]", p2i(r->value())); //value==target + st->print(" | [target=" INTPTR_FORMAT "]", p2i(r->value())); //value==target break; } case relocInfo::static_call_type: { static_call_Relocation* r = (static_call_Relocation*) reloc(); - tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", + st->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", p2i(r->destination()), p2i(r->method_value())); CodeBlob* cb = CodeCache::find_blob(r->destination()); if (cb != nullptr) { - tty->print(" Blob::%s", cb->name()); + st->print(" Blob::%s", cb->name()); } break; } @@ -889,28 +919,28 @@ void RelocIterator::print_current() { { CallRelocation* r = (CallRelocation*) reloc(); address dest = r->destination(); - tty->print(" | [destination=" INTPTR_FORMAT "]", p2i(dest)); + st->print(" | [destination=" INTPTR_FORMAT "]", p2i(dest)); if (StubRoutines::contains(dest)) { StubCodeDesc* desc = StubCodeDesc::desc_for(dest); if (desc == nullptr) { desc = StubCodeDesc::desc_for(dest + frame::pc_return_offset); } if (desc != nullptr) { - tty->print(" Stub::%s", desc->name()); + st->print(" Stub::%s", desc->name()); } } else { CodeBlob* cb = CodeCache::find_blob(dest); if (cb != nullptr) { - tty->print(" %s", cb->name()); + st->print(" %s", cb->name()); } else { ResourceMark rm; const int buflen = 1024; char* buf = NEW_RESOURCE_ARRAY(char, buflen); int offset; if (os::dll_address_to_function_name(dest, buf, buflen, &offset)) { - tty->print(" %s", buf); + st->print(" %s", buf); if (offset != 0) { - tty->print("+%d", offset); + st->print("+%d", offset); } } } @@ -920,45 +950,45 @@ void RelocIterator::print_current() { case relocInfo::virtual_call_type: { virtual_call_Relocation* r = (virtual_call_Relocation*) reloc(); - tty->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", + st->print(" | [destination=" INTPTR_FORMAT " cached_value=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", p2i(r->destination()), p2i(r->cached_value()), p2i(r->method_value())); CodeBlob* cb = CodeCache::find_blob(r->destination()); if (cb != nullptr) { - tty->print(" Blob::%s", cb->name()); + st->print(" Blob::%s", cb->name()); } break; } case relocInfo::static_stub_type: { static_stub_Relocation* r = (static_stub_Relocation*) reloc(); - tty->print(" | [static_call=" INTPTR_FORMAT "]", p2i(r->static_call())); + st->print(" | [static_call=" INTPTR_FORMAT "]", p2i(r->static_call())); break; } case relocInfo::trampoline_stub_type: { trampoline_stub_Relocation* r = (trampoline_stub_Relocation*) reloc(); - tty->print(" | [trampoline owner=" INTPTR_FORMAT "]", p2i(r->owner())); + st->print(" | [trampoline owner=" INTPTR_FORMAT "]", p2i(r->owner())); break; } case relocInfo::opt_virtual_call_type: { opt_virtual_call_Relocation* r = (opt_virtual_call_Relocation*) reloc(); - tty->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", + st->print(" | [destination=" INTPTR_FORMAT " metadata=" INTPTR_FORMAT "]", p2i(r->destination()), p2i(r->method_value())); CodeBlob* cb = CodeCache::find_blob(r->destination()); if (cb != nullptr) { - tty->print(" Blob::%s", cb->name()); + st->print(" Blob::%s", cb->name()); } break; } default: break; } - tty->cr(); + st->cr(); } -void RelocIterator::print() { +void RelocIterator::print_on(outputStream* st) { RelocIterator save_this = (*this); relocInfo* scan = _current; if (!has_current()) scan += 1; // nothing to scan here! @@ -969,32 +999,37 @@ void RelocIterator::print() { got_next = (skip_next || next()); skip_next = false; - tty->print(" @" INTPTR_FORMAT ": ", p2i(scan)); + st->print(" @" INTPTR_FORMAT ": ", p2i(scan)); relocInfo* newscan = _current+1; if (!has_current()) newscan -= 1; // nothing to scan here! while (scan < newscan) { - tty->print("%04x", *(short*)scan & 0xFFFF); + st->print("%04x", *(short*)scan & 0xFFFF); scan++; } - tty->cr(); + st->cr(); if (!got_next) break; - print_current(); + print_current_on(st); } (*this) = save_this; } +//--------------------------------------------------------------------------------- +// Non-product code + +#ifndef PRODUCT + // For the debugger: extern "C" void print_blob_locs(nmethod* nm) { nm->print(); RelocIterator iter(nm); - iter.print(); + iter.print_on(tty); } extern "C" void print_buf_locs(CodeBuffer* cb) { FlagSetting fs(PrintRelocations, true); - cb->print(); + cb->print_on(tty); } #endif // !PRODUCT diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 25cca49e50b..714a964b28d 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -451,6 +451,8 @@ class relocInfo { length_limit = 1 + 1 + (3*BytesPerWord/BytesPerShort) + 1, have_format = format_width > 0 }; + + static const char* type_name(relocInfo::relocType t); }; #define FORWARD_DECLARE_EACH_CLASS(name) \ @@ -574,7 +576,7 @@ class RelocIterator : public StackObj { void set_has_current(bool b) { _datalen = !b ? -1 : 0; - debug_only(_data = nullptr); + DEBUG_ONLY(_data = nullptr); } void set_current(relocInfo& ri) { _current = &ri; @@ -600,6 +602,7 @@ class RelocIterator : public StackObj { // constructor RelocIterator(nmethod* nm, address begin = nullptr, address limit = nullptr); RelocIterator(CodeSection* cb, address begin = nullptr, address limit = nullptr); + RelocIterator(CodeBlob* cb); // get next reloc info, return !eos bool next() { @@ -638,11 +641,11 @@ class RelocIterator : public StackObj { bool addr_in_const() const; address section_start(int n) const { - assert(_section_start[n], "must be initialized"); + assert(_section_start[n], "section %d must be initialized", n); return _section_start[n]; } address section_end(int n) const { - assert(_section_end[n], "must be initialized"); + assert(_section_end[n], "section %d must be initialized", n); return _section_end[n]; } @@ -658,11 +661,9 @@ class RelocIterator : public StackObj { // generic relocation accessor; switches on type to call the above Relocation* reloc(); -#ifndef PRODUCT public: - void print(); - void print_current(); -#endif + void print_on(outputStream* st); + void print_current_on(outputStream* st); }; @@ -672,6 +673,7 @@ class RelocIterator : public StackObj { class Relocation { friend class RelocIterator; + friend class AOTCodeReader; private: // When a relocation has been created by a RelocIterator, @@ -1377,6 +1379,8 @@ class internal_word_Relocation : public DataRelocation { void unpack_data() override; void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) override; + void fix_relocation_after_aot_load(address orig_base_addr, address current_base_addr); + address target(); // if _target==nullptr, fetch addr from code stream int section() { return _section; } address value() override { return target(); } diff --git a/src/hotspot/share/code/stubs.cpp b/src/hotspot/share/code/stubs.cpp index 074241ff611..6ae71f93709 100644 --- a/src/hotspot/share/code/stubs.cpp +++ b/src/hotspot/share/code/stubs.cpp @@ -176,14 +176,14 @@ void StubQueue::commit(int committed_code_size) { _queue_end += committed_size; _number_of_stubs++; if (_mutex != nullptr) _mutex->unlock(); - debug_only(stub_verify(s);) + DEBUG_ONLY(stub_verify(s);) } void StubQueue::remove_first() { if (number_of_stubs() == 0) return; Stub* s = first(); - debug_only(stub_verify(s);) + DEBUG_ONLY(stub_verify(s);) stub_finalize(s); _queue_begin += stub_size(s); assert(_queue_begin <= _buffer_limit, "sanity check"); @@ -210,7 +210,7 @@ void StubQueue::remove_first(int n) { void StubQueue::remove_all(){ - debug_only(verify();) + DEBUG_ONLY(verify();) remove_first(number_of_stubs()); assert(number_of_stubs() == 0, "sanity check"); } diff --git a/src/hotspot/share/compiler/compilationLog.cpp b/src/hotspot/share/compiler/compilationLog.cpp index f8dc24d3aaa..e9592415f3d 100644 --- a/src/hotspot/share/compiler/compilationLog.cpp +++ b/src/hotspot/share/compiler/compilationLog.cpp @@ -51,7 +51,11 @@ void CompilationLog::log_nmethod(JavaThread* thread, nmethod* nm) { void CompilationLog::log_failure(JavaThread* thread, CompileTask* task, const char* reason, const char* retry_message) { StringLogMessage lm; - lm.print("%4d COMPILE SKIPPED: %s", task->compile_id(), reason); + if (task == nullptr) { + lm.print("Id not known, task was 0; COMPILE SKIPPED: %s", reason); + } else { + lm.print("%4d COMPILE SKIPPED: %s", task->compile_id(), reason); + } if (retry_message != nullptr) { lm.append(" (%s)", retry_message); } diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index 0c2822c94d2..d842bcb2b6f 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -374,7 +374,7 @@ void ArenaStatCounter::on_arena_chunk_deallocation(size_t size, uint64_t stamp) void ArenaStatCounter::print_peak_state_on(outputStream* st) const { st->print("Total Usage: %zu ", _peak); if (_peak > 0) { -#ifdef COMPILER2 +#ifdef COMPILER1 // C1: print allocations broken down by arena types if (_comp_type == CompilerType::compiler_c1) { st->print("["); @@ -396,16 +396,16 @@ void ArenaStatCounter::print_peak_state_on(outputStream* st) const { #ifdef COMPILER2 // C2: print counters and timeline on multiple lines, indented if (_comp_type == CompilerType::compiler_c2) { - streamIndentor si(st, 4); + StreamIndentor si(st, 4); st->cr(); st->print_cr("--- Arena Usage by Arena Type and compilation phase, at arena usage peak of %zu ---", _peak); { - streamIndentor si(st, 4); + StreamIndentor si(st, 4); _counters_at_global_peak.print_on(st); } st->print_cr("--- Allocation timelime by phase ---"); { - streamIndentor si(st, 4); + StreamIndentor si(st, 4); _timeline.print_on(st); } st->print_cr("---"); @@ -825,7 +825,6 @@ void CompilationMemoryStatistic::on_end_compilation() { if (print) { // Pre-assemble string to prevent tearing stringStream ss; - StreamAutoIndentor sai(&ss); ss.print("%s (%d) (%s) Arena usage ", compilertype2name(arena_stat->comp_type()), arena_stat->comp_id(), result); arena_stat->fmn().print_on(&ss); ss.print_raw(": "); @@ -1000,8 +999,7 @@ void CompilationMemoryStatistic::print_error_report(outputStream* st) { if (!check_before_reporting(st)) { return; } - StreamAutoIndentor sai(tty); - streamIndentor si(tty, 4); + StreamIndentor si(tty, 4); const ArenaStatCounter* const oom_stats = Atomic::load(&_arenastat_oom_crash); if (oom_stats != nullptr) { // we crashed due to a compiler limit hit. Lead with a printout of the offending stats @@ -1021,8 +1019,7 @@ void CompilationMemoryStatistic::print_final_report(outputStream* st) { return; } st->print_cr("Compiler Memory Statistic, 10 most expensive compilations:"); - StreamAutoIndentor sai(st); - streamIndentor si(st, 4); + StreamIndentor si(st, 4); print_all_by_size(st, false, false, 0, 10); } @@ -1031,8 +1028,7 @@ void CompilationMemoryStatistic::print_jcmd_report(outputStream* st, bool verbos return; } st->print_cr("Compiler Memory Statistic"); - StreamAutoIndentor sai(st); - streamIndentor si(st, 4); + StreamIndentor si(st, 4); print_all_by_size(st, verbose, legend, minsize, -1); } diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index fa18b3c8ab4..bab437eaade 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotLinkedClassBulkLoader.hpp" #include "code/scopeDesc.hpp" #include "compiler/compilationPolicy.hpp" #include "compiler/compileBroker.hpp" @@ -31,6 +32,7 @@ #include "oops/method.inline.hpp" #include "oops/methodData.hpp" #include "oops/oop.inline.hpp" +#include "oops/trainingData.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/arguments.hpp" #include "runtime/deoptimization.hpp" @@ -50,11 +52,13 @@ #include "jvmci/jvmci.hpp" #endif -jlong CompilationPolicy::_start_time = 0; +int64_t CompilationPolicy::_start_time = 0; int CompilationPolicy::_c1_count = 0; int CompilationPolicy::_c2_count = 0; double CompilationPolicy::_increase_threshold_at_ratio = 0; +CompilationPolicy::TrainingReplayQueue CompilationPolicy::_training_replay_queue; + void compilationPolicy_init() { CompilationPolicy::initialize(); } @@ -78,33 +82,111 @@ bool CompilationPolicy::must_be_compiled(const methodHandle& m, int comp_level) if (m->has_compiled_code()) return false; // already compiled if (!can_be_compiled(m, comp_level)) return false; - return !UseInterpreter || // must compile all methods + return !UseInterpreter || // must compile all methods (AlwaysCompileLoopMethods && m->has_loops() && CompileBroker::should_compile_new_jobs()); // eagerly compile loop methods } +void CompilationPolicy::maybe_compile_early(const methodHandle& m, TRAPS) { + if (m->method_holder()->is_not_initialized()) { + // 'is_not_initialized' means not only '!is_initialized', but also that + // initialization has not been started yet ('!being_initialized') + // Do not force compilation of methods in uninitialized classes. + return; + } + if (!m->is_native() && MethodTrainingData::have_data()) { + MethodTrainingData* mtd = MethodTrainingData::find_fast(m); + if (mtd == nullptr) { + return; // there is no training data recorded for m + } + CompLevel cur_level = static_cast(m->highest_comp_level()); + CompLevel next_level = trained_transition(m, cur_level, mtd, THREAD); + if (next_level != cur_level && can_be_compiled(m, next_level) && !CompileBroker::compilation_is_in_queue(m)) { + if (PrintTieredEvents) { + print_event(FORCE_COMPILE, m(), m(), InvocationEntryBci, next_level); + } + CompileBroker::compile_method(m, InvocationEntryBci, next_level, 0, CompileTask::Reason_MustBeCompiled, THREAD); + if (HAS_PENDING_EXCEPTION) { + CLEAR_PENDING_EXCEPTION; + } + } + } +} + void CompilationPolicy::compile_if_required(const methodHandle& m, TRAPS) { + if (!THREAD->can_call_java() || THREAD->is_Compiler_thread()) { + // don't force compilation, resolve was on behalf of compiler + return; + } + if (m->method_holder()->is_not_initialized()) { + // 'is_not_initialized' means not only '!is_initialized', but also that + // initialization has not been started yet ('!being_initialized') + // Do not force compilation of methods in uninitialized classes. + // Note that doing this would throw an assert later, + // in CompileBroker::compile_method. + // We sometimes use the link resolver to do reflective lookups + // even before classes are initialized. + return; + } + if (must_be_compiled(m)) { // This path is unusual, mostly used by the '-Xcomp' stress test mode. - - if (!THREAD->can_call_java() || THREAD->is_Compiler_thread()) { - // don't force compilation, resolve was on behalf of compiler - return; - } - if (m->method_holder()->is_not_initialized()) { - // 'is_not_initialized' means not only '!is_initialized', but also that - // initialization has not been started yet ('!being_initialized') - // Do not force compilation of methods in uninitialized classes. - // Note that doing this would throw an assert later, - // in CompileBroker::compile_method. - // We sometimes use the link resolver to do reflective lookups - // even before classes are initialized. - return; - } CompLevel level = initial_compile_level(m); if (PrintTieredEvents) { - print_event(COMPILE, m(), m(), InvocationEntryBci, level); + print_event(FORCE_COMPILE, m(), m(), InvocationEntryBci, level); + } + CompileBroker::compile_method(m, InvocationEntryBci, level, 0, CompileTask::Reason_MustBeCompiled, THREAD); + } +} + +void CompilationPolicy::replay_training_at_init_impl(InstanceKlass* klass, TRAPS) { + if (!klass->has_init_deps_processed()) { + ResourceMark rm; + log_debug(training)("Replay training: %s", klass->external_name()); + + KlassTrainingData* ktd = KlassTrainingData::find(klass); + if (ktd != nullptr) { + guarantee(ktd->has_holder(), ""); + ktd->notice_fully_initialized(); // sets klass->has_init_deps_processed bit + assert(klass->has_init_deps_processed(), ""); + if (AOTCompileEagerly) { + ktd->iterate_comp_deps([&](CompileTrainingData* ctd) { + if (ctd->init_deps_left() == 0) { + MethodTrainingData* mtd = ctd->method(); + if (mtd->has_holder()) { + const methodHandle mh(THREAD, const_cast(mtd->holder())); + CompilationPolicy::maybe_compile_early(mh, THREAD); + } + } + }); + } + } + } +} + +void CompilationPolicy::replay_training_at_init(InstanceKlass* klass, TRAPS) { + assert(klass->is_initialized(), ""); + if (TrainingData::have_data() && klass->is_shared()) { + _training_replay_queue.push(klass, TrainingReplayQueue_lock, THREAD); + } +} + +// For TrainingReplayQueue +template<> +void CompilationPolicyUtils::Queue::print_on(outputStream* st) { + int pos = 0; + for (QueueNode* cur = _head; cur != nullptr; cur = cur->next()) { + ResourceMark rm; + InstanceKlass* ik = cur->value(); + st->print_cr("%3d: " INTPTR_FORMAT " %s", ++pos, p2i(ik), ik->external_name()); + } +} + +void CompilationPolicy::replay_training_at_init_loop(TRAPS) { + while (!CompileBroker::is_compilation_disabled_forever()) { + InstanceKlass* ik = _training_replay_queue.pop(TrainingReplayQueue_lock, THREAD); + if (ik != nullptr) { + replay_training_at_init_impl(ik, THREAD); } - CompileBroker::compile_method(m, InvocationEntryBci, level, methodHandle(), 0, CompileTask::Reason_MustBeCompiled, THREAD); } } @@ -122,7 +204,7 @@ static inline CompLevel adjust_level_for_compilability_query(CompLevel comp_leve // Returns true if m is allowed to be compiled bool CompilationPolicy::can_be_compiled(const methodHandle& m, int comp_level) { // allow any levels for WhiteBox - assert(WhiteBoxAPI || comp_level == CompLevel_any || is_compile(comp_level), "illegal compilation level"); + assert(WhiteBoxAPI || comp_level == CompLevel_any || is_compile(comp_level), "illegal compilation level %d", comp_level); if (m->is_abstract()) return false; if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false; @@ -322,7 +404,7 @@ double CompilationPolicy::threshold_scale(CompLevel level, int feedback_k) { return 1; } -void CompilationPolicy::print_counters(const char* prefix, const Method* m) { +void CompilationPolicy::print_counters(const char* prefix, Method* m) { int invocation_count = m->invocation_count(); int backedge_count = m->backedge_count(); MethodData* mdh = m->method_data(); @@ -342,8 +424,36 @@ void CompilationPolicy::print_counters(const char* prefix, const Method* m) { m->highest_comp_level(), m->highest_osr_comp_level()); } +void CompilationPolicy::print_training_data(const char* prefix, Method* method) { + methodHandle m(Thread::current(), method); + tty->print(" %smtd: ", prefix); + MethodTrainingData* mtd = MethodTrainingData::find(m); + if (mtd == nullptr) { + tty->print("null"); + } else { + MethodData* md = mtd->final_profile(); + tty->print("mdo="); + if (md == nullptr) { + tty->print("null"); + } else { + int mdo_invocations = md->invocation_count(); + int mdo_backedges = md->backedge_count(); + int mdo_invocations_start = md->invocation_count_start(); + int mdo_backedges_start = md->backedge_count_start(); + tty->print("%d(%d), %d(%d)", mdo_invocations, mdo_invocations_start, mdo_backedges, mdo_backedges_start); + } + CompileTrainingData* ctd = mtd->last_toplevel_compile(CompLevel_full_optimization); + tty->print(", deps="); + if (ctd == nullptr) { + tty->print("null"); + } else { + tty->print("%d", ctd->init_deps_left()); + } + } +} + // Print an event. -void CompilationPolicy::print_event(EventType type, const Method* m, const Method* im, int bci, CompLevel level) { +void CompilationPolicy::print_event(EventType type, Method* m, Method* im, int bci, CompLevel level) { bool inlinee_event = m != im; ttyLocker tty_lock; @@ -359,6 +469,9 @@ void CompilationPolicy::print_event(EventType type, const Method* m, const Metho case COMPILE: tty->print("compile"); break; + case FORCE_COMPILE: + tty->print("force-compile"); + break; case REMOVE_FROM_QUEUE: tty->print("remove-from-queue"); break; @@ -424,6 +537,10 @@ void CompilationPolicy::print_event(EventType type, const Method* m, const Metho if (m->queued_for_compilation()) { tty->print("in-queue"); } else tty->print("idle"); + print_training_data("", m); + if (inlinee_event) { + print_training_data("inlinee ", im); + } } tty->print_cr("]"); } @@ -433,6 +550,7 @@ void CompilationPolicy::initialize() { int count = CICompilerCount; bool c1_only = CompilerConfig::is_c1_only(); bool c2_only = CompilerConfig::is_c2_or_jvmci_compiler_only(); + int min_count = (c1_only || c2_only) ? 1 : 2; #ifdef _LP64 // Turn on ergonomic compiler count selection @@ -443,7 +561,7 @@ void CompilationPolicy::initialize() { // Simple log n seems to grow too slowly for tiered, try something faster: log n * log log n int log_cpu = log2i(os::active_processor_count()); int loglog_cpu = log2i(MAX2(log_cpu, 1)); - count = MAX2(log_cpu * loglog_cpu * 3 / 2, 2); + count = MAX2(log_cpu * loglog_cpu * 3 / 2, min_count); // Make sure there is enough space in the code cache to hold all the compiler buffers size_t c1_size = 0; #ifdef COMPILER1 @@ -457,7 +575,7 @@ void CompilationPolicy::initialize() { int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size; if (count > max_count) { // Lower the compiler count such that all buffers fit into the code cache - count = MAX2(max_count, c1_only ? 1 : 2); + count = MAX2(max_count, min_count); } FLAG_SET_ERGO(CICompilerCount, count); } @@ -476,9 +594,10 @@ void CompilationPolicy::initialize() { #endif if (c1_only) { - // No C2 compiler thread required + // No C2 compiler threads are needed set_c1_count(count); } else if (c2_only) { + // No C1 compiler threads are needed set_c2_count(count); } else { #if INCLUDE_JVMCI @@ -496,6 +615,9 @@ void CompilationPolicy::initialize() { } assert(count == c1_count() + c2_count(), "inconsistent compiler thread count"); set_increase_threshold_at_ratio(); + } else { + // Interpreter mode creates no compilers + FLAG_SET_ERGO(CICompilerCount, 0); } set_start_time(nanos_to_millis(os::javaTimeNanos())); } @@ -617,12 +739,12 @@ void CompilationPolicy::handle_counter_overflow(const methodHandle& method) { } // Called with the queue locked and with at least one element -CompileTask* CompilationPolicy::select_task(CompileQueue* compile_queue) { +CompileTask* CompilationPolicy::select_task(CompileQueue* compile_queue, JavaThread* THREAD) { CompileTask *max_blocking_task = nullptr; CompileTask *max_task = nullptr; Method* max_method = nullptr; - jlong t = nanos_to_millis(os::javaTimeNanos()); + int64_t t = nanos_to_millis(os::javaTimeNanos()); // Iterate through the queue and find a method with a maximum rate. for (CompileTask* task = compile_queue->first(); task != nullptr;) { CompileTask* next_task = task->next(); @@ -639,7 +761,7 @@ CompileTask* CompilationPolicy::select_task(CompileQueue* compile_queue) { return task; } Method* method = task->method(); - methodHandle mh(Thread::current(), method); + methodHandle mh(THREAD, method); if (task->can_become_stale() && is_stale(t, TieredCompileTaskTimeout, mh) && !is_old(mh)) { if (PrintTieredEvents) { print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel) task->comp_level()); @@ -675,7 +797,7 @@ CompileTask* CompilationPolicy::select_task(CompileQueue* compile_queue) { max_method = max_task->method(); } - methodHandle max_method_h(Thread::current(), max_method); + methodHandle max_method_h(THREAD, max_method); if (max_task != nullptr && max_task->comp_level() == CompLevel_full_profile && TieredStopAtLevel > CompLevel_full_profile && max_method != nullptr && is_method_profiled(max_method_h) && !Arguments::is_compiler_only()) { @@ -694,7 +816,6 @@ CompileTask* CompilationPolicy::select_task(CompileQueue* compile_queue) { print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); } } - return max_task; } @@ -717,6 +838,13 @@ nmethod* CompilationPolicy::event(const methodHandle& method, const methodHandle print_event(bci == InvocationEntryBci ? CALL : LOOP, method(), inlinee(), bci, comp_level); } +#if INCLUDE_JVMCI + if (EnableJVMCI && UseJVMCICompiler && + comp_level == CompLevel_full_optimization CDS_ONLY(&& !AOTLinkedClassBulkLoader::class_preloading_finished())) { + return nullptr; + } +#endif + if (comp_level == CompLevel_none && JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode()) { @@ -796,7 +924,7 @@ void CompilationPolicy::compile(const methodHandle& mh, int bci, CompLevel level nmethod* osr_nm = mh->lookup_osr_nmethod_for(bci, CompLevel_simple, false); if (osr_nm != nullptr && osr_nm->comp_level() > CompLevel_simple) { // Invalidate the existing OSR nmethod so that a compile at CompLevel_simple is permitted. - osr_nm->make_not_entrant("OSR invalidation for compiling with C1"); + osr_nm->make_not_entrant(nmethod::ChangeReason::OSR_invalidation_for_compiling_with_C1); } compile(mh, bci, CompLevel_simple, THREAD); } @@ -812,12 +940,12 @@ void CompilationPolicy::compile(const methodHandle& mh, int bci, CompLevel level } int hot_count = (bci == InvocationEntryBci) ? mh->invocation_count() : mh->backedge_count(); update_rate(nanos_to_millis(os::javaTimeNanos()), mh); - CompileBroker::compile_method(mh, bci, level, mh, hot_count, CompileTask::Reason_Tiered, THREAD); + CompileBroker::compile_method(mh, bci, level, hot_count, CompileTask::Reason_Tiered, THREAD); } } // update_rate() is called from select_task() while holding a compile queue lock. -void CompilationPolicy::update_rate(jlong t, const methodHandle& method) { +void CompilationPolicy::update_rate(int64_t t, const methodHandle& method) { // Skip update if counters are absent. // Can't allocate them since we are holding compile queue lock. if (method->method_counters() == nullptr) return; @@ -831,8 +959,8 @@ void CompilationPolicy::update_rate(jlong t, const methodHandle& method) { // We don't update the rate if we've just came out of a safepoint. // delta_s is the time since last safepoint in milliseconds. - jlong delta_s = t - SafepointTracing::end_of_last_safepoint_ms(); - jlong delta_t = t - (method->prev_time() != 0 ? method->prev_time() : start_time()); // milliseconds since the last measurement + int64_t delta_s = t - SafepointTracing::end_of_last_safepoint_ms(); + int64_t delta_t = t - (method->prev_time() != 0 ? method->prev_time() : start_time()); // milliseconds since the last measurement // How many events were there since the last time? int event_count = method->invocation_count() + method->backedge_count(); int delta_e = event_count - method->prev_event_count(); @@ -855,9 +983,9 @@ void CompilationPolicy::update_rate(jlong t, const methodHandle& method) { // Check if this method has been stale for a given number of milliseconds. // See select_task(). -bool CompilationPolicy::is_stale(jlong t, jlong timeout, const methodHandle& method) { - jlong delta_s = t - SafepointTracing::end_of_last_safepoint_ms(); - jlong delta_t = t - method->prev_time(); +bool CompilationPolicy::is_stale(int64_t t, int64_t timeout, const methodHandle& method) { + int64_t delta_s = t - SafepointTracing::end_of_last_safepoint_ms(); + int64_t delta_t = t - method->prev_time(); if (delta_t > timeout && delta_s > timeout) { int event_count = method->invocation_count() + method->backedge_count(); int delta_e = event_count - method->prev_event_count(); @@ -908,13 +1036,12 @@ bool CompilationPolicy::is_method_profiled(const methodHandle& method) { // Determine is a method is mature. -bool CompilationPolicy::is_mature(Method* method) { +bool CompilationPolicy::is_mature(MethodData* mdo) { if (Arguments::is_compiler_only()) { // Always report profiles as immature with -Xcomp return false; } - methodHandle mh(Thread::current(), method); - MethodData* mdo = method->method_data(); + methodHandle mh(Thread::current(), mdo->method()); if (mdo != nullptr) { int i = mdo->invocation_count(); int b = mdo->backedge_count(); @@ -931,9 +1058,18 @@ bool CompilationPolicy::should_create_mdo(const methodHandle& method, CompLevel if (cur_level != CompLevel_none || force_comp_at_level_simple(method) || CompilationModeFlag::quick_only() || !ProfileInterpreter) { return false; } + + if (TrainingData::have_data()) { + MethodTrainingData* mtd = MethodTrainingData::find_fast(method); + if (mtd != nullptr && mtd->saw_level(CompLevel_full_optimization)) { + return true; + } + } + if (is_old(method)) { return true; } + int i = method->invocation_count(); int b = method->backedge_count(); double k = Tier0ProfilingStartPercentage / 100.0; @@ -967,7 +1103,7 @@ void CompilationPolicy::create_mdo(const methodHandle& mh, JavaThread* THREAD) { if (mh->method_data() == nullptr) { Method::build_profiling_method_data(mh, CHECK_AND_CLEAR); } - if (ProfileInterpreter) { + if (ProfileInterpreter && THREAD->has_last_Java_frame()) { MethodData* mdo = mh->method_data(); if (mdo != nullptr) { frame last_frame = THREAD->last_frame(); @@ -980,7 +1116,136 @@ void CompilationPolicy::create_mdo(const methodHandle& mh, JavaThread* THREAD) { } } +CompLevel CompilationPolicy::trained_transition_from_none(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD) { + precond(mtd != nullptr); + precond(cur_level == CompLevel_none); + if (mtd->only_inlined() && !mtd->saw_level(CompLevel_full_optimization)) { + return CompLevel_none; + } + + bool training_has_profile = (mtd->final_profile() != nullptr); + if (mtd->saw_level(CompLevel_full_optimization) && !training_has_profile) { + return CompLevel_full_profile; + } + + CompLevel highest_training_level = static_cast(mtd->highest_top_level()); + switch (highest_training_level) { + case CompLevel_limited_profile: + case CompLevel_full_profile: + return CompLevel_limited_profile; + case CompLevel_simple: + return CompLevel_simple; + case CompLevel_none: + return CompLevel_none; + default: + break; + } + + // Now handle the case of level 4. + assert(highest_training_level == CompLevel_full_optimization, "Unexpected compilation level: %d", highest_training_level); + if (!training_has_profile) { + // The method was a part of a level 4 compile, but don't have a stored profile, + // we need to profile it. + return CompLevel_full_profile; + } + const bool deopt = (static_cast(method->highest_comp_level()) == CompLevel_full_optimization); + // If we deopted, then we reprofile + if (deopt && !is_method_profiled(method)) { + return CompLevel_full_profile; + } + + CompileTrainingData* ctd = mtd->last_toplevel_compile(CompLevel_full_optimization); + assert(ctd != nullptr, "Should have CTD for CompLevel_full_optimization"); + // With SkipTier2IfPossible and all deps satisfied, go to level 4 immediately + if (SkipTier2IfPossible && ctd->init_deps_left() == 0) { + if (method->method_data() == nullptr) { + create_mdo(method, THREAD); + } + return CompLevel_full_optimization; + } + + // Otherwise go to level 2 + return CompLevel_limited_profile; +} + + +CompLevel CompilationPolicy::trained_transition_from_limited_profile(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD) { + precond(mtd != nullptr); + precond(cur_level == CompLevel_limited_profile); + + // One of the main reasons that we can get here is that we're waiting for the stored C2 code to become ready. + + // But first, check if we have a saved profile + bool training_has_profile = (mtd->final_profile() != nullptr); + if (!training_has_profile) { + return CompLevel_full_profile; + } + + + assert(training_has_profile, "Have to have a profile to be here"); + // Check if the method is ready + CompileTrainingData* ctd = mtd->last_toplevel_compile(CompLevel_full_optimization); + if (ctd != nullptr && ctd->init_deps_left() == 0) { + if (method->method_data() == nullptr) { + create_mdo(method, THREAD); + } + return CompLevel_full_optimization; + } + + // Otherwise stay at the current level + return CompLevel_limited_profile; +} + + +CompLevel CompilationPolicy::trained_transition_from_full_profile(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD) { + precond(mtd != nullptr); + precond(cur_level == CompLevel_full_profile); + + CompLevel highest_training_level = static_cast(mtd->highest_top_level()); + // We have method at the full profile level and we also know that it's possibly an important method. + if (highest_training_level == CompLevel_full_optimization && !mtd->only_inlined()) { + // Check if it is adequately profiled + if (is_method_profiled(method)) { + return CompLevel_full_optimization; + } + } + + // Otherwise stay at the current level + return CompLevel_full_profile; +} + +CompLevel CompilationPolicy::trained_transition(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD) { + precond(MethodTrainingData::have_data()); + + // If there is no training data recorded for this method, bail out. + if (mtd == nullptr) { + return cur_level; + } + + CompLevel next_level = cur_level; + switch(cur_level) { + default: break; + case CompLevel_none: + next_level = trained_transition_from_none(method, cur_level, mtd, THREAD); + break; + case CompLevel_limited_profile: + next_level = trained_transition_from_limited_profile(method, cur_level, mtd, THREAD); + break; + case CompLevel_full_profile: + next_level = trained_transition_from_full_profile(method, cur_level, mtd, THREAD); + break; + } + + // We don't have any special strategies for the C2-only compilation modes, so just fix up the levels for now. + if (CompilationModeFlag::high_only_quick_internal() && CompLevel_simple < next_level && next_level < CompLevel_full_optimization) { + return CompLevel_none; + } + if (CompilationModeFlag::high_only() && next_level < CompLevel_full_optimization) { + return CompLevel_none; + } + return (cur_level != next_level) ? limit_level(next_level) : cur_level; +} /* * Method states: @@ -1022,93 +1287,137 @@ void CompilationPolicy::create_mdo(const methodHandle& mh, JavaThread* THREAD) { // Common transition function. Given a predicate determines if a method should transition to another level. template -CompLevel CompilationPolicy::common(const methodHandle& method, CompLevel cur_level, bool disable_feedback) { +CompLevel CompilationPolicy::common(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD, bool disable_feedback) { CompLevel next_level = cur_level; - int i = method->invocation_count(); - int b = method->backedge_count(); if (force_comp_at_level_simple(method)) { next_level = CompLevel_simple; - } else { - if (is_trivial(method) || method->is_native()) { - next_level = CompilationModeFlag::disable_intermediate() ? CompLevel_full_optimization : CompLevel_simple; + } else if (is_trivial(method) || method->is_native()) { + // We do not care if there is profiling data for these methods, throw them to compiler. + next_level = CompilationModeFlag::disable_intermediate() ? CompLevel_full_optimization : CompLevel_simple; + } else if (MethodTrainingData::have_data()) { + MethodTrainingData* mtd = MethodTrainingData::find_fast(method); + if (mtd == nullptr) { + // We haven't see compilations of this method in training. It's either very cold or the behavior changed. + // Feed it to the standard TF with no profiling delay. + next_level = standard_transition(method, cur_level, false /*delay_profiling*/, disable_feedback); } else { - switch(cur_level) { - default: break; - case CompLevel_none: - // If we were at full profile level, would we switch to full opt? - if (common(method, CompLevel_full_profile, disable_feedback) == CompLevel_full_optimization) { - next_level = CompLevel_full_optimization; - } else if (!CompilationModeFlag::disable_intermediate() && Predicate::apply(method, cur_level, i, b)) { - // C1-generated fully profiled code is about 30% slower than the limited profile - // code that has only invocation and backedge counters. The observation is that - // if C2 queue is large enough we can spend too much time in the fully profiled code - // while waiting for C2 to pick the method from the queue. To alleviate this problem - // we introduce a feedback on the C2 queue size. If the C2 queue is sufficiently long - // we choose to compile a limited profiled version and then recompile with full profiling - // when the load on C2 goes down. - if (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) > - Tier3DelayOn * compiler_count(CompLevel_full_optimization)) { - next_level = CompLevel_limited_profile; - } else { - next_level = CompLevel_full_profile; - } - } - break; - case CompLevel_limited_profile: - if (is_method_profiled(method)) { - // Special case: we got here because this method was fully profiled in the interpreter. - next_level = CompLevel_full_optimization; - } else { - MethodData* mdo = method->method_data(); - if (mdo != nullptr) { - if (mdo->would_profile()) { - if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= - Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - Predicate::apply(method, cur_level, i, b))) { - next_level = CompLevel_full_profile; - } - } else { - next_level = CompLevel_full_optimization; - } - } else { - // If there is no MDO we need to profile - if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= - Tier3DelayOff * compiler_count(CompLevel_full_optimization) && - Predicate::apply(method, cur_level, i, b))) { - next_level = CompLevel_full_profile; - } - } - } - break; - case CompLevel_full_profile: - { - MethodData* mdo = method->method_data(); - if (mdo != nullptr) { - if (mdo->would_profile() || CompilationModeFlag::disable_intermediate()) { - int mdo_i = mdo->invocation_count_delta(); - int mdo_b = mdo->backedge_count_delta(); - if (Predicate::apply(method, cur_level, mdo_i, mdo_b)) { - next_level = CompLevel_full_optimization; - } - } else { - next_level = CompLevel_full_optimization; - } - } - } - break; + next_level = trained_transition(method, cur_level, mtd, THREAD); + if (cur_level == next_level) { + // trained_transtion() is going to return the same level if no startup/warmup optimizations apply. + // In order to catch possible pathologies due to behavior change we feed the event to the regular + // TF but with profiling delay. + next_level = standard_transition(method, cur_level, true /*delay_profiling*/, disable_feedback); } } + } else { + next_level = standard_transition(method, cur_level, false /*delay_profiling*/, disable_feedback); } return (next_level != cur_level) ? limit_level(next_level) : next_level; } +template +CompLevel CompilationPolicy::standard_transition(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback) { + CompLevel next_level = cur_level; + switch(cur_level) { + default: break; + case CompLevel_none: + next_level = transition_from_none(method, cur_level, delay_profiling, disable_feedback); + break; + case CompLevel_limited_profile: + next_level = transition_from_limited_profile(method, cur_level, delay_profiling, disable_feedback); + break; + case CompLevel_full_profile: + next_level = transition_from_full_profile(method, cur_level); + break; + } + return next_level; +} + +template +CompLevel CompilationPolicy::transition_from_none(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback) { + precond(cur_level == CompLevel_none); + CompLevel next_level = cur_level; + int i = method->invocation_count(); + int b = method->backedge_count(); + double scale = delay_profiling ? Tier0ProfileDelayFactor : 1.0; + // If we were at full profile level, would we switch to full opt? + if (transition_from_full_profile(method, CompLevel_full_profile) == CompLevel_full_optimization) { + next_level = CompLevel_full_optimization; + } else if (!CompilationModeFlag::disable_intermediate() && Predicate::apply_scaled(method, cur_level, i, b, scale)) { + // C1-generated fully profiled code is about 30% slower than the limited profile + // code that has only invocation and backedge counters. The observation is that + // if C2 queue is large enough we can spend too much time in the fully profiled code + // while waiting for C2 to pick the method from the queue. To alleviate this problem + // we introduce a feedback on the C2 queue size. If the C2 queue is sufficiently long + // we choose to compile a limited profiled version and then recompile with full profiling + // when the load on C2 goes down. + if (delay_profiling || (!disable_feedback && CompileBroker::queue_size(CompLevel_full_optimization) > Tier3DelayOn * compiler_count(CompLevel_full_optimization))) { + next_level = CompLevel_limited_profile; + } else { + next_level = CompLevel_full_profile; + } + } + return next_level; +} + +template +CompLevel CompilationPolicy::transition_from_full_profile(const methodHandle& method, CompLevel cur_level) { + precond(cur_level == CompLevel_full_profile); + CompLevel next_level = cur_level; + MethodData* mdo = method->method_data(); + if (mdo != nullptr) { + if (mdo->would_profile() || CompilationModeFlag::disable_intermediate()) { + int mdo_i = mdo->invocation_count_delta(); + int mdo_b = mdo->backedge_count_delta(); + if (Predicate::apply(method, cur_level, mdo_i, mdo_b)) { + next_level = CompLevel_full_optimization; + } + } else { + next_level = CompLevel_full_optimization; + } + } + return next_level; +} + +template +CompLevel CompilationPolicy::transition_from_limited_profile(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback) { + precond(cur_level == CompLevel_limited_profile); + CompLevel next_level = cur_level; + int i = method->invocation_count(); + int b = method->backedge_count(); + double scale = delay_profiling ? Tier2ProfileDelayFactor : 1.0; + MethodData* mdo = method->method_data(); + if (mdo != nullptr) { + if (mdo->would_profile()) { + if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= + Tier3DelayOff * compiler_count(CompLevel_full_optimization) && + Predicate::apply_scaled(method, cur_level, i, b, scale))) { + next_level = CompLevel_full_profile; + } + } else { + next_level = CompLevel_full_optimization; + } + } else { + // If there is no MDO we need to profile + if (disable_feedback || (CompileBroker::queue_size(CompLevel_full_optimization) <= + Tier3DelayOff * compiler_count(CompLevel_full_optimization) && + Predicate::apply_scaled(method, cur_level, i, b, scale))) { + next_level = CompLevel_full_profile; + } + } + if (next_level == CompLevel_full_profile && is_method_profiled(method)) { + next_level = CompLevel_full_optimization; + } + return next_level; +} + // Determine if a method should be compiled with a normal entry point at a different level. -CompLevel CompilationPolicy::call_event(const methodHandle& method, CompLevel cur_level, Thread* thread) { - CompLevel osr_level = MIN2((CompLevel) method->highest_osr_comp_level(), common(method, cur_level, true)); - CompLevel next_level = common(method, cur_level, is_old(method)); +CompLevel CompilationPolicy::call_event(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD) { + CompLevel osr_level = MIN2((CompLevel) method->highest_osr_comp_level(), common(method, cur_level, THREAD, true)); + CompLevel next_level = common(method, cur_level, THREAD, !TrainingData::have_data() && is_old(method)); // If OSR method level is greater than the regular method level, the levels should be // equalized by raising the regular method level in order to avoid OSRs during each @@ -1122,12 +1431,18 @@ CompLevel CompilationPolicy::call_event(const methodHandle& method, CompLevel cu } else { next_level = MAX2(osr_level, next_level); } +#if INCLUDE_JVMCI + if (EnableJVMCI && UseJVMCICompiler && + next_level == CompLevel_full_optimization CDS_ONLY(&& !AOTLinkedClassBulkLoader::class_preloading_finished())) { + next_level = cur_level; + } +#endif return next_level; } // Determine if we should do an OSR compilation of a given method. -CompLevel CompilationPolicy::loop_event(const methodHandle& method, CompLevel cur_level, Thread* thread) { - CompLevel next_level = common(method, cur_level, true); +CompLevel CompilationPolicy::loop_event(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD) { + CompLevel next_level = common(method, cur_level, THREAD, true); if (cur_level == CompLevel_none) { // If there is a live OSR method that means that we deopted to the interpreter // for the transition. @@ -1201,7 +1516,7 @@ void CompilationPolicy::method_back_branch_event(const methodHandle& mh, const m int osr_bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci; print_event(MAKE_NOT_ENTRANT, mh(), mh(), osr_bci, level); } - nm->make_not_entrant("OSR invalidation, back branch"); + nm->make_not_entrant(nmethod::ChangeReason::OSR_invalidation_back_branch); } } // Fix up next_level if necessary to avoid deopts diff --git a/src/hotspot/share/compiler/compilationPolicy.hpp b/src/hotspot/share/compiler/compilationPolicy.hpp index fe33fb8cfba..75374a2f830 100644 --- a/src/hotspot/share/compiler/compilationPolicy.hpp +++ b/src/hotspot/share/compiler/compilationPolicy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,8 +28,82 @@ #include "code/nmethod.hpp" #include "compiler/compileBroker.hpp" #include "oops/methodData.hpp" +#include "oops/trainingData.hpp" #include "utilities/globalDefinitions.hpp" +namespace CompilationPolicyUtils { +template +class Queue { + class QueueNode : public CHeapObj { + T* _value; + QueueNode* _next; + public: + QueueNode(T* value, QueueNode* next) : _value(value), _next(next) { } + T* value() const { return _value; } + void set_next(QueueNode* next) { _next = next; } + QueueNode* next() const { return _next; } + }; + + QueueNode* _head; + QueueNode* _tail; + + void push_unlocked(T* value) { + QueueNode* n = new QueueNode(value, nullptr); + if (_tail != nullptr) { + _tail->set_next(n); + } + _tail = n; + if (_head == nullptr) { + _head = _tail; + } + } + T* pop_unlocked() { + QueueNode* n = _head; + if (_head != nullptr) { + _head = _head->next(); + } + if (_head == nullptr) { + _tail = _head; + } + T* value = nullptr; + if (n != nullptr) { + value = n->value(); + delete n; + } + return value; + } +public: + Queue() : _head(nullptr), _tail(nullptr) { } + void push(T* value, Monitor* lock, TRAPS) { + MonitorLocker locker(THREAD, lock); + push_unlocked(value); + locker.notify_all(); + } + + bool is_empty_unlocked() const { return _head == nullptr; } + + T* pop(Monitor* lock, TRAPS) { + MonitorLocker locker(THREAD, lock); + while(is_empty_unlocked() && !CompileBroker::is_compilation_disabled_forever()) { + locker.wait(); + } + T* value = pop_unlocked(); + return value; + } + + T* try_pop(Monitor* lock, TRAPS) { + MonitorLocker locker(THREAD, lock); + T* value = nullptr; + if (!is_empty_unlocked()) { + value = pop_unlocked(); + } + return value; + } + + void print_on(outputStream* st); +}; +} // namespace CompilationPolicyUtils + class CompileTask; class CompileQueue; /* @@ -173,9 +247,12 @@ class CompilationPolicy : AllStatic { friend class CallPredicate; friend class LoopPredicate; - static jlong _start_time; + typedef CompilationPolicyUtils::Queue TrainingReplayQueue; + + static int64_t _start_time; static int _c1_count, _c2_count; static double _increase_threshold_at_ratio; + static TrainingReplayQueue _training_replay_queue; // Set carry flags in the counters (in Method* and MDO). inline static void handle_counter_overflow(const methodHandle& method); @@ -187,29 +264,45 @@ class CompilationPolicy : AllStatic { inline static CompLevel limit_level(CompLevel level); // Common transition function. Given a predicate determines if a method should transition to another level. template - static CompLevel common(const methodHandle& method, CompLevel cur_level, bool disable_feedback = false); + static CompLevel common(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD, bool disable_feedback = false); + + template + static CompLevel transition_from_none(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback); + template + static CompLevel transition_from_limited_profile(const methodHandle& method, CompLevel cur_level, bool delay_profiling, bool disable_feedback); + template + static CompLevel transition_from_full_profile(const methodHandle& method, CompLevel cur_level); + template + static CompLevel standard_transition(const methodHandle& method, CompLevel cur_level, bool delayprof, bool disable_feedback); + + static CompLevel trained_transition_from_none(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD); + static CompLevel trained_transition_from_limited_profile(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD); + static CompLevel trained_transition_from_full_profile(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD); + static CompLevel trained_transition(const methodHandle& method, CompLevel cur_level, MethodTrainingData* mtd, JavaThread* THREAD); + // Transition functions. // call_event determines if a method should be compiled at a different // level with a regular invocation entry. - static CompLevel call_event(const methodHandle& method, CompLevel cur_level, Thread* thread); + static CompLevel call_event(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD); // loop_event checks if a method should be OSR compiled at a different // level. - static CompLevel loop_event(const methodHandle& method, CompLevel cur_level, Thread* thread); - static void print_counters(const char* prefix, const Method* m); + static CompLevel loop_event(const methodHandle& method, CompLevel cur_level, JavaThread* THREAD); + static void print_counters(const char* prefix, Method* m); + static void print_training_data(const char* prefix, Method* method); // Has a method been long around? // We don't remove old methods from the compile queue even if they have // very low activity (see select_task()). inline static bool is_old(const methodHandle& method); // Was a given method inactive for a given number of milliseconds. // If it is, we would remove it from the queue (see select_task()). - inline static bool is_stale(jlong t, jlong timeout, const methodHandle& method); + inline static bool is_stale(int64_t t, int64_t timeout, const methodHandle& method); // Compute the weight of the method for the compilation scheduling inline static double weight(Method* method); // Apply heuristics and return true if x should be compiled before y inline static bool compare_methods(Method* x, Method* y); // Compute event rate for a given method. The rate is the number of event (invocations + backedges) // per millisecond. - inline static void update_rate(jlong t, const methodHandle& method); + inline static void update_rate(int64_t t, const methodHandle& method); // Compute threshold scaling coefficient inline static double threshold_scale(CompLevel level, int feedback_k); // If a method is old enough and is still in the interpreter we would want to @@ -224,8 +317,8 @@ class CompilationPolicy : AllStatic { static void set_c1_count(int x) { _c1_count = x; } static void set_c2_count(int x) { _c2_count = x; } - enum EventType { CALL, LOOP, COMPILE, REMOVE_FROM_QUEUE, UPDATE_IN_QUEUE, REPROFILE, MAKE_NOT_ENTRANT }; - static void print_event(EventType type, const Method* m, const Method* im, int bci, CompLevel level); + enum EventType { CALL, LOOP, COMPILE, FORCE_COMPILE, FORCE_RECOMPILE, REMOVE_FROM_QUEUE, UPDATE_IN_QUEUE, REPROFILE, MAKE_NOT_ENTRANT }; + static void print_event(EventType type, Method* m, Method* im, int bci, CompLevel level); // Check if the method can be compiled, change level if necessary static void compile(const methodHandle& mh, int bci, CompLevel level, TRAPS); // Simple methods are as good being compiled with C1 as C2. @@ -242,21 +335,25 @@ class CompilationPolicy : AllStatic { int bci, CompLevel level, nmethod* nm, TRAPS); static void set_increase_threshold_at_ratio() { _increase_threshold_at_ratio = 100 / (100 - (double)IncreaseFirstTierCompileThresholdAt); } - static void set_start_time(jlong t) { _start_time = t; } - static jlong start_time() { return _start_time; } + static void set_start_time(int64_t t) { _start_time = t; } + static int64_t start_time() { return _start_time; } // m must be compiled before executing it static bool must_be_compiled(const methodHandle& m, int comp_level = CompLevel_any); -public: + static void maybe_compile_early(const methodHandle& m, TRAPS); + static void replay_training_at_init_impl(InstanceKlass* klass, TRAPS); + public: static int min_invocations() { return Tier4MinInvocationThreshold; } static int c1_count() { return _c1_count; } static int c2_count() { return _c2_count; } static int compiler_count(CompLevel comp_level); - // If m must_be_compiled then request a compilation from the CompileBroker. // This supports the -Xcomp option. static void compile_if_required(const methodHandle& m, TRAPS); + static void replay_training_at_init(InstanceKlass* klass, TRAPS); + static void replay_training_at_init_loop(TRAPS); + // m is allowed to be compiled static bool can_be_compiled(const methodHandle& m, int comp_level = CompLevel_any); // m is allowed to be osr compiled @@ -269,9 +366,9 @@ class CompilationPolicy : AllStatic { static nmethod* event(const methodHandle& method, const methodHandle& inlinee, int branch_bci, int bci, CompLevel comp_level, nmethod* nm, TRAPS); // Select task is called by CompileBroker. We should return a task or nullptr. - static CompileTask* select_task(CompileQueue* compile_queue); + static CompileTask* select_task(CompileQueue* compile_queue, JavaThread* THREAD); // Tell the runtime if we think a given method is adequately profiled. - static bool is_mature(Method* method); + static bool is_mature(MethodData* mdo); // Initialize: set compiler thread count static void initialize(); static bool should_not_inline(ciEnv* env, ciMethod* callee); @@ -280,6 +377,7 @@ class CompilationPolicy : AllStatic { static CompLevel initial_compile_level(const methodHandle& method); // Return highest level possible static CompLevel highest_compile_level(); + static void dump(); }; #endif // SHARE_COMPILER_COMPILATIONPOLICY_HPP diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 168679feb9b..b5f02b2d9a2 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/cdsConfig.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/symbolTable.hpp" #include "classfile/vmClasses.hpp" @@ -230,7 +231,7 @@ CompileTaskWrapper::~CompileTaskWrapper() { if (task->is_blocking()) { bool free_task = false; { - MutexLocker notifier(thread, task->lock()); + MutexLocker notifier(thread, CompileTaskWait_lock); task->mark_complete(); #if INCLUDE_JVMCI if (CompileBroker::compiler(task->comp_level())->is_jvmci()) { @@ -244,7 +245,7 @@ CompileTaskWrapper::~CompileTaskWrapper() { if (!free_task) { // Notify the waiting thread that the compilation has completed // so that it can free the task. - task->lock()->notify_all(); + CompileTaskWait_lock->notify_all(); } } if (free_task) { @@ -347,6 +348,13 @@ void CompileQueue::add(CompileTask* task) { task->log_task_queued(); } + if (TrainingData::need_data() && !CDSConfig::is_dumping_final_static_archive()) { + CompileTrainingData* ctd = CompileTrainingData::make(task); + if (ctd != nullptr) { + task->set_training_data(ctd); + } + } + // Notify CompilerThreads that a task is available. MethodCompileQueue_lock->notify_all(); } @@ -367,12 +375,12 @@ void CompileQueue::free_all() { next = current->next(); bool found_waiter = false; { - MutexLocker ct_lock(current->lock()); + MutexLocker ct_lock(CompileTaskWait_lock); assert(current->waiting_for_completion_count() <= 1, "more than one thread are waiting for task"); if (current->waiting_for_completion_count() > 0) { // If another thread waits for this task, we must wake them up // so they will stop waiting and free the task. - current->lock()->notify(); + CompileTaskWait_lock->notify_all(); found_waiter = true; } } @@ -398,7 +406,6 @@ CompileTask* CompileQueue::get(CompilerThread* thread) { // save methods from RedefineClasses across safepoint // across MethodCompileQueue_lock below. methodHandle save_method; - methodHandle save_hot_method; MonitorLocker locker(MethodCompileQueue_lock); // If _first is null we have no more compile jobs. There are two reasons for @@ -442,7 +449,7 @@ CompileTask* CompileQueue::get(CompilerThread* thread) { CompileTask* task; { NoSafepointVerifier nsv; - task = CompilationPolicy::select_task(this); + task = CompilationPolicy::select_task(this, thread); if (task != nullptr) { task = task->select_for_compilation(); } @@ -453,7 +460,6 @@ CompileTask* CompileQueue::get(CompilerThread* thread) { // the compilation queue, which is walked during RedefineClasses. Thread* thread = Thread::current(); save_method = methodHandle(thread, task->method()); - save_hot_method = methodHandle(thread, task->hot_method()); remove(task); } @@ -783,6 +789,10 @@ void CompileBroker::compilation_init(JavaThread* THREAD) { _initialized = true; } +void TrainingReplayThread::training_replay_thread_entry(JavaThread* thread, TRAPS) { + CompilationPolicy::replay_training_at_init_loop(thread); +} + #if defined(ASSERT) && COMPILER2_OR_JVMCI // Entry for DeoptimizeObjectsALotThread. The threads are started in // CompileBroker::init_compiler_threads() iff DeoptimizeObjectsALot is enabled @@ -860,6 +870,9 @@ JavaThread* CompileBroker::make_thread(ThreadType type, jobject thread_handle, C new_thread = new DeoptimizeObjectsALotThread(); break; #endif // ASSERT + case training_replay_t: + new_thread = new TrainingReplayThread(); + break; default: ShouldNotReachHere(); } @@ -1017,6 +1030,16 @@ void CompileBroker::init_compiler_threads() { #endif // defined(ASSERT) && COMPILER2_OR_JVMCI } +void CompileBroker::init_training_replay() { + // Ensure any exceptions lead to vm_exit_during_initialization. + EXCEPTION_MARK; + if (TrainingData::have_data()) { + Handle thread_oop = JavaThread::create_system_thread_object("Training replay thread", CHECK); + jobject thread_handle = JNIHandles::make_local(THREAD, thread_oop()); + make_thread(training_replay_t, thread_handle, nullptr, nullptr, THREAD); + } +} + void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) { int old_c2_count = 0, new_c2_count = 0, old_c1_count = 0, new_c1_count = 0; @@ -1154,7 +1177,6 @@ void CompileBroker::mark_on_stack() { void CompileBroker::compile_method_base(const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, CompileTask::CompileReason compile_reason, bool blocking, @@ -1173,13 +1195,8 @@ void CompileBroker::compile_method_base(const methodHandle& method, tty->print(" osr_bci: %d", osr_bci); } tty->print(" level: %d comment: %s count: %d", comp_level, CompileTask::reason_name(compile_reason), hot_count); - if (!hot_method.is_null()) { - tty->print(" hot: "); - if (hot_method() != method()) { - hot_method->print_short_name(tty); - } else { - tty->print("yes"); - } + if (hot_count > 0) { + tty->print(" hot: yes"); } tty->cr(); } @@ -1326,7 +1343,7 @@ void CompileBroker::compile_method_base(const methodHandle& method, task = create_compile_task(queue, compile_id, method, osr_bci, comp_level, - hot_method, hot_count, compile_reason, + hot_count, compile_reason, blocking); } @@ -1337,7 +1354,7 @@ void CompileBroker::compile_method_base(const methodHandle& method, nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, + int hot_count, CompileTask::CompileReason compile_reason, TRAPS) { // Do nothing if compilebroker is not initialized or compiles are submitted on level none @@ -1357,14 +1374,14 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci, DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, comp); // CompileBroker::compile_method can trap and can have pending async exception. - nmethod* nm = CompileBroker::compile_method(method, osr_bci, comp_level, hot_method, hot_count, compile_reason, directive, THREAD); + nmethod* nm = CompileBroker::compile_method(method, osr_bci, comp_level, hot_count, compile_reason, directive, THREAD); DirectivesStack::release(directive); return nm; } nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, + int hot_count, CompileTask::CompileReason compile_reason, DirectiveSet* directive, TRAPS) { @@ -1460,7 +1477,7 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci, return nullptr; } bool is_blocking = !directive->BackgroundCompilationOption || ReplayCompiles; - compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, compile_reason, is_blocking, THREAD); + compile_method_base(method, osr_bci, comp_level, hot_count, compile_reason, is_blocking, THREAD); } // return requested nmethod @@ -1607,13 +1624,12 @@ CompileTask* CompileBroker::create_compile_task(CompileQueue* queue, const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, CompileTask::CompileReason compile_reason, bool blocking) { CompileTask* new_task = CompileTask::allocate(); new_task->initialize(compile_id, method, osr_bci, comp_level, - hot_method, hot_count, compile_reason, + hot_count, compile_reason, blocking); queue->add(new_task); return new_task; @@ -1639,7 +1655,7 @@ static const int JVMCI_COMPILATION_PROGRESS_WAIT_ATTEMPTS = 10; */ bool CompileBroker::wait_for_jvmci_completion(JVMCICompiler* jvmci, CompileTask* task, JavaThread* thread) { assert(UseJVMCICompiler, "sanity"); - MonitorLocker ml(thread, task->lock()); + MonitorLocker ml(thread, CompileTaskWait_lock); int progress_wait_attempts = 0; jint thread_jvmci_compilation_ticks = 0; jint global_jvmci_compilation_ticks = jvmci->global_compilation_ticks(); @@ -1707,7 +1723,7 @@ void CompileBroker::wait_for_completion(CompileTask* task) { } else #endif { - MonitorLocker ml(thread, task->lock()); + MonitorLocker ml(thread, CompileTaskWait_lock); free_task = true; task->inc_waiting_for_completion(); while (!task->is_complete() && !is_compilation_disabled_forever()) { diff --git a/src/hotspot/share/compiler/compileBroker.hpp b/src/hotspot/share/compiler/compileBroker.hpp index 77662692f56..9a0e77ce4ba 100644 --- a/src/hotspot/share/compiler/compileBroker.hpp +++ b/src/hotspot/share/compiler/compileBroker.hpp @@ -254,11 +254,13 @@ class CompileBroker: AllStatic { enum ThreadType { compiler_t, - deoptimizer_t + deoptimizer_t, + training_replay_t }; static JavaThread* make_thread(ThreadType type, jobject thread_oop, CompileQueue* queue, AbstractCompiler* comp, JavaThread* THREAD); static void init_compiler_threads(); + static void init_training_replay(); static void possibly_add_compiler_threads(JavaThread* THREAD); static bool compilation_is_prohibited(const methodHandle& method, int osr_bci, int comp_level, bool excluded); @@ -267,7 +269,6 @@ class CompileBroker: AllStatic { const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, CompileTask::CompileReason compile_reason, bool blocking); @@ -288,7 +289,6 @@ class CompileBroker: AllStatic { static void compile_method_base(const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, CompileTask::CompileReason compile_reason, bool blocking, @@ -322,7 +322,6 @@ class CompileBroker: AllStatic { static nmethod* compile_method(const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, CompileTask::CompileReason compile_reason, TRAPS); @@ -333,7 +332,6 @@ class CompileBroker: AllStatic { static nmethod* compile_method(const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, CompileTask::CompileReason compile_reason, DirectiveSet* directive, @@ -451,4 +449,16 @@ class CompileBroker: AllStatic { static void print_heapinfo(outputStream *out, const char* function, size_t granularity); }; +// In order to achiveve a maximally fast warmup we attempt to compile important methods as soon as all +// the classes that they depend on are initialized. TrainingReplayThread processes a queue of InstanceKlass* +// that have just finished running their static initializers. We find all the methods that depend on the given class +// and for which the number of remaining dependencies is now zero, and eagerly compile them. +class TrainingReplayThread : public JavaThread { + static void training_replay_thread_entry(JavaThread* thread, TRAPS); +public: + TrainingReplayThread() : JavaThread(&training_replay_thread_entry) { } + + bool is_hidden_from_external_view() const { return true; } +}; + #endif // SHARE_COMPILER_COMPILEBROKER_HPP diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index 87d4a11e528..b955a250fae 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -65,14 +65,10 @@ CompileTask* CompileTask::allocate() { void CompileTask::free(CompileTask* task) { MutexLocker locker(CompileTaskAlloc_lock); if (!task->is_free()) { - assert(!task->lock()->is_locked(), "Should not be locked when freed"); - if ((task->_method_holder != nullptr && JNIHandles::is_weak_global_handle(task->_method_holder)) || - (task->_hot_method_holder != nullptr && JNIHandles::is_weak_global_handle(task->_hot_method_holder))) { + if ((task->_method_holder != nullptr && JNIHandles::is_weak_global_handle(task->_method_holder))) { JNIHandles::destroy_weak_global(task->_method_holder); - JNIHandles::destroy_weak_global(task->_hot_method_holder); } else { JNIHandles::destroy_global(task->_method_holder); - JNIHandles::destroy_global(task->_hot_method_holder); } if (task->_failure_reason_on_C_heap && task->_failure_reason != nullptr) { os::free((void*) task->_failure_reason); @@ -90,12 +86,9 @@ void CompileTask::initialize(int compile_id, const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, CompileTask::CompileReason compile_reason, bool is_blocking) { - assert(!_lock->is_locked(), "bad locking"); - Thread* thread = Thread::current(); _compile_id = compile_id; _method = method(); @@ -112,8 +105,6 @@ void CompileTask::initialize(int compile_id, _is_complete = false; _is_success = false; - _hot_method = nullptr; - _hot_method_holder = nullptr; _hot_count = hot_count; _time_queued = os::elapsed_counter(); _time_started = 0; @@ -125,20 +116,9 @@ void CompileTask::initialize(int compile_id, _nm_total_size = 0; _failure_reason = nullptr; _failure_reason_on_C_heap = false; + _training_data = nullptr; _arena_bytes = 0; - if (LogCompilation) { - if (hot_method.not_null()) { - if (hot_method == method) { - _hot_method = _method; - } else { - _hot_method = hot_method(); - // only add loader or mirror if different from _method_holder - _hot_method_holder = JNIHandles::make_weak_global(Handle(thread, hot_method->method_holder()->klass_holder())); - } - } - } - _next = nullptr; } @@ -159,11 +139,7 @@ CompileTask* CompileTask::select_for_compilation() { assert(_method->method_holder()->is_loader_alive(), "should be alive"); Handle method_holder(thread, _method->method_holder()->klass_holder()); JNIHandles::destroy_weak_global(_method_holder); - JNIHandles::destroy_weak_global(_hot_method_holder); _method_holder = JNIHandles::make_global(method_holder); - if (_hot_method != nullptr) { - _hot_method_holder = JNIHandles::make_global(Handle(thread, _hot_method->method_holder()->klass_holder())); - } return this; } @@ -173,9 +149,6 @@ void CompileTask::mark_on_stack() { } // Mark these methods as something redefine classes cannot remove. _method->set_on_stack(true); - if (_hot_method != nullptr) { - _hot_method->set_on_stack(true); - } } bool CompileTask::is_unloaded() const { @@ -188,9 +161,6 @@ void CompileTask::metadata_do(MetadataClosure* f) { return; } f->do_metadata(method()); - if (hot_method() != nullptr && hot_method() != method()) { - f->do_metadata(hot_method()); - } } // ------------------------------------------------------------------ @@ -329,9 +299,6 @@ void CompileTask::log_task_queued() { assert(_compile_reason > CompileTask::Reason_None && _compile_reason < CompileTask::Reason_Count, "Valid values"); xtty->print(" comment='%s'", reason_name(_compile_reason)); - if (_hot_method != nullptr && _hot_method != _method) { - xtty->method(_hot_method); - } if (_hot_count != 0) { xtty->print(" hot_count='%d'", _hot_count); } @@ -471,7 +438,7 @@ void CompileTask::print_inlining_inner_message(outputStream* st, InliningResult } void CompileTask::print_ul(const char* msg){ - LogTarget(Debug, jit, compilation) lt; + LogTarget(Info, jit, compilation) lt; if (lt.is_enabled()) { LogStream ls(lt); print(&ls, msg, /* short form */ true, /* cr */ true); @@ -479,7 +446,7 @@ void CompileTask::print_ul(const char* msg){ } void CompileTask::print_ul(const nmethod* nm, const char* msg) { - LogTarget(Debug, jit, compilation) lt; + LogTarget(Info, jit, compilation) lt; if (lt.is_enabled()) { LogStream ls(lt); print_impl(&ls, nm->method(), nm->compile_id(), diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 04ad7e35a13..166f6497f2b 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -29,8 +29,10 @@ #include "code/nmethod.hpp" #include "compiler/compileLog.hpp" #include "memory/allocation.hpp" +#include "runtime/mutexLocker.hpp" #include "utilities/xmlstream.hpp" +class CompileTrainingData; class DirectiveSet; JVMCI_ONLY(class JVMCICompileState;) @@ -81,7 +83,6 @@ class CompileTask : public CHeapObj { private: static CompileTask* _task_free_list; - Monitor* _lock; int _compile_id; Method* _method; jobject _method_holder; @@ -106,23 +107,18 @@ class CompileTask : public CHeapObj { // Fields used for logging why the compilation was initiated: jlong _time_queued; // time when task was enqueued jlong _time_started; // time when compilation started - Method* _hot_method; // which method actually triggered this task - jobject _hot_method_holder; int _hot_count; // information about its invocation counter CompileReason _compile_reason; // more info about the task const char* _failure_reason; // Specifies if _failure_reason is on the C heap. bool _failure_reason_on_C_heap; + CompileTrainingData* _training_data; size_t _arena_bytes; // peak size of temporary memory during compilation (e.g. node arenas) public: - CompileTask() : _failure_reason(nullptr), _failure_reason_on_C_heap(false) { - // May hold MethodCompileQueue_lock - _lock = new Monitor(Mutex::safepoint-1, "CompileTask_lock"); - } - + CompileTask() : _failure_reason(nullptr), _failure_reason_on_C_heap(false) {} void initialize(int compile_id, const methodHandle& method, int osr_bci, int comp_level, - const methodHandle& hot_method, int hot_count, + int hot_count, CompileTask::CompileReason compile_reason, bool is_blocking); static CompileTask* allocate(); @@ -130,7 +126,6 @@ class CompileTask : public CHeapObj { int compile_id() const { return _compile_id; } Method* method() const { return _method; } - Method* hot_method() const { return _hot_method; } int osr_bci() const { return _osr_bci; } bool is_complete() const { return _is_complete; } bool is_blocking() const { return _is_blocking; } @@ -173,21 +168,19 @@ class CompileTask : public CHeapObj { } #endif - Monitor* lock() const { return _lock; } - // See how many threads are waiting for this task. Must have lock to read this. int waiting_for_completion_count() { - assert(_lock->owned_by_self(), "must have lock to use waiting_for_completion_count()"); + assert(CompileTaskWait_lock->owned_by_self(), "must have lock to use waiting_for_completion_count()"); return _waiting_count; } // Indicates that a thread is waiting for this task to complete. Must have lock to use this. void inc_waiting_for_completion() { - assert(_lock->owned_by_self(), "must have lock to use inc_waiting_for_completion()"); + assert(CompileTaskWait_lock->owned_by_self(), "must have lock to use inc_waiting_for_completion()"); _waiting_count++; } // Indicates that a thread stopped waiting for this task to complete. Must have lock to use this. void dec_waiting_for_completion() { - assert(_lock->owned_by_self(), "must have lock to use dec_waiting_for_completion()"); + assert(CompileTaskWait_lock->owned_by_self(), "must have lock to use dec_waiting_for_completion()"); assert(_waiting_count > 0, "waiting count is not positive"); _waiting_count--; } @@ -215,6 +208,9 @@ class CompileTask : public CHeapObj { void set_is_free(bool val) { _is_free = val; } bool is_unloaded() const; + CompileTrainingData* training_data() const { return _training_data; } + void set_training_data(CompileTrainingData* td) { _training_data = td; } + // RedefineClasses support void metadata_do(MetadataClosure* f); void mark_on_stack(); diff --git a/src/hotspot/share/compiler/compilerDefinitions.hpp b/src/hotspot/share/compiler/compilerDefinitions.hpp index bdaa6dffb8f..bacc1f73f97 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.hpp +++ b/src/hotspot/share/compiler/compilerDefinitions.hpp @@ -59,7 +59,8 @@ enum CompLevel : s1 { CompLevel_simple = 1, // C1 CompLevel_limited_profile = 2, // C1, invocation & backedge counters CompLevel_full_profile = 3, // C1, invocation & backedge counters + mdo - CompLevel_full_optimization = 4 // C2 or JVMCI + CompLevel_full_optimization = 4, // C2 or JVMCI + CompLevel_count = 5 }; class CompilationModeFlag : AllStatic { diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index 27c71b1723c..27aafe06919 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -83,7 +83,8 @@ NOT_PRODUCT(cflags(PrintIdeal, bool, PrintIdeal, PrintIdeal)) \ cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \ cflags(Vectorize, bool, false, Vectorize) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \ -NOT_PRODUCT(cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel)) \ +NOT_PRODUCT(cflags(PhasePrintLevel, intx, PrintPhaseLevel, PhasePrintLevel)) \ +NOT_PRODUCT(cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLevel)) \ cflags(IncrementalInlineForceCleanup, bool, IncrementalInlineForceCleanup, IncrementalInlineForceCleanup) \ cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) #define compilerdirectives_c2_string_flags(cflags) \ @@ -202,7 +203,7 @@ void set_##name(void* value) { \ void set_ideal_phase_name_set(const BitMap& set) { _ideal_phase_name_set.set_from(set); }; - bool should_print_phase(const CompilerPhaseType cpt) const { + bool should_print_ideal_phase(const CompilerPhaseType cpt) const { return _ideal_phase_name_set.at(cpt); }; void set_trace_auto_vectorization_tags(const CHeapBitMap& tags) { diff --git a/src/hotspot/share/compiler/compilerOracle.cpp b/src/hotspot/share/compiler/compilerOracle.cpp index e7ef9703191..868ae8bfa41 100644 --- a/src/hotspot/share/compiler/compilerOracle.cpp +++ b/src/hotspot/share/compiler/compilerOracle.cpp @@ -317,8 +317,10 @@ TypedMethodOptionMatcher* TypedMethodOptionMatcher::match(const methodHandle& me } template -static void register_command(TypedMethodOptionMatcher* matcher, +static bool register_command(TypedMethodOptionMatcher* matcher, CompileCommandEnum option, + char* errorbuf, + const int buf_size, T value) { assert(matcher != option_list, "No circular lists please"); if (option == CompileCommandEnum::Log && !LogCompilation) { @@ -331,7 +333,17 @@ static void register_command(TypedMethodOptionMatcher* matcher, warning("Blackhole compile option is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions"); // Delete matcher as we don't keep it delete matcher; - return; + return true; + } + + if (!UnlockDiagnosticVMOptions) { + const char* name = option2name(option); + JVMFlag* flag = JVMFlag::find_declared_flag(name); + if (flag != nullptr && flag->is_diagnostic()) { + jio_snprintf(errorbuf, buf_size, "VM option '%s' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions.", name); + delete matcher; + return false; + } } matcher->init(option, option_list); @@ -346,7 +358,7 @@ static void register_command(TypedMethodOptionMatcher* matcher, matcher->print(); } - return; + return true; } template @@ -714,7 +726,7 @@ static bool parseMemStat(const char* line, uintx& value, int& bytes_read, char* return false; } -static void scan_value(enum OptionType type, char* line, int& total_bytes_read, +static bool scan_value(enum OptionType type, char* line, int& total_bytes_read, TypedMethodOptionMatcher* matcher, CompileCommandEnum option, char* errorbuf, const int buf_size) { int bytes_read = 0; const char* ccname = option2name(option); @@ -733,11 +745,10 @@ static void scan_value(enum OptionType type, char* line, int& total_bytes_read, } if (success) { total_bytes_read += bytes_read; - line += bytes_read; - register_command(matcher, option, value); - return; + return register_command(matcher, option, errorbuf, buf_size, value); } else { jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str); + return false; } } else if (type == OptionType::Uintx) { uintx value; @@ -751,21 +762,20 @@ static void scan_value(enum OptionType type, char* line, int& total_bytes_read, } if (success) { total_bytes_read += bytes_read; - line += bytes_read; - register_command(matcher, option, value); + return register_command(matcher, option, errorbuf, buf_size, value); } else { jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str); + return false; } } else if (type == OptionType::Ccstr) { ResourceMark rm; char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); if (sscanf(line, "%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) { total_bytes_read += bytes_read; - line += bytes_read; - register_command(matcher, option, (ccstr) value); - return; + return register_command(matcher, option, errorbuf, buf_size, (ccstr) value); } else { jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str); + return false; } } else if (type == OptionType::Ccstrlist) { // Accumulates several strings into one. The internal type is ccstr. @@ -790,6 +800,7 @@ static void scan_value(enum OptionType type, char* line, int& total_bytes_read, if (!validator.is_valid()) { jio_snprintf(errorbuf, buf_size, "Unrecognized intrinsic detected in %s: %s", option2name(option), validator.what()); + return false; } } #if !defined(PRODUCT) && defined(COMPILER2) @@ -798,18 +809,21 @@ static void scan_value(enum OptionType type, char* line, int& total_bytes_read, if (!validator.is_valid()) { jio_snprintf(errorbuf, buf_size, "Unrecognized tag name in %s: %s", option2name(option), validator.what()); + return false; } } else if (option == CompileCommandEnum::TraceMergeStores) { TraceMergeStores::TagValidator validator(value, true); if (!validator.is_valid()) { jio_snprintf(errorbuf, buf_size, "Unrecognized tag name in %s: %s", option2name(option), validator.what()); + return false; } } else if (option == CompileCommandEnum::PrintIdealPhase) { PhaseNameValidator validator(value); if (!validator.is_valid()) { jio_snprintf(errorbuf, buf_size, "Unrecognized phase name in %s: %s", option2name(option), validator.what()); + return false; } } else if (option == CompileCommandEnum::TestOptionList) { // all values are ok @@ -819,35 +833,32 @@ static void scan_value(enum OptionType type, char* line, int& total_bytes_read, assert(false, "Ccstrlist type option missing validator"); } - register_command(matcher, option, (ccstr) value); - return; + return register_command(matcher, option, errorbuf, buf_size, (ccstr) value); } else { jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str); + return false; } } else if (type == OptionType::Bool) { char value[256]; if (*line == '\0') { // Short version of a CompileCommand sets a boolean Option to true // -XXCompileCommand=

        + +

        File URL stream protocol handler properties

        +

        The following properties are used to configure the handler for URLs with the {@code file://} scheme:

        +
          +
        • {@systemProperty jdk.net.file.ftpfallback} (default: <false>)
          + The {@code file://} handler by default rejects any non-local file URL (as defined by RFC 8089) + as invalid. Setting this property to true enables a legacy feature where + the handler instead opens an FTP connection for such non-local URLs.

          +

          Any modern code should use explicit {@code ftp://} URLs instead and not rely on + enabling this legacy FTP fallback feature.

          +

        Misc HTTP URL stream protocol handler properties

          @@ -192,9 +203,9 @@

          Misc HTTP URL stream protocol handler properties

          {@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 + 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 + 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}.

          @@ -238,7 +249,7 @@

          Misc HTTP URL stream protocol handler properties

          {@code SHA-1}. If it is still required to use one of these algorithms, then they can be re-enabled by setting this property to a comma separated list of the algorithm names.

        • {@systemProperty jdk.https.negotiate.cbt} (default: <never>)
          - This controls the generation and sending of TLS channel binding tokens (CBT) when Kerberos + 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:

            @@ -247,8 +258,8 @@

            Misc HTTP URL stream protocol handler properties

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

          2. "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 + 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 @@ -306,32 +317,32 @@

          Unix domain sockets

          For Unix domain sockets, this means a unique path in some predefined system temporary directory. There are a number of system (and networking) properties that affect this behavior.

          -Unix domain socket addresses are limited in length to approximately 100 +Unix domain socket addresses are limited in length to approximately 100 bytes (depending on the platform), it is important to ensure that the temporary directory's name together with the filename used for the socket (currently a name similar to {@code socket_1679697142}) does not exceed this limit. The following properties can be used to control the selection of this directory:

            -
          • {@systemProperty jdk.net.unixdomain.tmpdir} This can be set as - a networking property in {@code conf/net.properties} If set, this specifies the +

          • {@systemProperty jdk.net.unixdomain.tmpdir} This can be set as + a networking property in {@code conf/net.properties} If set, this specifies the directory to use for automatically bound server socket addresses. On some platforms, (eg some Unix systems) this will have a predefined default value. On others, (eg Windows) there is no default value. Either way, it is always possible to override the networking property with a system property of the same name set on the command line. If neither of the networking nor system property - are set, then some systems (eg Windows) may check a commonly used environment + are set, then some systems (eg Windows) may check a commonly used environment variable as temporary directory.

          • {@systemProperty java.io.tmpdir} If the previous step fails to locate a directory to use, then the directory identified by the system property {@code java.io.tmpdir} is used.

          -More information about the platform specific behavior can be seen in the +More information about the platform specific behavior can be seen in the {@code conf/net.properties} configuration file.

          Implicit binding of a {@link java.nio.channels.SocketChannel SocketChannel}

          If a client socket is connected to a remote destination without calling {@code bind} first, -then the socket is implicitly bound. In this case, Unix domain sockets +then the socket is implicitly bound. In this case, Unix domain sockets are unnamed (ie. their path is empty). This behavior is not affected by any system or networking properties.

          diff --git a/src/java.base/share/classes/java/nio/X-Buffer.java.template b/src/java.base/share/classes/java/nio/X-Buffer.java.template index d089155abf9..283f5534597 100644 --- a/src/java.base/share/classes/java/nio/X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/X-Buffer.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1896,6 +1896,44 @@ public abstract sealed class $Type$Buffer #if[char] + /** + * Absolute bulk get method. + * + *

          This method transfers {@code srcEnd-srcBegin} characters from this + * buffer into the given array, starting at index {@code srcBegin} in this + * buffer and at offset {@code dstBegin} in the array. The position of this + * buffer is unchanged. + * + * @param srcBegin + * The index in this buffer from which the first character will be + * read; must be non-negative and less than {@code limit()} + * + * @param srcEnd + * The index in this buffer directly before the last character to + * read; must be non-negative and less or equal than {@code limit()} + * and must be greater or equal than {@code srcBegin} + * + * @param dst + * The destination array + * + * @param dstBegin + * The offset within the array of the first character to be + * written; must be non-negative and less than {@code dst.length} + * + * @throws IndexOutOfBoundsException + * If the preconditions on the {@code srcBegin}, {@code srcEnd}, + * and {@code dstBegin} parameters do not hold + * + * @implSpec This method is equivalent to + * {@code get(srcBegin, dst, dstBegin, srcEnd - srcBegin)}. + * + * @since 25 + */ + @Override + public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) { + get(srcBegin, dst, dstBegin, srcEnd - srcBegin); + } + /** * Returns a string containing the characters in this buffer. * diff --git a/src/java.base/share/classes/java/nio/charset/Charset.java b/src/java.base/share/classes/java/nio/charset/Charset.java index 4766c907d55..b36e11cdc36 100644 --- a/src/java.base/share/classes/java/nio/charset/Charset.java +++ b/src/java.base/share/classes/java/nio/charset/Charset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -634,8 +634,8 @@ public static SortedMap availableCharsets() { * upon the locale and charset of the underlying operating system. * * @return A charset object for the default charset - * @see file.encoding - * @see native.encoding + * @see System##file.encoding file.encoding + * @see System##native.encoding native.encoding * * @since 1.5 */ diff --git a/src/java.base/share/classes/java/nio/file/FileSystems.java b/src/java.base/share/classes/java/nio/file/FileSystems.java index f60f798c6e2..fc4b80b0b2a 100644 --- a/src/java.base/share/classes/java/nio/file/FileSystems.java +++ b/src/java.base/share/classes/java/nio/file/FileSystems.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,8 +257,9 @@ public static FileSystem getFileSystem(URI uri) { * * @throws IllegalArgumentException * if the pre-conditions for the {@code uri} parameter are not met, - * or the {@code env} parameter does not contain properties required - * by the provider, or a property value is invalid + * or if the {@code env} parameter does not contain properties + * required by the provider, contains an invalid combination of + * properties and values, or contains an invalid property value * @throws FileSystemAlreadyExistsException * if the file system has already been created * @throws ProviderNotFoundException @@ -296,8 +297,9 @@ public static FileSystem newFileSystem(URI uri, Map env) * * @throws IllegalArgumentException * if the pre-conditions for the {@code uri} parameter are not met, - * or the {@code env} parameter does not contain properties required - * by the provider, or a property value is invalid + * or if the {@code env} parameter does not contain properties + * required by the provider, contains an invalid combination of + * properties and values, or contains an invalid property value * @throws FileSystemAlreadyExistsException * if the URI scheme identifies an installed provider and the file * system has already been created @@ -400,6 +402,10 @@ public static FileSystem newFileSystem(Path path, * * @return a new file system * + * @throws IllegalArgumentException + * if the {@code env} parameter does not contain properties + * required by the provider, contains an invalid combination of + * properties and values, or contains an invalid property value * @throws ProviderNotFoundException * if a provider supporting this file type cannot be located * @throws ServiceConfigurationError @@ -476,6 +482,10 @@ public static FileSystem newFileSystem(Path path) throws IOException { * * @return a new file system * + * @throws IllegalArgumentException + * if the {@code env} parameter does not contain properties + * required by the provider, contains an invalid combination of + * properties and values, or contains an invalid property value * @throws ProviderNotFoundException * if a provider supporting this file type cannot be located * @throws ServiceConfigurationError 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 2f83f79d4bd..f8278fa2642 100644 --- a/src/java.base/share/classes/java/nio/file/Files.java +++ b/src/java.base/share/classes/java/nio/file/Files.java @@ -3043,7 +3043,7 @@ public static String readString(Path path, Charset cs) throws IOException { byte[] ba = readAllBytes(path); if (path.getClass().getModule() != Object.class.getModule()) ba = ba.clone(); - return JLA.newStringNoRepl(ba, cs); + return JLA.uncheckedNewStringNoRepl(ba, cs); } /** @@ -3362,7 +3362,7 @@ public static Path writeString(Path path, CharSequence csq, Charset cs, OpenOpti Objects.requireNonNull(csq); Objects.requireNonNull(cs); - byte[] bytes = JLA.getBytesNoRepl(String.valueOf(csq), cs); + byte[] bytes = JLA.uncheckedGetBytesNoRepl(String.valueOf(csq), cs); if (path.getClass().getModule() != Object.class.getModule()) bytes = bytes.clone(); write(path, bytes, options); diff --git a/src/java.base/share/classes/java/nio/file/Path.java b/src/java.base/share/classes/java/nio/file/Path.java index 827dd56a6a4..330af173012 100644 --- a/src/java.base/share/classes/java/nio/file/Path.java +++ b/src/java.base/share/classes/java/nio/file/Path.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -749,7 +749,9 @@ default Path resolveSibling(String other) { /** * Returns a {@code Path} object representing the absolute path of this - * path. + * path. Where this {@code Path} is associated with the default provider, + * then the returned absolute path will have a non-{@code null} + * {@linkplain #getRoot root component}. * *

          If this path is already {@link Path#isAbsolute absolute} then this * method simply returns this path. Otherwise, this method resolves the path diff --git a/src/java.base/share/classes/java/security/AsymmetricKey.java b/src/java.base/share/classes/java/security/AsymmetricKey.java index e96aeb4d84c..d37afe9bfea 100644 --- a/src/java.base/share/classes/java/security/AsymmetricKey.java +++ b/src/java.base/share/classes/java/security/AsymmetricKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ * * @since 22 */ -public interface AsymmetricKey extends Key { +public non-sealed interface AsymmetricKey extends Key, DEREncodable { /** * Returns the parameters associated with this key. * The parameters are optional and may be either diff --git a/src/java.base/share/classes/java/security/DEREncodable.java b/src/java.base/share/classes/java/security/DEREncodable.java new file mode 100644 index 00000000000..63c6a73ee52 --- /dev/null +++ b/src/java.base/share/classes/java/security/DEREncodable.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.security; + +import jdk.internal.javac.PreviewFeature; + +import javax.crypto.EncryptedPrivateKeyInfo; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + * This interface is implemented by security API classes that contain + * binary-encodable key or certificate material. + * These APIs or their subclasses typically provide methods to convert + * their instances to and from byte arrays in the Distinguished + * Encoding Rules (DER) format. + * + * @see AsymmetricKey + * @see KeyPair + * @see PKCS8EncodedKeySpec + * @see X509EncodedKeySpec + * @see EncryptedPrivateKeyInfo + * @see X509Certificate + * @see X509CRL + * @see PEMRecord + * + * @since 25 + */ + +@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) +public sealed interface DEREncodable permits AsymmetricKey, KeyPair, + PKCS8EncodedKeySpec, X509EncodedKeySpec, EncryptedPrivateKeyInfo, + X509Certificate, X509CRL, PEMRecord { +} diff --git a/src/java.base/share/classes/java/security/KeyPair.java b/src/java.base/share/classes/java/security/KeyPair.java index cc648a677dd..39c98501fea 100644 --- a/src/java.base/share/classes/java/security/KeyPair.java +++ b/src/java.base/share/classes/java/security/KeyPair.java @@ -37,7 +37,7 @@ * @since 1.1 */ -public final class KeyPair implements java.io.Serializable { +public final class KeyPair implements java.io.Serializable, DEREncodable { @java.io.Serial private static final long serialVersionUID = -7565189502268009837L; diff --git a/src/java.base/share/classes/java/security/PEMDecoder.java b/src/java.base/share/classes/java/security/PEMDecoder.java new file mode 100644 index 00000000000..7279e75cc98 --- /dev/null +++ b/src/java.base/share/classes/java/security/PEMDecoder.java @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.security; + +import jdk.internal.javac.PreviewFeature; + +import sun.security.pkcs.PKCS8Key; +import sun.security.rsa.RSAPrivateCrtKeyImpl; +import sun.security.util.KeyUtil; +import sun.security.util.Pem; + +import javax.crypto.EncryptedPrivateKeyInfo; +import javax.crypto.spec.PBEKeySpec; +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.security.cert.*; +import java.security.spec.*; +import java.util.Base64; +import java.util.Objects; + +/** + * {@code PEMDecoder} implements a decoder for Privacy-Enhanced Mail (PEM) data. + * PEM is a textual encoding used to store and transfer security + * objects, such as asymmetric keys, certificates, and certificate revocation + * lists (CRLs). It is defined in RFC 1421 and RFC 7468. PEM consists of a + * Base64-formatted binary encoding enclosed by a type-identifying header + * and footer. + * + *

          The {@linkplain #decode(String)} and {@linkplain #decode(InputStream)} + * methods return an instance of a class that matches the data + * type and implements {@link DEREncodable}. + * + *

          The following lists the supported PEM types and the {@code DEREncodable} + * types that each are decoded as: + *

            + *
          • CERTIFICATE : {@code X509Certificate}
          • + *
          • X509 CRL : {@code X509CRL}
          • + *
          • PUBLIC KEY : {@code PublicKey}
          • + *
          • PUBLIC KEY : {@code X509EncodedKeySpec} (Only supported when passed as + * a {@code Class} parameter)
          • + *
          • PRIVATE KEY : {@code PrivateKey}
          • + *
          • PRIVATE KEY : {@code PKCS8EncodedKeySpec} (Only supported when passed + * as a {@code Class} parameter)
          • + *
          • PRIVATE KEY : {@code KeyPair} (if the encoding also contains a + * public key)
          • + *
          • ENCRYPTED PRIVATE KEY : {@code EncryptedPrivateKeyInfo}
          • + *
          • ENCRYPTED PRIVATE KEY : {@code PrivateKey} (if configured with + * Decryption)
          • + *
          • Other types : {@code PEMRecord}
          • + *
          + * + *

          The {@code PublicKey} and {@code PrivateKey} types, an algorithm specific + * subclass is returned if the underlying algorithm is supported. For example an + * ECPublicKey and ECPrivateKey for Elliptic Curve keys. + * + *

          If the PEM type does not have a corresponding class, + * {@code decode(String)} and {@code decode(InputStream)} will return a + * {@link PEMRecord}. + * + *

          The {@linkplain #decode(String, Class)} and + * {@linkplain #decode(InputStream, Class)} methods take a class parameter + * which determines the type of {@code DEREncodable} that is returned. These + * methods are useful when extracting or changing the return class. + * For example, if the PEM contains both public and private keys, the + * class parameter can specify which to return. Use + * {@code PrivateKey.class} to return only the private key. + * If the class parameter is set to {@code X509EncodedKeySpec.class}, the + * public key will be returned in that format. Any type of PEM data can be + * decoded into a {@code PEMRecord} by specifying {@code PEMRecord.class}. + * If the class parameter doesn't match the PEM content, a + * {@linkplain ClassCastException} will be thrown. + * + *

          A new {@code PEMDecoder} instance is created when configured + * with {@linkplain #withFactory(Provider)} and/or + * {@linkplain #withDecryption(char[])}. {@linkplain #withFactory(Provider)} + * configures the decoder to use only {@linkplain KeyFactory} and + * {@linkplain CertificateFactory} instances from the given {@code Provider}. + * {@linkplain #withDecryption(char[])} configures the decoder to decrypt all + * encrypted private key PEM data using the given password. + * Configuring an instance for decryption does not prevent decoding with + * unencrypted PEM. Any encrypted PEM that fails decryption + * will throw a {@link RuntimeException}. When an encrypted private key PEM is + * used with a decoder not configured for decryption, an + * {@link EncryptedPrivateKeyInfo} object is returned. + * + *

          This class is immutable and thread-safe. + * + *

          Here is an example of decoding a {@code PrivateKey} object: + * {@snippet lang = java: + * PEMDecoder pd = PEMDecoder.of(); + * PrivateKey priKey = pd.decode(priKeyPEM, PrivateKey.class); + * } + * + *

          Here is an example of a {@code PEMDecoder} configured with decryption + * and a factory provider: + * {@snippet lang = java: + * PEMDecoder pd = PEMDecoder.of().withDecryption(password). + * withFactory(provider); + * byte[] pemData = pd.decode(privKey); + * } + * + * @implNote An implementation may support other PEM types and + * {@code DEREncodable} objects. This implementation additionally supports + * the following PEM types: {@code X509 CERTIFICATE}, + * {@code X.509 CERTIFICATE}, {@code CRL}, and {@code RSA PRIVATE KEY}. + * + * @see PEMEncoder + * @see PEMRecord + * @see EncryptedPrivateKeyInfo + * + * @spec https://www.rfc-editor.org/info/rfc1421 + * RFC 1421: Privacy Enhancement for Internet Electronic Mail + * @spec https://www.rfc-editor.org/info/rfc7468 + * RFC 7468: Textual Encodings of PKIX, PKCS, and CMS Structures + * + * @since 25 + */ + +@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) +public final class PEMDecoder { + private final Provider factory; + private final PBEKeySpec password; + + // Singleton instance for PEMDecoder + private final static PEMDecoder PEM_DECODER = new PEMDecoder(null, null); + + /** + * Creates an instance with a specific KeyFactory and/or password. + * @param withFactory KeyFactory provider + * @param withPassword char[] password for EncryptedPrivateKeyInfo + * decryption + */ + private PEMDecoder(Provider withFactory, PBEKeySpec withPassword) { + password = withPassword; + factory = withFactory; + } + + /** + * Returns an instance of {@code PEMDecoder}. + * + * @return a {@code PEMDecoder} instance + */ + public static PEMDecoder of() { + return PEM_DECODER; + } + + /** + * After the header, footer, and base64 have been separated, identify the + * header and footer and proceed with decoding the base64 for the + * appropriate type. + */ + private DEREncodable decode(PEMRecord pem) { + Base64.Decoder decoder = Base64.getMimeDecoder(); + + try { + return switch (pem.type()) { + case Pem.PUBLIC_KEY -> { + X509EncodedKeySpec spec = + new X509EncodedKeySpec(decoder.decode(pem.content())); + yield getKeyFactory( + KeyUtil.getAlgorithm(spec.getEncoded())). + generatePublic(spec); + } + case Pem.PRIVATE_KEY -> { + PKCS8Key p8key = new PKCS8Key(decoder.decode(pem.content())); + String algo = p8key.getAlgorithm(); + KeyFactory kf = getKeyFactory(algo); + DEREncodable d = kf.generatePrivate( + new PKCS8EncodedKeySpec(p8key.getEncoded(), algo)); + + // Look for a public key inside the pkcs8 encoding. + if (p8key.getPubKeyEncoded() != null) { + // Check if this is a OneAsymmetricKey encoding + X509EncodedKeySpec spec = new X509EncodedKeySpec( + p8key.getPubKeyEncoded(), algo); + yield new KeyPair(getKeyFactory(algo). + generatePublic(spec), (PrivateKey) d); + + } else if (d instanceof PKCS8Key p8 && + p8.getPubKeyEncoded() != null) { + // If the KeyFactory decoded an algorithm-specific + // encodings, look for the public key again. This + // happens with EC and SEC1-v2 encoding + X509EncodedKeySpec spec = new X509EncodedKeySpec( + p8.getPubKeyEncoded(), algo); + yield new KeyPair(getKeyFactory(algo). + generatePublic(spec), p8); + } else { + // No public key, return the private key. + yield d; + } + } + case Pem.ENCRYPTED_PRIVATE_KEY -> { + if (password == null) { + yield new EncryptedPrivateKeyInfo(decoder.decode( + pem.content())); + } + yield new EncryptedPrivateKeyInfo(decoder.decode(pem.content())). + getKey(password.getPassword()); + } + case Pem.CERTIFICATE, Pem.X509_CERTIFICATE, + Pem.X_509_CERTIFICATE -> { + CertificateFactory cf = getCertFactory("X509"); + yield (X509Certificate) cf.generateCertificate( + new ByteArrayInputStream(decoder.decode(pem.content()))); + } + case Pem.X509_CRL, Pem.CRL -> { + CertificateFactory cf = getCertFactory("X509"); + yield (X509CRL) cf.generateCRL( + new ByteArrayInputStream(decoder.decode(pem.content()))); + } + case Pem.RSA_PRIVATE_KEY -> { + KeyFactory kf = getKeyFactory("RSA"); + yield kf.generatePrivate( + RSAPrivateCrtKeyImpl.getKeySpec(decoder.decode( + pem.content()))); + } + default -> pem; + }; + } catch (GeneralSecurityException | IOException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Decodes and returns a {@link DEREncodable} from the given {@code String}. + * + *

          This method reads the {@code String} until PEM data is found + * or the end of the {@code String} is reached. If no PEM data is found, + * an {@code IllegalArgumentException} is thrown. + * + *

          This method returns a Java API cryptographic object, + * such as a {@code PrivateKey}, if the PEM type is supported. + * Any non-PEM data preceding the PEM header is ignored by the decoder. + * Otherwise, a {@link PEMRecord} will be returned containing + * the type identifier and Base64-encoded data. + * Any non-PEM data preceding the PEM header will be stored in + * {@code leadingData}. + * + *

          Input consumed by this method is read in as + * {@link java.nio.charset.StandardCharsets#UTF_8 UTF-8}. + * + * @param str a String containing PEM data + * @return a {@code DEREncodable} + * @throws IllegalArgumentException on error in decoding or no PEM data + * found + * @throws NullPointerException when {@code str} is null + */ + public DEREncodable decode(String str) { + Objects.requireNonNull(str); + try { + return decode(new ByteArrayInputStream( + str.getBytes(StandardCharsets.UTF_8))); + } catch (IOException e) { + // With all data contained in the String, there are no IO ops. + throw new IllegalArgumentException(e); + } + } + + /** + * Decodes and returns a {@link DEREncodable} from the given + * {@code InputStream}. + * + *

          This method reads from the {@code InputStream} until the end of + * the PEM footer or the end of the stream. If an I/O error occurs, + * the read position in the stream may become inconsistent. + * It is recommended to perform no further decoding operations + * on the {@code InputStream}. + * + *

          This method returns a Java API cryptographic object, + * such as a {@code PrivateKey}, if the PEM type is supported. + * Any non-PEM data preceding the PEM header is ignored by the decoder. + * Otherwise, a {@link PEMRecord} will be returned containing + * the type identifier and Base64-encoded data. + * Any non-PEM data preceding the PEM header will be stored in + * {@code leadingData}. + * + *

          If no PEM data is found, an {@code IllegalArgumentException} is + * thrown. + * + * @param is InputStream containing PEM data + * @return a {@code DEREncodable} + * @throws IOException on IO or PEM syntax error where the + * {@code InputStream} did not complete decoding. + * @throws EOFException at the end of the {@code InputStream} + * @throws IllegalArgumentException on error in decoding + * @throws NullPointerException when {@code is} is null + */ + public DEREncodable decode(InputStream is) throws IOException { + Objects.requireNonNull(is); + PEMRecord pem = Pem.readPEM(is); + return decode(pem); + } + + /** + * Decodes and returns a {@code DEREncodable} of the specified class from + * the given PEM string. {@code tClass} must extend {@link DEREncodable} + * and be an appropriate class for the PEM type. + * + *

          This method reads the {@code String} until PEM data is found + * or the end of the {@code String} is reached. If no PEM data is found, + * an {@code IllegalArgumentException} is thrown. + * + *

          If the class parameter is {@code PEMRecord.class}, + * a {@linkplain PEMRecord} is returned containing the + * type identifier and Base64 encoding. Any non-PEM data preceding + * the PEM header will be stored in {@code leadingData}. Other + * class parameters will not return preceding non-PEM data. + * + *

          Input consumed by this method is read in as + * {@link java.nio.charset.StandardCharsets#UTF_8 UTF-8}. + * + * @param Class type parameter that extends {@code DEREncodable} + * @param str the String containing PEM data + * @param tClass the returned object class that implements + * {@code DEREncodable} + * @return a {@code DEREncodable} specified by {@code tClass} + * @throws IllegalArgumentException on error in decoding or no PEM data + * found + * @throws ClassCastException if {@code tClass} is invalid for the PEM type + * @throws NullPointerException when any input values are null + */ + public S decode(String str, Class tClass) { + Objects.requireNonNull(str); + try { + return decode(new ByteArrayInputStream( + str.getBytes(StandardCharsets.UTF_8)), tClass); + } catch (IOException e) { + // With all data contained in the String, there are no IO ops. + throw new IllegalArgumentException(e); + } + } + + /** + * Decodes and returns the specified class for the given + * {@link InputStream}. The class must extend {@link DEREncodable} and be + * an appropriate class for the PEM type. + * + *

          This method reads from the {@code InputStream} until the end of + * the PEM footer or the end of the stream. If an I/O error occurs, + * the read position in the stream may become inconsistent. + * It is recommended to perform no further decoding operations + * on the {@code InputStream}. + * + *

          If the class parameter is {@code PEMRecord.class}, + * a {@linkplain PEMRecord} is returned containing the + * type identifier and Base64 encoding. Any non-PEM data preceding + * the PEM header will be stored in {@code leadingData}. Other + * class parameters will not return preceding non-PEM data. + * + *

          If no PEM data is found, an {@code IllegalArgumentException} is + * thrown. + * + * @param Class type parameter that extends {@code DEREncodable}. + * @param is an InputStream containing PEM data + * @param tClass the returned object class that implements + * {@code DEREncodable}. + * @return a {@code DEREncodable} typecast to {@code tClass} + * @throws IOException on IO or PEM syntax error where the + * {@code InputStream} did not complete decoding. + * @throws EOFException at the end of the {@code InputStream} + * @throws IllegalArgumentException on error in decoding + * @throws ClassCastException if {@code tClass} is invalid for the PEM type + * @throws NullPointerException when any input values are null + * + * @see #decode(InputStream) + * @see #decode(String, Class) + */ + public S decode(InputStream is, Class tClass) + throws IOException { + Objects.requireNonNull(is); + Objects.requireNonNull(tClass); + PEMRecord pem = Pem.readPEM(is); + + if (tClass.isAssignableFrom(PEMRecord.class)) { + return tClass.cast(pem); + } + DEREncodable so = decode(pem); + + /* + * If the object is a KeyPair, check if the tClass is set to class + * specific to a private or public key. Because PKCS8v2 can be a + * KeyPair, it is possible for someone to assume all their PEM private + * keys are only PrivateKey and not KeyPair. + */ + if (so instanceof KeyPair kp) { + if ((PrivateKey.class).isAssignableFrom(tClass) || + (PKCS8EncodedKeySpec.class).isAssignableFrom(tClass)) { + so = kp.getPrivate(); + } + if ((PublicKey.class).isAssignableFrom(tClass) || + (X509EncodedKeySpec.class).isAssignableFrom(tClass)) { + so = kp.getPublic(); + } + } + + /* + * KeySpec use getKeySpec after the Key has been generated. Even though + * returning a binary encoding after the Base64 decoding is ok when the + * user wants PKCS8EncodedKeySpec, generating the key verifies the + * binary encoding and allows the KeyFactory to use the provider's + * KeySpec() + */ + + if ((EncodedKeySpec.class).isAssignableFrom(tClass) && + so instanceof Key key) { + try { + // unchecked suppressed as we know tClass comes from KeySpec + // KeyType not relevant here. We just want KeyFactory + if ((PKCS8EncodedKeySpec.class).isAssignableFrom(tClass)) { + so = getKeyFactory(key.getAlgorithm()). + getKeySpec(key, PKCS8EncodedKeySpec.class); + } else if ((X509EncodedKeySpec.class).isAssignableFrom(tClass)) { + so = getKeyFactory(key.getAlgorithm()) + .getKeySpec(key, X509EncodedKeySpec.class); + } else { + throw new IllegalArgumentException("Invalid KeySpec."); + } + } catch (InvalidKeySpecException e) { + throw new IllegalArgumentException("Invalid KeySpec " + + "specified (" + tClass.getName() +") for key (" + + key.getClass().getName() +")", e); + } + } + + return tClass.cast(so); + } + + private KeyFactory getKeyFactory(String algorithm) { + if (algorithm == null || algorithm.isEmpty()) { + throw new IllegalArgumentException("No algorithm found in " + + "the encoding"); + } + try { + if (factory == null) { + return KeyFactory.getInstance(algorithm); + } + return KeyFactory.getInstance(algorithm, factory); + } catch (GeneralSecurityException e) { + throw new IllegalArgumentException(e); + } + } + + // Convenience method to avoid provider getInstance checks clutter + private CertificateFactory getCertFactory(String algorithm) { + try { + if (factory == null) { + return CertificateFactory.getInstance(algorithm); + } + return CertificateFactory.getInstance(algorithm, factory); + } catch (GeneralSecurityException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Returns a copy of this {@code PEMDecoder} instance that uses + * {@link KeyFactory} and {@link CertificateFactory} implementations + * from the specified {@link Provider} to produce cryptographic objects. + * Any errors using the {@code Provider} will occur during decoding. + * + * @param provider the factory provider + * @return a new PEMEncoder instance configured to the {@code Provider}. + * @throws NullPointerException if {@code provider} is null + */ + public PEMDecoder withFactory(Provider provider) { + Objects.requireNonNull(provider); + return new PEMDecoder(provider, password); + } + + /** + * Returns a copy of this {@code PEMDecoder} that decodes and decrypts + * encrypted private keys using the specified password. + * Non-encrypted PEM can still be decoded from this instance. + * + * @param password the password to decrypt encrypted PEM data. This array + * is cloned and stored in the new instance. + * @return a new PEMEncoder instance configured for decryption + * @throws NullPointerException if {@code password} is null + */ + public PEMDecoder withDecryption(char[] password) { + Objects.requireNonNull(password); + return new PEMDecoder(factory, new PBEKeySpec(password)); + } +} diff --git a/src/java.base/share/classes/java/security/PEMEncoder.java b/src/java.base/share/classes/java/security/PEMEncoder.java new file mode 100644 index 00000000000..95fcffe967b --- /dev/null +++ b/src/java.base/share/classes/java/security/PEMEncoder.java @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.security; + +import jdk.internal.javac.PreviewFeature; +import sun.security.pkcs.PKCS8Key; +import sun.security.util.DerOutputStream; +import sun.security.util.DerValue; +import sun.security.util.Pem; +import sun.security.x509.AlgorithmId; + +import javax.crypto.*; +import javax.crypto.spec.PBEKeySpec; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.cert.*; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Objects; +import java.util.concurrent.locks.ReentrantLock; + +/** + * {@code PEMEncoder} implements an encoder for Privacy-Enhanced Mail (PEM) + * data. PEM is a textual encoding used to store and transfer security + * objects, such as asymmetric keys, certificates, and certificate revocation + * lists (CRL). It is defined in RFC 1421 and RFC 7468. PEM consists of a + * Base64-formatted binary encoding enclosed by a type-identifying header + * and footer. + * + *

          Encoding may be performed on Java API cryptographic objects that + * implement {@link DEREncodable}. The {@link #encode(DEREncodable)} + * and {@link #encodeToString(DEREncodable)} methods encode a DEREncodable + * into PEM and return the data in a byte array or String. + * + *

          Private keys can be encrypted and encoded by configuring a + * {@code PEMEncoder} with the {@linkplain #withEncryption(char[])} method, + * which takes a password and returns a new {@code PEMEncoder} instance + * configured to encrypt the key with that password. Alternatively, a + * private key encrypted as an {@code EncryptedKeyInfo} object can be encoded + * directly to PEM by passing it to the {@code encode} or + * {@code encodeToString} methods. + * + *

          PKCS #8 2.0 defines the ASN.1 OneAsymmetricKey structure, which may + * contain both private and public keys. + * {@link KeyPair} objects passed to the {@code encode} or + * {@code encodeToString} methods are encoded as a + * OneAsymmetricKey structure using the "PRIVATE KEY" type. + * + *

          When encoding a {@link PEMRecord}, the API surrounds the + * {@linkplain PEMRecord#content()} with the PEM header and footer + * from {@linkplain PEMRecord#type()}. {@linkplain PEMRecord#leadingData()} is + * not included in the encoding. {@code PEMRecord} will not perform + * validity checks on the data. + * + *

          The following lists the supported {@code DEREncodable} classes and + * the PEM types that each are encoded as: + * + *

            + *
          • {@code X509Certificate} : CERTIFICATE
          • + *
          • {@code X509CRL} : X509 CRL
          • + *
          • {@code PublicKey}: PUBLIC KEY
          • + *
          • {@code PrivateKey} : PRIVATE KEY
          • + *
          • {@code PrivateKey} (if configured with encryption): + * ENCRYPTED PRIVATE KEY
          • + *
          • {@code EncryptedPrivateKeyInfo} : ENCRYPTED PRIVATE KEY
          • + *
          • {@code KeyPair} : PRIVATE KEY
          • + *
          • {@code X509EncodedKeySpec} : PUBLIC KEY
          • + *
          • {@code PKCS8EncodedKeySpec} : PRIVATE KEY
          • + *
          • {@code PEMRecord} : {@code PEMRecord.type()}
          • + *
          + * + *

          This class is immutable and thread-safe. + * + *

          Here is an example of encoding a {@code PrivateKey} object: + * {@snippet lang = java: + * PEMEncoder pe = PEMEncoder.of(); + * byte[] pemData = pe.encode(privKey); + * } + * + *

          Here is an example that encrypts and encodes a private key using the + * specified password: + * {@snippet lang = java: + * PEMEncoder pe = PEMEncoder.of().withEncryption(password); + * byte[] pemData = pe.encode(privKey); + * } + * + * @implNote An implementation may support other PEM types and + * {@code DEREncodable} objects. + * + * + * @see PEMDecoder + * @see PEMRecord + * @see EncryptedPrivateKeyInfo + * + * @spec https://www.rfc-editor.org/info/rfc1421 + * RFC 1421: Privacy Enhancement for Internet Electronic Mail + * @spec https://www.rfc-editor.org/info/rfc7468 + * RFC 7468: Textual Encodings of PKIX, PKCS, and CMS Structures + * + * @since 25 + */ +@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) +public final class PEMEncoder { + + // Singleton instance of PEMEncoder + private static final PEMEncoder PEM_ENCODER = new PEMEncoder(null); + + // Stores the password for an encrypted encoder that isn't setup yet. + private PBEKeySpec keySpec; + // Stores the key after the encoder is ready to encrypt. The prevents + // repeated SecretKeyFactory calls if the encoder is used on multiple keys. + private SecretKey key; + // Makes SecretKeyFactory generation thread-safe. + private final ReentrantLock lock; + + /** + * Instantiate a {@code PEMEncoder} for Encrypted Private Keys. + * + * @param pbe contains the password spec used for encryption. + */ + private PEMEncoder(PBEKeySpec pbe) { + keySpec = pbe; + key = null; + lock = new ReentrantLock(); + } + + /** + * Returns an instance of {@code PEMEncoder}. + * + * @return a {@code PEMEncoder} + */ + public static PEMEncoder of() { + return PEM_ENCODER; + } + + /** + * Encodes the specified {@code DEREncodable} and returns a PEM encoded + * string. + * + * @param de the {@code DEREncodable} to be encoded + * @return a {@code String} containing the PEM encoded data + * @throws IllegalArgumentException if the {@code DEREncodable} cannot be + * encoded + * @throws NullPointerException if {@code de} is {@code null} + * @see #withEncryption(char[]) + */ + public String encodeToString(DEREncodable de) { + Objects.requireNonNull(de); + return switch (de) { + case PublicKey pu -> buildKey(null, pu.getEncoded()); + case PrivateKey pr -> buildKey(pr.getEncoded(), null); + case KeyPair kp -> { + if (kp.getPublic() == null) { + throw new IllegalArgumentException("KeyPair does not " + + "contain PublicKey."); + } + if (kp.getPrivate() == null) { + throw new IllegalArgumentException("KeyPair does not " + + "contain PrivateKey."); + } + yield buildKey(kp.getPrivate().getEncoded(), + kp.getPublic().getEncoded()); + } + case X509EncodedKeySpec x -> + buildKey(null, x.getEncoded()); + case PKCS8EncodedKeySpec p -> + buildKey(p.getEncoded(), null); + case EncryptedPrivateKeyInfo epki -> { + try { + yield Pem.pemEncoded(Pem.ENCRYPTED_PRIVATE_KEY, + epki.getEncoded()); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + case X509Certificate c -> { + try { + if (isEncrypted()) { + throw new IllegalArgumentException("Certificates " + + "cannot be encrypted"); + } + yield Pem.pemEncoded(Pem.CERTIFICATE, c.getEncoded()); + } catch (CertificateEncodingException e) { + throw new IllegalArgumentException(e); + } + } + case X509CRL crl -> { + try { + if (isEncrypted()) { + throw new IllegalArgumentException("CRLs cannot be " + + "encrypted"); + } + yield Pem.pemEncoded(Pem.X509_CRL, crl.getEncoded()); + } catch (CRLException e) { + throw new IllegalArgumentException(e); + } + } + case PEMRecord rec -> { + if (isEncrypted()) { + throw new IllegalArgumentException("PEMRecord cannot be " + + "encrypted"); + } + yield Pem.pemEncoded(rec); + } + + default -> throw new IllegalArgumentException("PEM does not " + + "support " + de.getClass().getCanonicalName()); + }; + } + + /** + * Encodes the specified {@code DEREncodable} and returns the PEM encoding + * in a byte array. + * + * @param de the {@code DEREncodable} to be encoded + * @return a PEM encoded byte array + * @throws IllegalArgumentException if the {@code DEREncodable} cannot be + * encoded + * @throws NullPointerException if {@code de} is {@code null} + * @see #withEncryption(char[]) + */ + public byte[] encode(DEREncodable de) { + return encodeToString(de).getBytes(StandardCharsets.ISO_8859_1); + } + + /** + * Returns a new {@code PEMEncoder} instance configured for encryption + * with the default algorithm and a given password. + * + *

          Only {@link PrivateKey} objects can be encrypted with this newly + * configured instance. Encoding other {@link DEREncodable} objects will + * throw an {@code IllegalArgumentException}. + * + * @implNote + * The default password-based encryption algorithm is defined + * by the {@code jdk.epkcs8.defaultAlgorithm} security property and + * uses the default encryption parameters of the provider that is selected. + * For greater flexibility with encryption options and parameters, use + * {@link EncryptedPrivateKeyInfo#encryptKey(PrivateKey, Key, + * String, AlgorithmParameterSpec, Provider, SecureRandom)} and use the + * returned object with {@link #encode(DEREncodable)}. + * + * @param password the encryption password. The array is cloned and + * stored in the new instance. + * @return a new {@code PEMEncoder} instance configured for encryption + * @throws NullPointerException when password is {@code null} + */ + public PEMEncoder withEncryption(char[] password) { + // PBEKeySpec clones the password + Objects.requireNonNull(password, "password cannot be null."); + return new PEMEncoder(new PBEKeySpec(password)); + } + + /** + * Build PEM encoding. + */ + private String buildKey(byte[] privateBytes, byte[] publicBytes) { + DerOutputStream out = new DerOutputStream(); + Cipher cipher; + + if (privateBytes == null && publicBytes == null) { + throw new IllegalArgumentException("No encoded data given by the " + + "DEREncodable."); + } + + // If `keySpec` is non-null, then `key` hasn't been established. + // Setting a `key` prevents repeated key generation operations. + // withEncryption() is a configuration method and cannot throw an + // exception; therefore generation is delayed. + if (keySpec != null) { + // For thread safety + lock.lock(); + if (key == null) { + try { + key = SecretKeyFactory.getInstance(Pem.DEFAULT_ALGO). + generateSecret(keySpec); + keySpec.clearPassword(); + keySpec = null; + } catch (GeneralSecurityException e) { + throw new IllegalArgumentException("Security property " + + "\"jdk.epkcs8.defaultAlgorithm\" may not specify a " + + "valid algorithm. Operation cannot be performed.", e); + } finally { + lock.unlock(); + } + } else { + lock.unlock(); + } + } + + // If `key` is non-null, this is an encoder ready to encrypt. + if (key != null) { + if (privateBytes == null || publicBytes != null) { + throw new IllegalArgumentException("Can only encrypt a " + + "PrivateKey."); + } + + try { + cipher = Cipher.getInstance(Pem.DEFAULT_ALGO); + cipher.init(Cipher.ENCRYPT_MODE, key); + } catch (GeneralSecurityException e) { + throw new IllegalArgumentException("Security property " + + "\"jdk.epkcs8.defaultAlgorithm\" may not specify a " + + "valid algorithm. Operation cannot be performed.", e); + } + + try { + new AlgorithmId(Pem.getPBEID(Pem.DEFAULT_ALGO), + cipher.getParameters()).encode(out); + out.putOctetString(cipher.doFinal(privateBytes)); + return Pem.pemEncoded(Pem.ENCRYPTED_PRIVATE_KEY, + DerValue.wrap(DerValue.tag_Sequence, out).toByteArray()); + } catch (GeneralSecurityException e) { + throw new IllegalArgumentException(e); + } + } + + // X509 only + if (publicBytes != null && privateBytes == null) { + if (publicBytes.length == 0) { + throw new IllegalArgumentException("No public key encoding " + + "given by the DEREncodable."); + } + + return Pem.pemEncoded(Pem.PUBLIC_KEY, publicBytes); + } + + // PKCS8 only + if (publicBytes == null && privateBytes != null) { + if (privateBytes.length == 0) { + throw new IllegalArgumentException("No private key encoding " + + "given by the DEREncodable."); + } + + return Pem.pemEncoded(Pem.PRIVATE_KEY, privateBytes); + } + + // OneAsymmetricKey + if (privateBytes.length == 0) { + throw new IllegalArgumentException("No private key encoding " + + "given by the DEREncodable."); + } + + if (publicBytes.length == 0) { + throw new IllegalArgumentException("No public key encoding " + + "given by the DEREncodable."); + } + try { + return Pem.pemEncoded(Pem.PRIVATE_KEY, + PKCS8Key.getEncoded(publicBytes, privateBytes)); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } + + private boolean isEncrypted() { + return (key != null || keySpec != null); + } +} diff --git a/src/java.base/share/classes/java/security/PEMRecord.java b/src/java.base/share/classes/java/security/PEMRecord.java new file mode 100644 index 00000000000..2ce567f9fde --- /dev/null +++ b/src/java.base/share/classes/java/security/PEMRecord.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.security; + +import jdk.internal.javac.PreviewFeature; + +import sun.security.util.Pem; + +import java.util.Objects; + +/** + * {@code PEMRecord} is a {@link DEREncodable} that represents Privacy-Enhanced + * Mail (PEM) data by its type and Base64 form. {@link PEMDecoder} and + * {@link PEMEncoder} use {@code PEMRecord} when representing the data as a + * cryptographic object is not desired or the type has no + * {@code DEREncodable}. + * + *

          {@code type} and {@code content} may not be {@code null}. + * {@code leadingData} may be null if no non-PEM data preceded PEM header + * during decoding. {@code leadingData} may be useful for reading metadata + * that accompanies PEM data. + * + *

          No validation is performed during instantiation to ensure that + * {@code type} conforms to {@code RFC 7468}, that {@code content} is valid + * Base64, or that {@code content} matches the {@code type}. + * {@code leadingData} is not defensively copied and does not return a + * clone when {@linkplain #leadingData()} is called. + * + * @param type the type identifier in the PEM header without PEM syntax labels. + * For a public key, {@code type} would be "PUBLIC KEY". + * @param content the Base64-encoded data, excluding the PEM header and footer + * @param leadingData any non-PEM data preceding the PEM header when decoding. + * + * @spec https://www.rfc-editor.org/info/rfc7468 + * RFC 7468: Textual Encodings of PKIX, PKCS, and CMS Structures + * + * @see PEMDecoder + * @see PEMEncoder + * + * @since 25 + */ +@PreviewFeature(feature = PreviewFeature.Feature.PEM_API) +public record PEMRecord(String type, String content, byte[] leadingData) + implements DEREncodable { + + /** + * Creates a {@code PEMRecord} instance with the given parameters. + * + * @param type the type identifier + * @param content the Base64-encoded data, excluding the PEM header and + * footer + * @param leadingData any non-PEM data read during the decoding process + * before the PEM header. This value maybe {@code null}. + * @throws IllegalArgumentException if {@code type} is incorrectly + * formatted. + * @throws NullPointerException if {@code type} and/or {@code content} are + * {@code null}. + */ + public PEMRecord { + Objects.requireNonNull(type, "\"type\" cannot be null."); + Objects.requireNonNull(content, "\"content\" cannot be null."); + + // With no validity checking on `type`, the constructor accept anything + // including lowercase. The onus is on the caller. + if (type.startsWith("-") || type.startsWith("BEGIN ") || + type.startsWith("END ")) { + throw new IllegalArgumentException("PEM syntax labels found. " + + "Only the PEM type identifier is allowed"); + } + + } + + /** + * Creates a {@code PEMRecord} instance with a given {@code type} and + * {@code content} data in String form. {@code leadingData} is set to null. + * + * @param type the PEM type identifier + * @param content the Base64-encoded data, excluding the PEM header and + * footer + * @throws IllegalArgumentException if {@code type} is incorrectly + * formatted. + * @throws NullPointerException if {@code type} and/or {@code content} are + * {@code null}. + */ + public PEMRecord(String type, String content) { + this(type, content, null); + } + + /** + * Returns the type and Base64 encoding in PEM format. {@code leadingData} + * is not returned by this method. + */ + @Override + public String toString() { + return Pem.pemEncoded(this); + } +} diff --git a/src/java.base/share/classes/java/security/SecureClassLoader.java b/src/java.base/share/classes/java/security/SecureClassLoader.java index 8a6ba76e211..b398d7332d7 100644 --- a/src/java.base/share/classes/java/security/SecureClassLoader.java +++ b/src/java.base/share/classes/java/security/SecureClassLoader.java @@ -64,15 +64,22 @@ public class SecureClassLoader extends ClassLoader { * Creates a new {@code SecureClassLoader} using the specified parent * class loader for delegation. * - * @param parent the parent ClassLoader + * @apiNote If {@code parent} is specified as {@code null} (for the + * bootstrap class loader) then there is no guarantee that all platform + * classes are visible. + * See {@linkplain ClassLoader##builtinLoaders Run-time Built-in Class Loaders} + * for information on the bootstrap class loader and other built-in class loaders. + * + * @param parent the parent ClassLoader, can be {@code null} for the bootstrap + * class loader */ protected SecureClassLoader(ClassLoader parent) { super(parent); } /** - * Creates a new {@code SecureClassLoader} using the default parent class - * loader for delegation. + * Creates a new {@code SecureClassLoader} using the + * {@linkplain ClassLoader#getSystemClassLoader() system class loader as the parent}. */ protected SecureClassLoader() { super(); @@ -82,8 +89,15 @@ protected SecureClassLoader() { * Creates a new {@code SecureClassLoader} of the specified name and * using the specified parent class loader for delegation. * + * @apiNote If {@code parent} is specified as {@code null} (for the + * bootstrap class loader) then there is no guarantee that all platform + * classes are visible. + * See {@linkplain ClassLoader##builtinLoaders Run-time Built-in Class Loaders} + * for information on the bootstrap class loader and other built-in class loaders. + * * @param name class loader name; or {@code null} if not named - * @param parent the parent class loader + * @param parent the parent class loader, can be {@code null} for the bootstrap + * class loader * * @throws IllegalArgumentException if the given name is empty. * diff --git a/src/java.base/share/classes/java/security/cert/X509CRL.java b/src/java.base/share/classes/java/security/cert/X509CRL.java index 111de1daf0e..d19618f81ed 100644 --- a/src/java.base/share/classes/java/security/cert/X509CRL.java +++ b/src/java.base/share/classes/java/security/cert/X509CRL.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,7 +107,7 @@ * @see X509Extension */ -public abstract class X509CRL extends CRL implements X509Extension { +public abstract non-sealed class X509CRL extends CRL implements X509Extension, DEREncodable { private transient X500Principal issuerPrincipal; 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 4e579a75b1c..fe4a472dead 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,8 +107,8 @@ * @see X509Extension */ -public abstract class X509Certificate extends Certificate -implements X509Extension { +public abstract non-sealed class X509Certificate extends Certificate + implements X509Extension, DEREncodable { @java.io.Serial private static final long serialVersionUID = -2491127588187038216L; diff --git a/src/java.base/share/classes/java/security/doc-files/debug-system-property.html b/src/java.base/share/classes/java/security/doc-files/debug-system-property.html new file mode 100644 index 00000000000..ac325b2ef62 --- /dev/null +++ b/src/java.base/share/classes/java/security/doc-files/debug-system-property.html @@ -0,0 +1,179 @@ + + + + + + The java.security.debug system property + + + +

          {@systemProperty java.security.debug}

          +

          To monitor security access, you can set the java.security.debug + system property, which determines what trace messages are printed during + execution. The value of the property is one or more options separated by a + comma. Each trace message includes the thread id, caller information, and + timestamp. +

          + +

          The following table lists the java.security.debug options:

          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          Security Debug Options
          OptionDescription
          allTurn on all the debugging options
          certpathTurns on debugging for the PKIX CertPathValidator and + CertPathBuilder implementations. The following sub-options + can be used with the certpath option: +
            +
          • ocsp: Dump OCSP protocol exchanges
          • +
          • verbose: A hexadecimal dump of the OCSP + request and response bytes is displayed.
          • +
          +
          configfileJAAS (Java Authentication and Authorization Service) configuration file loading
          configparserJAAS configuration file parsing
          gssloginconfigJava GSS (Generic Security Services) login configuration file debugging
          jarJAR file verification
          jcaJCA engine class debugging
          KeyStoreKeyStore debugging
          logincontextLoginContext results
          pcscJava Smart Card I/O and SunPCSC provider debugging
          pkcs11PKCS11 session manager debugging
          pkcs11keystorePKCS11 KeyStore debugging
          pkcs12PKCS12 KeyStore debugging
          propertiesjava.security configuration file debugging
          providerSecurity provider debugging. The following sub-option can be used + with the provider option: engine=(engines) + : The output is displayed only for a specified list of one or more JCA + engines, separated by a comma. The supported values for (engines) are: +
            +
          • Cipher
          • +
          • KDF
          • +
          • KeyAgreement
          • +
          • KeyGenerator
          • +
          • KeyPairGenerator
          • +
          • KeyStore
          • +
          • Mac
          • +
          • MessageDigest
          • +
          • SecureRandom
          • +
          • Signature
          • +
          +
          securerandomSecureRandom debugging
          sunpkcs11SunPKCS11 provider debugging
          tsTimestamping debugging
          x509X.509 certificate debugging. The following sub-option can be used + with the X.509 option. +
            +
          • ava: Embed non-printable/non-escaped + characters in AVA components as hex strings
          • +
          +
          + + diff --git a/src/java.base/share/classes/java/security/package-info.java b/src/java.base/share/classes/java/security/package-info.java index b887d5c17a3..fafdca73801 100644 --- a/src/java.base/share/classes/java/security/package-info.java +++ b/src/java.base/share/classes/java/security/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,6 +71,12 @@ * *
        * + *

        Additional Specification

        + * + * * @spec security/standard-names.html Java Security Standard Algorithm Names * @since 1.1 */ diff --git a/src/java.base/share/classes/java/security/spec/PKCS8EncodedKeySpec.java b/src/java.base/share/classes/java/security/spec/PKCS8EncodedKeySpec.java index af7f135d7c4..917b15e06b6 100644 --- a/src/java.base/share/classes/java/security/spec/PKCS8EncodedKeySpec.java +++ b/src/java.base/share/classes/java/security/spec/PKCS8EncodedKeySpec.java @@ -25,25 +25,35 @@ package java.security.spec; +import java.security.DEREncodable; + /** * This class represents the ASN.1 encoding of a private key, - * encoded according to the ASN.1 type {@code PrivateKeyInfo}. - * The {@code PrivateKeyInfo} syntax is defined in the PKCS#8 standard + * encoded according to the ASN.1 type {@code OneAsymmetricKey}. + * The {@code OneAsymmetricKey} syntax is defined in the PKCS#8 standard * as follows: * *
        - * PrivateKeyInfo ::= SEQUENCE {
        + * OneAsymmetricKey ::= SEQUENCE {
          *   version Version,
          *   privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
          *   privateKey PrivateKey,
        - *   attributes [0] IMPLICIT Attributes OPTIONAL }
        + *   attributes       [0] Attributes OPTIONAL,
        + *   ...,
        + *   [[2: publicKey  [1] PublicKey OPTIONAL ]],
        + *   ...
        + * }
        + *
        + * PrivateKeyInfo ::= OneAsymmetricKey
          *
        - * Version ::= INTEGER
        + * Version ::= INTEGER { v1(0), v2(1) }
          *
          * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
          *
          * PrivateKey ::= OCTET STRING
          *
        + * PublicKey ::= BIT STRING
        + *
          * Attributes ::= SET OF Attribute
          * 
        * @@ -56,11 +66,14 @@ * @see EncodedKeySpec * @see X509EncodedKeySpec * + * @spec https://www.rfc-editor.org/info/rfc5958 + * RFC 5958: Asymmetric Key Packages + * * @since 1.2 */ -public class PKCS8EncodedKeySpec extends EncodedKeySpec { - +public non-sealed class PKCS8EncodedKeySpec extends EncodedKeySpec implements + DEREncodable { /** * Creates a new {@code PKCS8EncodedKeySpec} with the given encoded key. * diff --git a/src/java.base/share/classes/java/security/spec/X509EncodedKeySpec.java b/src/java.base/share/classes/java/security/spec/X509EncodedKeySpec.java index a405104cd07..e8b6e599676 100644 --- a/src/java.base/share/classes/java/security/spec/X509EncodedKeySpec.java +++ b/src/java.base/share/classes/java/security/spec/X509EncodedKeySpec.java @@ -25,6 +25,8 @@ package java.security.spec; +import java.security.DEREncodable; + /** * This class represents the ASN.1 encoding of a public key, * encoded according to the ASN.1 type {@code SubjectPublicKeyInfo}. @@ -49,8 +51,8 @@ * @since 1.2 */ -public class X509EncodedKeySpec extends EncodedKeySpec { - +public non-sealed class X509EncodedKeySpec extends EncodedKeySpec implements + DEREncodable { /** * Creates a new {@code X509EncodedKeySpec} with the given encoded key. * diff --git a/src/java.base/share/classes/java/text/Collator.java b/src/java.base/share/classes/java/text/Collator.java index 78fb7c654b6..7f6db310366 100644 --- a/src/java.base/share/classes/java/text/Collator.java +++ b/src/java.base/share/classes/java/text/Collator.java @@ -138,7 +138,7 @@ public abstract class Collator * Collator strength value. When set, only SECONDARY and above differences are * considered significant during comparison. The assignment of strengths * to language features is locale dependent. A common example is for - * different accented forms of the same base letter ("a" vs "\u00E4") to be + * different accented forms of the same base letter ("a" vs "ä" (U+00E9)) to be * considered a SECONDARY difference. * @see java.text.Collator#setStrength * @see java.text.Collator#getStrength diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index 35464d6ec91..fae11cbdba1 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2169,14 +2169,10 @@ private void readObject(ObjectInputStream inStream) throws IOException, } /** - * Sets the maximum number of digits allowed in the integer portion of a - * number. - * The maximum allowed integer range is 309, if the {@code newValue} > 309, - * then the maximum integer digits count is set to 309. Negative input - * values are replaced with 0. - * - * @param newValue the maximum number of integer digits to be shown - * @see #getMaximumIntegerDigits() + * {@inheritDoc NumberFormat} + *

        The maximum allowed integer range is 309, if the {@code newValue} > + * 309, then the maximum integer digits count is set to 309. + * @param newValue the maximum number of integer digits to be shown. */ @Override public void setMaximumIntegerDigits(int newValue) { @@ -2194,14 +2190,10 @@ public void setMaximumIntegerDigits(int newValue) { } /** - * Sets the minimum number of digits allowed in the integer portion of a - * number. - * The maximum allowed integer range is 309, if the {@code newValue} > 309, - * then the minimum integer digits count is set to 309. Negative input - * values are replaced with 0. - * - * @param newValue the minimum number of integer digits to be shown - * @see #getMinimumIntegerDigits() + * {@inheritDoc NumberFormat} + *

        The maximum allowed integer range is 309, if the {@code newValue} > + * 309, then the minimum integer digits count is set to 309. + * @param newValue the minimum number of integer digits to be shown. */ @Override public void setMinimumIntegerDigits(int newValue) { @@ -2219,14 +2211,10 @@ public void setMinimumIntegerDigits(int newValue) { } /** - * Sets the minimum number of digits allowed in the fraction portion of a - * number. - * The maximum allowed fraction range is 340, if the {@code newValue} > 340, - * then the minimum fraction digits count is set to 340. Negative input - * values are replaced with 0. - * - * @param newValue the minimum number of fraction digits to be shown - * @see #getMinimumFractionDigits() + * {@inheritDoc NumberFormat} + *

        The maximum allowed fraction range is 340, if the {@code newValue} > + * 340, then the minimum fraction digits count is set to 340. + * @param newValue the minimum number of fraction digits to be shown. */ @Override public void setMinimumFractionDigits(int newValue) { @@ -2245,14 +2233,10 @@ public void setMinimumFractionDigits(int newValue) { } /** - * Sets the maximum number of digits allowed in the fraction portion of a - * number. - * The maximum allowed fraction range is 340, if the {@code newValue} > 340, - * then the maximum fraction digits count is set to 340. Negative input - * values are replaced with 0. - * - * @param newValue the maximum number of fraction digits to be shown - * @see #getMaximumFractionDigits() + * {@inheritDoc NumberFormat} + *

        The maximum allowed fraction range is 340, if the {@code newValue} > + * 340, then the maximum fraction digits count is set to 340. + * @param newValue the maximum number of fraction digits to be shown. */ @Override public void setMaximumFractionDigits(int newValue) { diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index ce2ecfb23a2..3aa42ed8601 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -110,6 +110,10 @@ * defined by {@link Character#digit Character.digit}, are recognized. * *

        Integer and Fraction Digit Limits

        + * The integer and fraction digit limits are set by either applying a {@link ##patterns + * pattern} or using one of the appropriate {@code DecimalFormat} setter methods, + * for example, {@link #setMinimumFractionDigits(int)}. These limits have no impact + * on parsing behavior. * @implSpec * When formatting a {@code Number} other than {@code BigInteger} and * {@code BigDecimal}, {@code 309} is used as the upper limit for integer digits, @@ -3972,9 +3976,9 @@ else if (ch == percent) { } /** - * Sets the maximum number of digits allowed in the integer portion of a - * number. Negative input values are replaced with 0. - * @see NumberFormat#setMaximumIntegerDigits + * {@inheritDoc NumberFormat} + * @param newValue the maximum number of integer digits to be shown. + * @see #getMaximumIntegerDigits() * @see ##digit_limits Integer and Fraction Digit Limits */ @Override @@ -3989,9 +3993,9 @@ public void setMaximumIntegerDigits(int newValue) { } /** - * Sets the minimum number of digits allowed in the integer portion of a - * number. Negative input values are replaced with 0. - * @see NumberFormat#setMinimumIntegerDigits + * {@inheritDoc NumberFormat} + * @param newValue the minimum number of integer digits to be shown. + * @see #getMinimumIntegerDigits() * @see ##digit_limits Integer and Fraction Digit Limits */ @Override @@ -4006,9 +4010,9 @@ public void setMinimumIntegerDigits(int newValue) { } /** - * Sets the maximum number of digits allowed in the fraction portion of a - * number. Negative input values are replaced with 0. - * @see NumberFormat#setMaximumFractionDigits + * {@inheritDoc NumberFormat} + * @param newValue the maximum number of fraction digits to be shown. + * @see #getMaximumFractionDigits() * @see ##digit_limits Integer and Fraction Digit Limits */ @Override @@ -4023,9 +4027,9 @@ public void setMaximumFractionDigits(int newValue) { } /** - * Sets the minimum number of digits allowed in the fraction portion of a - * number. Negative input values are replaced with 0. - * @see NumberFormat#setMinimumFractionDigits + * {@inheritDoc NumberFormat} + * @param newValue the minimum number of fraction digits to be shown. + * @see #getMinimumFractionDigits() * @see ##digit_limits Integer and Fraction Digit Limits */ @Override @@ -4040,11 +4044,11 @@ public void setMinimumFractionDigits(int newValue) { } /** - * Gets the maximum number of digits allowed in the integer portion of a - * number. The maximum number of integer digits can be set by either {@link #setMaximumIntegerDigits(int)} - * or {@link #applyPattern(String)}. See the {@link ##patterns Pattern Section} for - * comprehensive rules regarding maximum integer digits in patterns. + * {@inheritDoc NumberFormat} + *

        Unlike the other digit limits, {@code maximumIntegerDigits} is not + * updated by {@code DecimalFormats} created or updated with a string pattern. * @see #setMaximumIntegerDigits + * @see ##patterns Pattern Section * @see ##digit_limits Integer and Fraction Digit Limits */ @Override @@ -4053,8 +4057,7 @@ public int getMaximumIntegerDigits() { } /** - * Gets the minimum number of digits allowed in the integer portion of a - * number. + * {@inheritDoc NumberFormat} * @see #setMinimumIntegerDigits * @see ##digit_limits Integer and Fraction Digit Limits */ @@ -4064,8 +4067,7 @@ public int getMinimumIntegerDigits() { } /** - * Gets the maximum number of digits allowed in the fraction portion of a - * number. + * {@inheritDoc NumberFormat} * @see #setMaximumFractionDigits * @see ##digit_limits Integer and Fraction Digit Limits */ @@ -4075,8 +4077,7 @@ public int getMaximumFractionDigits() { } /** - * Gets the minimum number of digits allowed in the fraction portion of a - * number. + * {@inheritDoc NumberFormat} * @see #setMinimumFractionDigits * @see ##digit_limits Integer and Fraction Digit Limits */ diff --git a/src/java.base/share/classes/java/text/DigitList.java b/src/java.base/share/classes/java/text/DigitList.java index f269698d6da..d757f03bb84 100644 --- a/src/java.base/share/classes/java/text/DigitList.java +++ b/src/java.base/share/classes/java/text/DigitList.java @@ -784,12 +784,7 @@ public String toString() { return "0"; } - return getStringBuilder() - .append("0.") - .append(digits, 0, count) - .append("x10^") - .append(decimalAt) - .toString(); + return "0." + new String(digits, 0, count) + "x10^" + decimalAt; } private StringBuilder tempBuilder; diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java index 710c4e771ff..bd4ec53656a 100644 --- a/src/java.base/share/classes/java/text/NumberFormat.java +++ b/src/java.base/share/classes/java/text/NumberFormat.java @@ -129,9 +129,9 @@ *

          *
        • {@link #setParseIntegerOnly(boolean)}; when {@code true}, will only return the * integer portion of the number parsed from the String. - *
        • {@link #setMinimumFractionDigits(int)}; Use to adjust the expected digits when - * formatting. Use any of the other minimum/maximum or fraction/integer setter methods - * in the same manner. + *
        • {@link #setMinimumFractionDigits(int)}; Use to adjust the expected digits + * when formatting. Use any of the other minimum/maximum or fraction/integer + * setter methods in the same manner. These methods have no impact on parsing behavior. *
        • {@link #setGroupingUsed(boolean)}; when {@code true}, formatted numbers will be displayed * with grouping separators. Additionally, when {@code false}, parsing will not expect * grouping separators in the parsed String. @@ -918,7 +918,7 @@ public void setGroupingUsed(boolean newValue) { /** * Returns the maximum number of digits allowed in the integer portion of a - * number. + * number during formatting. * * @return the maximum number of digits * @see #setMaximumIntegerDigits @@ -929,14 +929,15 @@ public int getMaximumIntegerDigits() { /** * Sets the maximum number of digits allowed in the integer portion of a - * number. maximumIntegerDigits must be ≥ minimumIntegerDigits. If the - * new value for maximumIntegerDigits is less than the current value - * of minimumIntegerDigits, then minimumIntegerDigits will also be set to - * the new value. + * number during formatting. {@code maximumIntegerDigits} must be ≥ + * {@code minimumIntegerDigits}. If the new value for {@code + * maximumIntegerDigits} is less than the current value of + * {@code minimumIntegerDigits}, then {@code minimumIntegerDigits} will + * also be set to the new value. Negative input values are replaced with 0. * - * @param newValue the maximum number of integer digits to be shown; if - * less than zero, then zero is used. The concrete subclass may enforce an - * upper limit to this value appropriate to the numeric type being formatted. + * @param newValue the maximum number of integer digits to be shown. The + * concrete subclass may enforce an upper limit to this value appropriate to + * the numeric type being formatted. * @see #getMaximumIntegerDigits */ public void setMaximumIntegerDigits(int newValue) { @@ -948,7 +949,7 @@ public void setMaximumIntegerDigits(int newValue) { /** * Returns the minimum number of digits allowed in the integer portion of a - * number. + * number during formatting. * * @return the minimum number of digits * @see #setMinimumIntegerDigits @@ -959,14 +960,15 @@ public int getMinimumIntegerDigits() { /** * Sets the minimum number of digits allowed in the integer portion of a - * number. minimumIntegerDigits must be ≤ maximumIntegerDigits. If the - * new value for minimumIntegerDigits exceeds the current value - * of maximumIntegerDigits, then maximumIntegerDigits will also be set to - * the new value + * number during formatting. {@code minimumIntegerDigits} must be ≤ + * {@code maximumIntegerDigits}. If the new value for {@code minimumIntegerDigits} + * exceeds the current value of {@code maximumIntegerDigits}, then {@code + * maximumIntegerDigits} will also be set to the new value. Negative input + * values are replaced with 0. * - * @param newValue the minimum number of integer digits to be shown; if - * less than zero, then zero is used. The concrete subclass may enforce an - * upper limit to this value appropriate to the numeric type being formatted. + * @param newValue the minimum number of integer digits to be shown. The + * concrete subclass may enforce an upper limit to this value appropriate to + * the numeric type being formatted. * @see #getMinimumIntegerDigits */ public void setMinimumIntegerDigits(int newValue) { @@ -978,7 +980,7 @@ public void setMinimumIntegerDigits(int newValue) { /** * Returns the maximum number of digits allowed in the fraction portion of a - * number. + * number during formatting. * * @return the maximum number of digits. * @see #setMaximumFractionDigits @@ -989,14 +991,15 @@ public int getMaximumFractionDigits() { /** * Sets the maximum number of digits allowed in the fraction portion of a - * number. maximumFractionDigits must be ≥ minimumFractionDigits. If the - * new value for maximumFractionDigits is less than the current value - * of minimumFractionDigits, then minimumFractionDigits will also be set to - * the new value. + * number during formatting. {@code maximumFractionDigits} must be ≥ + * {@code minimumFractionDigits}. If the new value for {@code maximumFractionDigits} + * is less than the current value of {@code minimumFractionDigits}, then + * {@code minimumFractionDigits} will also be set to the new value. Negative + * input values are replaced with 0. * - * @param newValue the maximum number of fraction digits to be shown; if - * less than zero, then zero is used. The concrete subclass may enforce an - * upper limit to this value appropriate to the numeric type being formatted. + * @param newValue the maximum number of fraction digits to be shown. The + * concrete subclass may enforce an upper limit to this value appropriate to + * the numeric type being formatted. * @see #getMaximumFractionDigits */ public void setMaximumFractionDigits(int newValue) { @@ -1008,7 +1011,7 @@ public void setMaximumFractionDigits(int newValue) { /** * Returns the minimum number of digits allowed in the fraction portion of a - * number. + * number during formatting. * * @return the minimum number of digits * @see #setMinimumFractionDigits @@ -1019,14 +1022,15 @@ public int getMinimumFractionDigits() { /** * Sets the minimum number of digits allowed in the fraction portion of a - * number. minimumFractionDigits must be ≤ maximumFractionDigits. If the - * new value for minimumFractionDigits exceeds the current value - * of maximumFractionDigits, then maximumFractionDigits will also be set to - * the new value + * number during formatting. {@code minimumFractionDigits} must be ≤ + * {@code maximumFractionDigits}. If the new value for {@code + * minimumFractionDigits} exceeds the current value of {@code + * maximumFractionDigits}, then {@code maximumFractionDigits} will also be + * set to the new value. Negative input values are replaced with 0. * - * @param newValue the minimum number of fraction digits to be shown; if - * less than zero, then zero is used. The concrete subclass may enforce an - * upper limit to this value appropriate to the numeric type being formatted. + * @param newValue the minimum number of fraction digits to be shown. The + * concrete subclass may enforce an upper limit to this value appropriate to + * the numeric type being formatted. * @see #getMinimumFractionDigits */ public void setMinimumFractionDigits(int newValue) { diff --git a/src/java.base/share/classes/java/text/RuleBasedCollator.java b/src/java.base/share/classes/java/text/RuleBasedCollator.java index 045ca6e8e9b..dc45dafb846 100644 --- a/src/java.base/share/classes/java/text/RuleBasedCollator.java +++ b/src/java.base/share/classes/java/text/RuleBasedCollator.java @@ -591,7 +591,7 @@ public synchronized CollationKey getCollationKey(String source) // Here's a hypothetical example, with the collation element represented as // a three-digit number, one digit for primary, one for secondary, etc. // - // String: A a B \u00e9 <--(e-acute) + // String: A a B é (U+00E9, e-acute) // Collation Elements: 101 100 201 510 // // Collation Key: 112500011010 diff --git a/src/java.base/share/classes/java/time/Clock.java b/src/java.base/share/classes/java/time/Clock.java index 731a117fcea..7fab5d27fb3 100644 --- a/src/java.base/share/classes/java/time/Clock.java +++ b/src/java.base/share/classes/java/time/Clock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,8 +61,6 @@ */ package java.time; -import java.io.IOException; -import java.io.ObjectInputStream; import java.io.ObjectStreamException; import static java.time.LocalTime.NANOS_PER_MINUTE; @@ -780,7 +778,7 @@ public boolean equals(Object obj) { } @Override public int hashCode() { - return baseClock.hashCode() ^ ((int) (tickNanos ^ (tickNanos >>> 32))); + return baseClock.hashCode() ^ Long.hashCode(tickNanos); } @Override public String toString() { diff --git a/src/java.base/share/classes/java/time/Duration.java b/src/java.base/share/classes/java/time/Duration.java index d640121f32d..88d49fa9e45 100644 --- a/src/java.base/share/classes/java/time/Duration.java +++ b/src/java.base/share/classes/java/time/Duration.java @@ -1460,7 +1460,7 @@ public boolean equals(Object other) { */ @Override public int hashCode() { - return ((int) (seconds ^ (seconds >>> 32))) + (51 * nanos); + return Long.hashCode(seconds) + (51 * nanos); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/Instant.java b/src/java.base/share/classes/java/time/Instant.java index 82ff18c1421..1c7a41d7f0e 100644 --- a/src/java.base/share/classes/java/time/Instant.java +++ b/src/java.base/share/classes/java/time/Instant.java @@ -1363,7 +1363,7 @@ public boolean equals(Object other) { */ @Override public int hashCode() { - return ((int) (seconds ^ (seconds >>> 32))) + 51 * nanos; + return Long.hashCode(seconds) + 51 * nanos; } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/LocalDate.java b/src/java.base/share/classes/java/time/LocalDate.java index 13478530301..6724410da2b 100644 --- a/src/java.base/share/classes/java/time/LocalDate.java +++ b/src/java.base/share/classes/java/time/LocalDate.java @@ -182,11 +182,11 @@ public final class LocalDate /** * @serial The month-of-year. */ - private final short month; + private final byte month; /** * @serial The day-of-month. */ - private final short day; + private final byte day; //----------------------------------------------------------------------- /** @@ -490,8 +490,8 @@ private static LocalDate resolvePreviousValid(int year, int month, int day) { */ private LocalDate(int year, int month, int dayOfMonth) { this.year = year; - this.month = (short) month; - this.day = (short) dayOfMonth; + this.month = (byte) month; + this.day = (byte) dayOfMonth; } //----------------------------------------------------------------------- @@ -2133,10 +2133,7 @@ public boolean equals(Object obj) { */ @Override public int hashCode() { - int yearValue = year; - int monthValue = month; - int dayValue = day; - return (yearValue & 0xFFFFF800) ^ ((yearValue << 11) + (monthValue << 6) + (dayValue)); + return (year & 0xFFFFF800) ^ ((year << 11) + (month << 6) + day); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/MonthDay.java b/src/java.base/share/classes/java/time/MonthDay.java index 1de4fa84d3e..6244c14e6e1 100644 --- a/src/java.base/share/classes/java/time/MonthDay.java +++ b/src/java.base/share/classes/java/time/MonthDay.java @@ -146,11 +146,11 @@ public final class MonthDay /** * @serial The month-of-year, not null. */ - private final int month; + private final byte month; /** * @serial The day-of-month. */ - private final int day; + private final byte day; //----------------------------------------------------------------------- /** @@ -319,8 +319,8 @@ public static MonthDay parse(CharSequence text, DateTimeFormatter formatter) { * @param dayOfMonth the day-of-month to represent, validated from 1 to 29-31 */ private MonthDay(int month, int dayOfMonth) { - this.month = month; - this.day = dayOfMonth; + this.month = (byte) month; + this.day = (byte) dayOfMonth; } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/YearMonth.java b/src/java.base/share/classes/java/time/YearMonth.java index 8ad1172811f..b24151de3f0 100644 --- a/src/java.base/share/classes/java/time/YearMonth.java +++ b/src/java.base/share/classes/java/time/YearMonth.java @@ -153,7 +153,7 @@ public final class YearMonth /** * @serial The month-of-year, not null. */ - private final int month; + private final byte month; //----------------------------------------------------------------------- /** @@ -306,7 +306,7 @@ public static YearMonth parse(CharSequence text, DateTimeFormatter formatter) { */ private YearMonth(int year, int month) { this.year = year; - this.month = month; + this.month = (byte) month; } /** diff --git a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java index a79ecebe0c2..ca226b70d24 100644 --- a/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java +++ b/src/java.base/share/classes/java/time/chrono/ChronoLocalDateImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -421,7 +421,7 @@ public boolean equals(Object obj) { @Override public int hashCode() { long epDay = toEpochDay(); - return getChronology().hashCode() ^ ((int) (epDay ^ (epDay >>> 32))); + return getChronology().hashCode() ^ Long.hashCode(epDay); } @Override diff --git a/src/java.base/share/classes/java/time/chrono/HijrahDate.java b/src/java.base/share/classes/java/time/chrono/HijrahDate.java index 114a47e4797..2d3e4f93e69 100644 --- a/src/java.base/share/classes/java/time/chrono/HijrahDate.java +++ b/src/java.base/share/classes/java/time/chrono/HijrahDate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,11 +137,11 @@ public final class HijrahDate /** * The month-of-year. */ - private final transient int monthOfYear; + private final transient byte monthOfYear; /** * The day-of-month. */ - private final transient int dayOfMonth; + private final transient byte dayOfMonth; //------------------------------------------------------------------------- /** @@ -273,8 +273,8 @@ private HijrahDate(HijrahChronology chrono, int prolepticYear, int monthOfYear, this.chrono = chrono; this.prolepticYear = prolepticYear; - this.monthOfYear = monthOfYear; - this.dayOfMonth = dayOfMonth; + this.monthOfYear = (byte) monthOfYear; + this.dayOfMonth = (byte) dayOfMonth; } /** @@ -287,8 +287,8 @@ private HijrahDate(HijrahChronology chrono, long epochDay) { this.chrono = chrono; this.prolepticYear = dateInfo[0]; - this.monthOfYear = dateInfo[1]; - this.dayOfMonth = dateInfo[2]; + this.monthOfYear = (byte) dateInfo[1]; + this.dayOfMonth = (byte) dateInfo[2]; } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/util/AbstractMap.java b/src/java.base/share/classes/java/util/AbstractMap.java index 7c0b4d9dd1b..afc5b339354 100644 --- a/src/java.base/share/classes/java/util/AbstractMap.java +++ b/src/java.base/share/classes/java/util/AbstractMap.java @@ -877,6 +877,14 @@ public String toString() { */ /* non-public */ abstract static class ViewCollection implements Collection { UnsupportedOperationException uoe() { return new UnsupportedOperationException(); } + // convert null entry return values into NSEE + static > T nsee(T entry) { + if (entry == null) { + throw new NoSuchElementException(); + } else { + return entry; + } + } abstract Collection view(); public boolean add(E t) { throw uoe(); } diff --git a/src/java.base/share/classes/java/util/Collection.java b/src/java.base/share/classes/java/util/Collection.java index 0253dbc7e1a..43e8db55d7f 100644 --- a/src/java.base/share/classes/java/util/Collection.java +++ b/src/java.base/share/classes/java/util/Collection.java @@ -58,7 +58,7 @@ * constructors) but all of the general-purpose {@code Collection} * implementations in the Java platform libraries comply. * - *

          Certain methods are specified to be + *

          Certain methods are specified to be * optional. If a collection implementation doesn't implement a * particular operation, it should define the corresponding method to throw * {@code UnsupportedOperationException}. Such methods are marked "optional diff --git a/src/java.base/share/classes/java/util/Collections.java b/src/java.base/share/classes/java/util/Collections.java index 4dc7edeb852..7d3f4dd8573 100644 --- a/src/java.base/share/classes/java/util/Collections.java +++ b/src/java.base/share/classes/java/util/Collections.java @@ -2688,6 +2688,7 @@ public static List synchronizedList(List list) { new SynchronizedList<>(list)); } + // used by java.util.Vector static List synchronizedList(List list, Object mutex) { return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list, mutex) : @@ -2706,14 +2707,29 @@ static class SynchronizedList /** @serial */ @SuppressWarnings("serial") // Conditionally serializable final List list; + transient SynchronizedList reversedView = null; + transient final boolean isReversed; + // constructs a forward view, using 'this' as the mutex SynchronizedList(List list) { super(list); this.list = list; + this.isReversed = false; } + + // constructs a forward view, using 'mutex' as the mutex SynchronizedList(List list, Object mutex) { super(list, mutex); this.list = list; + this.isReversed = false; + } + + // constructs the reversed view; first arg should be reversed view of backing list + SynchronizedList(List revList, Object mutex, SynchronizedList forward) { + super(revList, mutex); + this.list = revList; + this.reversedView = forward; + this.isReversed = true; } public boolean equals(Object o) { @@ -2724,7 +2740,6 @@ public boolean equals(Object o) { public int hashCode() { synchronized (mutex) {return list.hashCode();} } - public E get(int index) { synchronized (mutex) {return list.get(index);} } @@ -2737,41 +2752,97 @@ public void add(int index, E element) { public E remove(int index) { synchronized (mutex) {return list.remove(index);} } - public int indexOf(Object o) { synchronized (mutex) {return list.indexOf(o);} } public int lastIndexOf(Object o) { synchronized (mutex) {return list.lastIndexOf(o);} } - public boolean addAll(int index, Collection c) { synchronized (mutex) {return list.addAll(index, c);} } - public ListIterator listIterator() { return list.listIterator(); // Must be manually synched by user } - public ListIterator listIterator(int index) { return list.listIterator(index); // Must be manually synched by user } - public List subList(int fromIndex, int toIndex) { synchronized (mutex) { return new SynchronizedList<>(list.subList(fromIndex, toIndex), mutex); } } - - @Override public void replaceAll(UnaryOperator operator) { synchronized (mutex) {list.replaceAll(operator);} } - @Override public void sort(Comparator c) { synchronized (mutex) {list.sort(c);} } + public void addFirst(E element) { + synchronized (mutex) {list.addFirst(element);} + } + public void addLast(E element) { + synchronized (mutex) {list.addLast(element);} + } + public E getFirst() { + synchronized (mutex) {return list.getFirst();} + } + public E getLast() { + synchronized (mutex) {return list.getLast();} + } + public E removeFirst() { + synchronized (mutex) {return list.removeFirst();} + } + public E removeLast() { + synchronized (mutex) {return list.removeLast();} + } + + /** + * Reversed view handling. The reversedView field is transient + * and is initialized to null upon construction of the wrapper + * and upon deserialization. Reversed views are not serializable. + * The reversed view is created on first call to the reversed() + * method. + * + * There are four objects at play here: + * + * L = original list + * Lr = reversed view of original list + * S = synchronized forward wrapper: its backing list is L + * Sr = synchronized reversed wrapper: its backing list is Lr + * + * The reversedView field of S points to Sr and vice versa. + * This enables the reversed() method always to return the same + * object, and for S.reversed().reversed() to return S. This isn't + * strictly necessary, because all internal locking is done on S + * (which is passed around as mutex). But in the case where the + * client does external locking, it's good to minimize the number + * of different instances. Note however that external locking on + * the reversed wrapper Sr can't be made to work properly with + * internal or external locking on the forward wrapper S. (Sublists + * of a synchronized wrapper, reversed or not, have the same issue.) + * + * An alternative would be to have a ReversedSynchronizedList view class. However, + * that would require two extra classes (one RandomAccess and one not) and it would + * complicate the serialization story. + */ + public List reversed() { + synchronized (mutex) { + if (reversedView == null) { + reversedView = new SynchronizedList<>(list.reversed(), mutex, this); + } + return reversedView; + } + } + + @java.io.Serial + private void writeObject(ObjectOutputStream out) throws IOException { + if (isReversed) { + throw new java.io.NotSerializableException(); + } + out.defaultWriteObject(); + } /** * SynchronizedRandomAccessList instances are serialized as @@ -2808,6 +2879,19 @@ static class SynchronizedRandomAccessList super(list, mutex); } + SynchronizedRandomAccessList(List list, Object mutex, SynchronizedList forward) { + super(list, mutex, forward); + } + + public List reversed() { + synchronized (mutex) { + if (reversedView == null) { + reversedView = new SynchronizedRandomAccessList<>(list.reversed(), mutex, this); + } + return reversedView; + } + } + public List subList(int fromIndex, int toIndex) { synchronized (mutex) { return new SynchronizedRandomAccessList<>( diff --git a/src/java.base/share/classes/java/util/Currency.java b/src/java.base/share/classes/java/util/Currency.java index 3aa966e83e8..febae04a77b 100644 --- a/src/java.base/share/classes/java/util/Currency.java +++ b/src/java.base/share/classes/java/util/Currency.java @@ -38,6 +38,7 @@ import java.time.format.DateTimeParseException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.function.Supplier; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.spi.CurrencyNameProvider; @@ -141,7 +142,8 @@ public final class Currency implements Serializable { // class data: instance map private static ConcurrentMap instances = new ConcurrentHashMap<>(7); - private static HashSet available; + private static final Supplier> available = + StableValue.supplier(Currency::computeAllCurrencies); // Class data: currency data obtained from currency.data file. // Purpose: @@ -447,7 +449,7 @@ public static Currency getInstance(Locale locale) { * @since 1.7 */ public static Set getAvailableCurrencies() { - return new HashSet<>(getCurrencies()); + return new HashSet<>(available.get()); } /** @@ -462,53 +464,52 @@ public static Set getAvailableCurrencies() { * @since 25 */ public static Stream availableCurrencies() { - return getCurrencies().stream(); + return available.get().stream(); } - // Returns the set of available Currencies which are lazily initialized - private static synchronized HashSet getCurrencies() { - if (available == null) { - var sysTime = System.currentTimeMillis(); - available = HashSet.newHashSet(256); - - // Add simple currencies first - for (char c1 = 'A'; c1 <= 'Z'; c1 ++) { - for (char c2 = 'A'; c2 <= 'Z'; c2 ++) { - int tableEntry = getMainTableEntry(c1, c2); - if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK - && tableEntry != INVALID_COUNTRY_ENTRY) { - char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A'); - int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT; - int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT; - StringBuilder sb = new StringBuilder(); - sb.append(c1); - sb.append(c2); - sb.append(finalChar); - available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode)); - } else if ((tableEntry & COUNTRY_TYPE_MASK) == SPECIAL_CASE_COUNTRY_MASK - && tableEntry != INVALID_COUNTRY_ENTRY - && tableEntry != COUNTRY_WITHOUT_CURRENCY_ENTRY) { - int index = SpecialCaseEntry.toIndex(tableEntry); - SpecialCaseEntry scEntry = specialCasesList.get(index); - - if (scEntry.cutOverTime == Long.MAX_VALUE - || sysTime < scEntry.cutOverTime) { - available.add(getInstance(scEntry.oldCurrency, - scEntry.oldCurrencyFraction, - scEntry.oldCurrencyNumericCode)); - } else { - available.add(getInstance(scEntry.newCurrency, - scEntry.newCurrencyFraction, - scEntry.newCurrencyNumericCode)); - } + // Builds and returns the set of available Currencies + private static HashSet computeAllCurrencies() { + var sysTime = System.currentTimeMillis(); + HashSet available = HashSet.newHashSet(256); + + for (char c1 = 'A'; c1 <= 'Z'; c1 ++) { + for (char c2 = 'A'; c2 <= 'Z'; c2 ++) { + int tableEntry = getMainTableEntry(c1, c2); + if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK + && tableEntry != INVALID_COUNTRY_ENTRY) { + // Simple Currencies + char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A'); + int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT; + int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT; + StringBuilder sb = new StringBuilder(); + sb.append(c1); + sb.append(c2); + sb.append(finalChar); + available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode)); + } else if ((tableEntry & COUNTRY_TYPE_MASK) == SPECIAL_CASE_COUNTRY_MASK + && tableEntry != INVALID_COUNTRY_ENTRY + && tableEntry != COUNTRY_WITHOUT_CURRENCY_ENTRY) { + // Special Currencies + int index = SpecialCaseEntry.toIndex(tableEntry); + SpecialCaseEntry scEntry = specialCasesList.get(index); + + if (scEntry.cutOverTime == Long.MAX_VALUE + || sysTime < scEntry.cutOverTime) { + available.add(getInstance(scEntry.oldCurrency, + scEntry.oldCurrencyFraction, + scEntry.oldCurrencyNumericCode)); + } else { + available.add(getInstance(scEntry.newCurrency, + scEntry.newCurrencyFraction, + scEntry.newCurrencyNumericCode)); } } } + } - // Now add other currencies - for (OtherCurrencyEntry entry : otherCurrenciesList) { - available.add(getInstance(entry.currencyCode)); - } + // Other Currencies + for (OtherCurrencyEntry entry : otherCurrenciesList) { + available.add(getInstance(entry.currencyCode)); } return available; } diff --git a/src/java.base/share/classes/java/util/HexFormat.java b/src/java.base/share/classes/java/util/HexFormat.java index cd6cf8af17d..99d047995fd 100644 --- a/src/java.base/share/classes/java/util/HexFormat.java +++ b/src/java.base/share/classes/java/util/HexFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -462,7 +462,7 @@ private String formatOptDelimiter(byte[] bytes, int fromIndex, int toIndex) { } try { // Return a new string using the bytes without making a copy - return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1); + return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1); } catch (CharacterCodingException cce) { throw new AssertionError(cce); } @@ -696,7 +696,7 @@ public String toHexDigits(byte value) { rep[0] = (byte)toHighHexDigit(value); rep[1] = (byte)toLowHexDigit(value); try { - return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1); + return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1); } catch (CharacterCodingException cce) { throw new AssertionError(cce); } @@ -732,7 +732,7 @@ public String toHexDigits(short value) { rep[3] = (byte)toLowHexDigit((byte)value); try { - return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1); + return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1); } catch (CharacterCodingException cce) { throw new AssertionError(cce); } @@ -760,7 +760,7 @@ public String toHexDigits(int value) { rep[7] = (byte)toLowHexDigit((byte)value); try { - return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1); + return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1); } catch (CharacterCodingException cce) { throw new AssertionError(cce); } @@ -796,7 +796,7 @@ public String toHexDigits(long value) { rep[15] = (byte)toLowHexDigit((byte)value); try { - return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1); + return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1); } catch (CharacterCodingException cce) { throw new AssertionError(cce); } @@ -824,7 +824,7 @@ public String toHexDigits(long value, int digits) { value = value >>> 4; } try { - return jla.newStringNoRepl(rep, StandardCharsets.ISO_8859_1); + return jla.uncheckedNewStringNoRepl(rep, StandardCharsets.ISO_8859_1); } catch (CharacterCodingException cce) { throw new AssertionError(cce); } diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index 205a6be6f89..38cc45122a2 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,11 +36,18 @@ import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.IntFunction; import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.function.UnaryOperator; + import jdk.internal.access.JavaUtilCollectionAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.lang.stable.StableUtil; +import jdk.internal.lang.stable.StableValueImpl; import jdk.internal.misc.CDS; +import jdk.internal.util.ArraysSupport; +import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Stable; /** @@ -128,6 +135,14 @@ public List listFromTrustedArray(Object[] array) { public List listFromTrustedArrayNullsAllowed(Object[] array) { return ImmutableCollections.listFromTrustedArrayNullsAllowed(array); } + public List stableList(int size, IntFunction mapper) { + // A stable list is not Serializable, so we cannot return `List.of()` if `size == 0` + return new StableList<>(size, mapper); + } + public Map stableMap(Set keys, Function mapper) { + // A stable map is not Serializable, so we cannot return `Map.of()` if `keys.isEmpty()` + return new StableMap<>(keys, mapper); + } }); } } @@ -435,20 +450,20 @@ public void add(E e) { } } - static final class SubList extends AbstractImmutableList + static sealed class SubList extends AbstractImmutableList implements RandomAccess { @Stable - private final AbstractImmutableList root; + final AbstractImmutableList root; @Stable - private final int offset; + final int offset; @Stable - private final int size; + final int size; private SubList(AbstractImmutableList root, int offset, int size) { - assert root instanceof List12 || root instanceof ListN; + assert root instanceof List12 || root instanceof ListN || root instanceof StableList; this.root = root; this.offset = offset; this.size = size; @@ -498,8 +513,8 @@ private void rangeCheck(int index) { } } - private boolean allowNulls() { - return root instanceof ListN && ((ListN)root).allowNulls; + boolean allowNulls() { + return root instanceof ListN listN && listN.allowNulls; } @Override @@ -551,6 +566,7 @@ public T[] toArray(T[] a) { } return array; } + } @jdk.internal.ValueBased @@ -768,6 +784,187 @@ public int lastIndexOf(Object o) { } } + @FunctionalInterface + interface HasStableDelegates { + StableValueImpl[] delegates(); + } + + @jdk.internal.ValueBased + static final class StableList + extends AbstractImmutableList + implements HasStableDelegates { + + @Stable + private final IntFunction mapper; + @Stable + final StableValueImpl[] delegates; + + StableList(int size, IntFunction mapper) { + this.mapper = mapper; + this.delegates = StableUtil.array(size); + } + + @Override public boolean isEmpty() { return delegates.length == 0;} + @Override public int size() { return delegates.length; } + @Override public Object[] toArray() { return copyInto(new Object[size()]); } + + @ForceInline + @Override + public E get(int i) { + final StableValueImpl delegate; + try { + delegate = delegates[i]; + } catch (ArrayIndexOutOfBoundsException aioobe) { + throw new IndexOutOfBoundsException(i); + } + return delegate.orElseSet(new Supplier() { + @Override public E get() { return mapper.apply(i); }}); + } + + @Override + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + final int size = delegates.length; + if (a.length < size) { + // Make a new array of a's runtime type, but my contents: + T[] n = (T[])Array.newInstance(a.getClass().getComponentType(), size); + return copyInto(n); + } + copyInto(a); + if (a.length > size) { + a[size] = null; // null-terminate + } + return a; + } + + @Override + public int indexOf(Object o) { + final int size = size(); + for (int i = 0; i < size; i++) { + if (Objects.equals(o, get(i))) { + return i; + } + } + return -1; + } + + @Override + public int lastIndexOf(Object o) { + for (int i = size() - 1; i >= 0; i--) { + if (Objects.equals(o, get(i))) { + return i; + } + } + return -1; + } + + @SuppressWarnings("unchecked") + private T[] copyInto(Object[] a) { + final int len = delegates.length; + for (int i = 0; i < len; i++) { + a[i] = get(i); + } + return (T[]) a; + } + + @Override + public List reversed() { + return new StableReverseOrderListView<>(this); + } + + @Override + public List subList(int fromIndex, int toIndex) { + subListRangeCheck(fromIndex, toIndex, size()); + return StableSubList.fromStableList(this, fromIndex, toIndex); + } + + @Override + public String toString() { + return StableUtil.renderElements(this, "StableCollection", delegates); + } + + @Override + public StableValueImpl[] delegates() { + return delegates; + } + + private static final class StableSubList extends SubList + implements HasStableDelegates { + + private StableSubList(AbstractImmutableList root, int offset, int size) { + super(root, offset, size); + } + + @Override + public List reversed() { + return new StableReverseOrderListView<>(this); + } + + @Override + public List subList(int fromIndex, int toIndex) { + subListRangeCheck(fromIndex, toIndex, size()); + return StableSubList.fromStableSubList(this, fromIndex, toIndex); + } + + @Override + public String toString() { + return StableUtil.renderElements(this, "StableCollection", delegates()); + } + + @Override + boolean allowNulls() { + return true; + } + + @Override + public StableValueImpl[] delegates() { + @SuppressWarnings("unchecked") + final var rootDelegates = ((HasStableDelegates) root).delegates(); + return Arrays.copyOfRange(rootDelegates, offset, offset + size); + } + + static SubList fromStableList(StableList list, int fromIndex, int toIndex) { + return new StableSubList<>(list, fromIndex, toIndex - fromIndex); + } + + static SubList fromStableSubList(StableSubList parent, int fromIndex, int toIndex) { + return new StableSubList<>(parent.root, parent.offset + fromIndex, toIndex - fromIndex); + } + + } + + private static final class StableReverseOrderListView + extends ReverseOrderListView.Rand + implements HasStableDelegates { + + private StableReverseOrderListView(List base) { + super(base, false); + } + + // This method does not evaluate the elements + @Override + public String toString() { + return StableUtil.renderElements(this, "StableCollection", delegates()); + } + + @Override + public List subList(int fromIndex, int toIndex) { + final int size = base.size(); + subListRangeCheck(fromIndex, toIndex, size); + return new StableReverseOrderListView<>(base.subList(size - toIndex, size - fromIndex)); + } + + @Override + public StableValueImpl[] delegates() { + @SuppressWarnings("unchecked") + final var baseDelegates = ((HasStableDelegates) base).delegates(); + return ArraysSupport.reverse( + Arrays.copyOf(baseDelegates, baseDelegates.length)); + } + } + + } + // ---------- Set Implementations ---------- @jdk.internal.ValueBased @@ -1112,7 +1309,7 @@ public T[] toArray(T[] a) { // ---------- Map Implementations ---------- // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap - abstract static class AbstractImmutableMap extends AbstractMap implements Serializable { + abstract static class AbstractImmutableMap extends AbstractMap { @Override public void clear() { throw uoe(); } @Override public V compute(K key, BiFunction rf) { throw uoe(); } @Override public V computeIfAbsent(K key, Function mf) { throw uoe(); } @@ -1143,7 +1340,7 @@ public V getOrDefault(Object key, V defaultValue) { } // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap - static final class Map1 extends AbstractImmutableMap { + static final class Map1 extends AbstractImmutableMap implements Serializable { @Stable private final K k0; @Stable @@ -1215,7 +1412,7 @@ public void forEach(BiConsumer action) { * @param the value type */ // Not a jdk.internal.ValueBased class; disqualified by fields in superclass AbstractMap - static final class MapN extends AbstractImmutableMap { + static final class MapN extends AbstractImmutableMap implements Serializable { @Stable final Object[] table; // pairs of key, value @@ -1405,6 +1602,188 @@ private Object writeReplace() { return new CollSer(CollSer.IMM_MAP, array); } } + + static final class StableMap + extends AbstractImmutableMap { + + @Stable + private final Function mapper; + @Stable + private final Map> delegate; + + StableMap(Set keys, Function mapper) { + this.mapper = mapper; + this.delegate = StableUtil.map(keys); + } + + @Override public boolean containsKey(Object o) { return delegate.containsKey(o); } + @Override public int size() { return delegate.size(); } + @Override public Set> entrySet() { return StableMapEntrySet.of(this); } + + @ForceInline + @Override + public V get(Object key) { + return getOrDefault(key, null); + } + + @ForceInline + @Override + public V getOrDefault(Object key, V defaultValue) { + final StableValueImpl stable = delegate.get(key); + if (stable == null) { + return defaultValue; + } + @SuppressWarnings("unchecked") + final K k = (K) key; + return stable.orElseSet(new Supplier() { + @Override public V get() { return mapper.apply(k); }}); + } + + @jdk.internal.ValueBased + static final class StableMapEntrySet extends AbstractImmutableSet> { + + // Use a separate field for the outer class in order to facilitate + // a @Stable annotation. + @Stable + private final StableMap outer; + + @Stable + private final Set>> delegateEntrySet; + + private StableMapEntrySet(StableMap outer) { + this.outer = outer; + this.delegateEntrySet = outer.delegate.entrySet(); + } + + @Override public Iterator> iterator() { return LazyMapIterator.of(this); } + @Override public int size() { return delegateEntrySet.size(); } + @Override public int hashCode() { return outer.hashCode(); } + + @Override + public String toString() { + return StableUtil.renderMappings(this, "StableCollection", delegateEntrySet, false); + } + + // For @ValueBased + private static StableMapEntrySet of(StableMap outer) { + return new StableMapEntrySet<>(outer); + } + + @jdk.internal.ValueBased + static final class LazyMapIterator implements Iterator> { + + // Use a separate field for the outer class in order to facilitate + // a @Stable annotation. + @Stable + private final StableMapEntrySet outer; + + @Stable + private final Iterator>> delegateIterator; + + private LazyMapIterator(StableMapEntrySet outer) { + this.outer = outer; + this.delegateIterator = outer.delegateEntrySet.iterator(); + } + + @Override public boolean hasNext() { return delegateIterator.hasNext(); } + + @Override + public Entry next() { + final Map.Entry> inner = delegateIterator.next(); + final K k = inner.getKey(); + return new StableEntry<>(k, inner.getValue(), new Supplier() { + @Override public V get() { return outer.outer.mapper.apply(k); }}); + } + + @Override + public void forEachRemaining(Consumer> action) { + final Consumer>> innerAction = + new Consumer<>() { + @Override + public void accept(Entry> inner) { + final K k = inner.getKey(); + action.accept(new StableEntry<>(k, inner.getValue(), new Supplier() { + @Override public V get() { return outer.outer.mapper.apply(k); }})); + } + }; + delegateIterator.forEachRemaining(innerAction); + } + + // For @ValueBased + private static LazyMapIterator of(StableMapEntrySet outer) { + return new LazyMapIterator<>(outer); + } + + } + } + + private record StableEntry(K getKey, // trick + StableValueImpl stableValue, + Supplier supplier) implements Map.Entry { + + @Override public V setValue(V value) { throw uoe(); } + @Override public V getValue() { return stableValue.orElseSet(supplier); } + @Override public int hashCode() { return hash(getKey()) ^ hash(getValue()); } + @Override public String toString() { return getKey() + "=" + stableValue.toString(); } + @Override public boolean equals(Object o) { + return o instanceof Map.Entry e + && Objects.equals(getKey(), e.getKey()) + // Invoke `getValue()` as late as possible to avoid evaluation + && Objects.equals(getValue(), e.getValue()); + } + + private int hash(Object obj) { return (obj == null) ? 0 : obj.hashCode(); } + } + + @Override + public Collection values() { + return StableMapValues.of(this); + } + + @jdk.internal.ValueBased + static final class StableMapValues extends AbstractImmutableCollection { + + // Use a separate field for the outer class in order to facilitate + // a @Stable annotation. + @Stable + private final StableMap outer; + + private StableMapValues(StableMap outer) { + this.outer = outer; + } + + @Override public Iterator iterator() { return outer.new ValueIterator(); } + @Override public int size() { return outer.size(); } + @Override public boolean isEmpty() { return outer.isEmpty();} + @Override public boolean contains(Object v) { return outer.containsValue(v); } + + private static final IntFunction[]> GENERATOR = new IntFunction[]>() { + @Override + public StableValueImpl[] apply(int len) { + return new StableValueImpl[len]; + } + }; + + @Override + public String toString() { + final StableValueImpl[] values = outer.delegate.values().toArray(GENERATOR); + return StableUtil.renderElements(this, "StableCollection", values); + } + + // For @ValueBased + private static StableMapValues of(StableMap outer) { + return new StableMapValues<>(outer); + } + + } + + @Override + public String toString() { + return StableUtil.renderMappings(this, "StableMap", delegate.entrySet(), true); + } + + } + } // ---------- Serialization Proxy ---------- diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 28468165fab..993495ff5ab 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -385,10 +385,10 @@ * {@snippet lang = java: * var number = 1000; * NumberFormat.getCurrencyInstance(Locale.US).format(number); // returns "$1,000.00" - * NumberFormat.getCurrencyInstance(Locale.JAPAN).format(number); // returns "\u00A51,000"" + * NumberFormat.getCurrencyInstance(Locale.JAPAN).format(number); // returns "¥1,000"" * var date = LocalDate.of(2024, 1, 1); * DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).localizedBy(Locale.US).format(date); // returns "January 1, 2024" - * DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).localizedBy(Locale.JAPAN).format(date); // returns "2024\u5e741\u67081\u65e5" + * DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).localizedBy(Locale.JAPAN).format(date); // returns "2024年1月1日" * } * *

          Locale Matching

          @@ -1310,7 +1310,7 @@ public static String[] getISOCountries() { } /** - * {@return a {@code Set} of ISO3166 country codes for the specified type} + * {@return an unmodifiable {@code Set} of ISO3166 country codes for the specified type} * * @param type {@link Locale.IsoCountryCode} specified ISO code type. * @see java.util.Locale.IsoCountryCode @@ -1691,37 +1691,37 @@ public String toLanguageTag() { LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions); StringBuilder buf = new StringBuilder(); - String subtag = tag.getLanguage(); + String subtag = tag.language(); if (!subtag.isEmpty()) { buf.append(LanguageTag.canonicalizeLanguage(subtag)); } - subtag = tag.getScript(); + subtag = tag.script(); if (!subtag.isEmpty()) { buf.append(LanguageTag.SEP); buf.append(LanguageTag.canonicalizeScript(subtag)); } - subtag = tag.getRegion(); + subtag = tag.region(); if (!subtag.isEmpty()) { buf.append(LanguageTag.SEP); buf.append(LanguageTag.canonicalizeRegion(subtag)); } - Listsubtags = tag.getVariants(); + Listsubtags = tag.variants(); for (String s : subtags) { buf.append(LanguageTag.SEP); // preserve casing buf.append(s); } - subtags = tag.getExtensions(); + subtags = tag.extensions(); for (String s : subtags) { buf.append(LanguageTag.SEP); buf.append(LanguageTag.canonicalizeExtension(s)); } - subtag = tag.getPrivateuse(); + subtag = tag.privateuse(); if (!subtag.isEmpty()) { if (buf.length() > 0) { buf.append(LanguageTag.SEP); @@ -1800,7 +1800,7 @@ public static String caseFoldLanguageTag(String languageTag) { * to {@link Locale.Builder#setLanguageTag(String)} which throws an exception * in this case. * - *

          The following conversions are performed:

            + *

            The following conversions are performed:

              * *
            • The language code "und" is mapped to language "". * @@ -1826,13 +1826,19 @@ public static String caseFoldLanguageTag(String languageTag) { * loc.getExtension('x'); // returns "urp" * } * - *
            • When the languageTag argument contains an extlang subtag, - * the first such subtag is used as the language, and the primary - * language subtag and other extlang subtags are ignored: + *
            • BCP 47 language tags permit up to three extlang subtags. However, + * the second and third extlang subtags are always ignored. As such, + * the first extlang subtag in {@code languageTag} is used as the language, + * and the primary language subtag and other extlang subtags are ignored. + * Language tags that exceed three extlang subtags are considered + * ill-formed starting at the offending extlang subtag. * * {@snippet lang=java : * Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao" * Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US" + * Locale.forLanguageTag("zh-yue-gan-cmn-czh-CN").toString(); + * // returns "yue"; "czh" exceeds the extlang limit, and subsequent + * // subtags are considered ill-formed * } * *
            • Case is normalized except for variant tags, which are left @@ -2787,6 +2793,9 @@ public Builder setLocale(Locale locale) { * just discards ill-formed and following portions of the * tag). * + *

              See {@link Locale##langtag_conversions converions} for a full list + * of conversions that are performed on {@code languageTag}. + * * @param languageTag the language tag * @return This builder. * @throws IllformedLocaleException if {@code languageTag} is ill-formed @@ -3497,8 +3506,7 @@ public int hashCode() { if (h == 0) { h = 17; h = 37*h + range.hashCode(); - long bitsWeight = Double.doubleToLongBits(weight); - h = 37*h + (int)(bitsWeight ^ (bitsWeight >>> 32)); + h = 37*h + Double.hashCode(weight); if (h != 0) { hash = h; } diff --git a/src/java.base/share/classes/java/util/LocaleISOData.java b/src/java.base/share/classes/java/util/LocaleISOData.java index d102ad5c87e..c2090d3be19 100644 --- a/src/java.base/share/classes/java/util/LocaleISOData.java +++ b/src/java.base/share/classes/java/util/LocaleISOData.java @@ -145,7 +145,7 @@ class LocaleISOData { + "mt" + "mlt" // Maltese + "my" + "mya" // Burmese + "na" + "nau" // Nauru - + "nb" + "nob" // Norwegian Bokm\u00e5l + + "nb" + "nob" // Norwegian Bokmål + "nd" + "nde" // North Ndebele + "ne" + "nep" // Nepali + "ng" + "ndo" // Ndonga @@ -209,7 +209,7 @@ class LocaleISOData { + "uz" + "uzb" // Uzbek + "ve" + "ven" // Venda + "vi" + "vie" // Vietnamese - + "vo" + "vol" // Volap\u00fck + + "vo" + "vol" // Volapük + "wa" + "wln" // Walloon + "wo" + "wol" // Wolof + "xh" + "xho" // Xhosa @@ -239,7 +239,7 @@ class LocaleISOData { + "AT" + "AUT" // Austria, Republic of + "AU" + "AUS" // Australia, Commonwealth of + "AW" + "ABW" // Aruba - + "AX" + "ALA" // \u00c5land Islands + + "AX" + "ALA" // Åland Islands + "AZ" + "AZE" // Azerbaijan, Republic of + "BA" + "BIH" // Bosnia and Herzegovina + "BB" + "BRB" // Barbados @@ -250,7 +250,7 @@ class LocaleISOData { + "BH" + "BHR" // Bahrain, Kingdom of + "BI" + "BDI" // Burundi, Republic of + "BJ" + "BEN" // Benin, People's Republic of - + "BL" + "BLM" // Saint Barth\u00e9lemy + + "BL" + "BLM" // Saint Barthélemy + "BM" + "BMU" // Bermuda + "BN" + "BRN" // Brunei Darussalam + "BO" + "BOL" // Bolivia, Plurinational State of @@ -278,7 +278,7 @@ class LocaleISOData { // + "CS" + "SCG" // Serbia and Montenegro + "CU" + "CUB" // Cuba, Republic of + "CV" + "CPV" // Cape Verde, Republic of - + "CW" + "CUW" // Cura\u00e7ao + + "CW" + "CUW" // Curaçao + "CX" + "CXR" // Christmas Island + "CY" + "CYP" // Cyprus, Republic of + "CZ" + "CZE" // Czech Republic diff --git a/src/java.base/share/classes/java/util/Optional.java b/src/java.base/share/classes/java/util/Optional.java index 21128fa980d..e19dde6383e 100644 --- a/src/java.base/share/classes/java/util/Optional.java +++ b/src/java.base/share/classes/java/util/Optional.java @@ -394,7 +394,7 @@ public T orElseThrow() { * @return the value, if present * @throws X if no value is present * @throws NullPointerException if no value is present and the exception - * supplying function is {@code null} + * supplying function is {@code null} or produces a {@code null} result */ public T orElseThrow(Supplier exceptionSupplier) throws X { if (value != null) { diff --git a/src/java.base/share/classes/java/util/PropertyResourceBundle.java b/src/java.base/share/classes/java/util/PropertyResourceBundle.java index d8cc1fac198..9b832a70577 100644 --- a/src/java.base/share/classes/java/util/PropertyResourceBundle.java +++ b/src/java.base/share/classes/java/util/PropertyResourceBundle.java @@ -81,7 +81,7 @@ * Keys are case-sensitive. * {@snippet lang=properties : * # MessageFormat pattern - * s1=Die Platte \"{1}\" enth\u00E4lt {0}. + * s1=Die Platte \"{1}\" enthält {0}. * # location of {0} in pattern * s2=1 * # sample disk name @@ -93,7 +93,7 @@ * # third ChoiceFormat choice * s6={0,number} Dateien * # sample date - * s7=3. M\u00E4rz 1996 + * s7=3. März 1996 * } * * @apiNote diff --git a/src/java.base/share/classes/java/util/ReverseOrderListView.java b/src/java.base/share/classes/java/util/ReverseOrderListView.java index f48b41920c9..6ecbac66ed8 100644 --- a/src/java.base/share/classes/java/util/ReverseOrderListView.java +++ b/src/java.base/share/classes/java/util/ReverseOrderListView.java @@ -33,19 +33,19 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.internal.util.ArraysSupport; +import jdk.internal.vm.annotation.Stable; /** * Provides a reverse-ordered view of a List. Not serializable. */ class ReverseOrderListView implements List { + @Stable final List base; final boolean modifiable; public static List of(List list, boolean modifiable) { - if (list instanceof ReverseOrderListView rolv) { - return rolv.base; - } else if (list instanceof RandomAccess) { + if (list instanceof RandomAccess) { return new ReverseOrderListView.Rand<>(list, modifiable); } else { return new ReverseOrderListView<>(list, modifiable); @@ -395,6 +395,10 @@ public List subList(int fromIndex, int toIndex) { return new ReverseOrderListView<>(base.subList(size - toIndex, size - fromIndex), modifiable); } + public List reversed() { + return base; + } + static void checkClosedRange(int index, int size) { if (index < 0 || index > size) { throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); diff --git a/src/java.base/share/classes/java/util/Scanner.java b/src/java.base/share/classes/java/util/Scanner.java index bb93745bc24..3e27325aa0d 100644 --- a/src/java.base/share/classes/java/util/Scanner.java +++ b/src/java.base/share/classes/java/util/Scanner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,7 +78,7 @@ * } * } * - *

              As another example, this code allows {@code long} types to be + *

              This code allows {@code long} types to be * assigned from entries in a file {@code myNumbers}: * {@snippet : * Scanner sc = new Scanner(new File("myNumbers")); @@ -87,6 +87,19 @@ * } * } * + *

              This code uses a {@code Scanner} to read lines from {@link System#in}. The + * {@code Scanner} uses the system property value of + * {@link System##stdin.encoding stdin.encoding} as the {@code Charset}. Specifying + * the charset explicitly is important when reading from {@code System.in}, as it + * may differ from the {@link Charset#defaultCharset() default charset} depending + * on the host environment or user configuration: + * {@snippet : + * Scanner sc = new Scanner(System.in, System.getProperty("stdin.encoding")); + * while (sc.hasNextLine()) { + * String aLine = sc.nextLine(); + * } + * } + * *

              The scanner can also use delimiters other than whitespace. This * example reads several items in from a string: * {@snippet : diff --git a/src/java.base/share/classes/java/util/SequencedMap.java b/src/java.base/share/classes/java/util/SequencedMap.java index 6bff204b65d..cf27b82896b 100644 --- a/src/java.base/share/classes/java/util/SequencedMap.java +++ b/src/java.base/share/classes/java/util/SequencedMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -263,8 +263,15 @@ default V putLast(K k, V v) { * * @implSpec * The implementation in this interface returns a {@code SequencedSet} instance - * that behaves as follows. Its {@link SequencedSet#add add} and {@link - * SequencedSet#addAll addAll} methods throw {@link UnsupportedOperationException}. + * that behaves as follows. Its {@link SequencedSet#add add}, {@link + * SequencedSet#addAll addAll}, {@link SequencedSet#addFirst addFirst}, and {@link + * SequencedSet#addLast addLast} methods throw {@link UnsupportedOperationException}. + * Its {@link SequencedSet#getFirst getFirst} and {@link SequencedSet#getLast getLast} + * methods are implemented in terms of the {@link #firstEntry firstEntry} and {@link + * #lastEntry lastEntry} methods of this interface, respectively. Its {@link + * SequencedSet#removeFirst removeFirst} and {@link SequencedSet#removeLast removeLast} + * methods are implemented in terms of the {@link #pollFirstEntry pollFirstEntry} and + * {@link #pollLastEntry pollLastEntry} methods of this interface, respectively. * Its {@link SequencedSet#reversed reversed} method returns the {@link * #sequencedKeySet sequencedKeySet} view of the {@link #reversed reversed} view of * this map. Each of its other methods calls the corresponding method of the {@link @@ -286,6 +293,16 @@ public boolean equals(Object other) { public int hashCode() { return view().hashCode(); } + public void addFirst(K k) { throw new UnsupportedOperationException(); } + public void addLast(K k) { throw new UnsupportedOperationException(); } + public K getFirst() { return nsee(SequencedMap.this.firstEntry()).getKey(); } + public K getLast() { return nsee(SequencedMap.this.lastEntry()).getKey(); } + public K removeFirst() { + return nsee(SequencedMap.this.pollFirstEntry()).getKey(); + } + public K removeLast() { + return nsee(SequencedMap.this.pollLastEntry()).getKey(); + } } return new SeqKeySet(); } @@ -295,8 +312,15 @@ public int hashCode() { * * @implSpec * The implementation in this interface returns a {@code SequencedCollection} instance - * that behaves as follows. Its {@link SequencedCollection#add add} and {@link - * SequencedCollection#addAll addAll} methods throw {@link UnsupportedOperationException}. + * that behaves as follows. Its {@link SequencedCollection#add add}, {@link + * SequencedCollection#addAll addAll}, {@link SequencedCollection#addFirst addFirst}, and {@link + * SequencedCollection#addLast addLast} methods throw {@link UnsupportedOperationException}. + * Its {@link SequencedCollection#getFirst getFirst} and {@link SequencedCollection#getLast getLast} + * methods are implemented in terms of the {@link #firstEntry firstEntry} and {@link + * #lastEntry lastEntry} methods of this interface, respectively. Its {@link + * SequencedCollection#removeFirst removeFirst} and {@link SequencedCollection#removeLast removeLast} + * methods are implemented in terms of the {@link #pollFirstEntry pollFirstEntry} and + * {@link #pollLastEntry pollLastEntry} methods of this interface, respectively. * Its {@link SequencedCollection#reversed reversed} method returns the {@link * #sequencedValues sequencedValues} view of the {@link #reversed reversed} view of * this map. Its {@link Object#equals equals} and {@link Object#hashCode hashCode} methods @@ -313,6 +337,16 @@ Collection view() { public SequencedCollection reversed() { return SequencedMap.this.reversed().sequencedValues(); } + public void addFirst(V v) { throw new UnsupportedOperationException(); } + public void addLast(V v) { throw new UnsupportedOperationException(); } + public V getFirst() { return nsee(SequencedMap.this.firstEntry()).getValue(); } + public V getLast() { return nsee(SequencedMap.this.lastEntry()).getValue(); } + public V removeFirst() { + return nsee(SequencedMap.this.pollFirstEntry()).getValue(); + } + public V removeLast() { + return nsee(SequencedMap.this.pollLastEntry()).getValue(); + } } return new SeqValues(); } @@ -322,8 +356,15 @@ public SequencedCollection reversed() { * * @implSpec * The implementation in this interface returns a {@code SequencedSet} instance - * that behaves as follows. Its {@link SequencedSet#add add} and {@link - * SequencedSet#addAll addAll} methods throw {@link UnsupportedOperationException}. + * that behaves as follows. Its {@link SequencedSet#add add}, {@link + * SequencedSet#addAll addAll}, {@link SequencedSet#addFirst addFirst}, and {@link + * SequencedSet#addLast addLast} methods throw {@link UnsupportedOperationException}. + * Its {@link SequencedSet#getFirst getFirst} and {@link SequencedSet#getLast getLast} + * methods are implemented in terms of the {@link #firstEntry firstEntry} and {@link + * #lastEntry lastEntry} methods of this interface, respectively. Its {@link + * SequencedSet#removeFirst removeFirst} and {@link SequencedSet#removeLast removeLast} + * methods are implemented in terms of the {@link #pollFirstEntry pollFirstEntry} and + * {@link #pollLastEntry pollLastEntry} methods of this interface, respectively. * Its {@link SequencedSet#reversed reversed} method returns the {@link * #sequencedEntrySet sequencedEntrySet} view of the {@link #reversed reversed} view of * this map. Each of its other methods calls the corresponding method of the {@link @@ -346,6 +387,16 @@ public boolean equals(Object other) { public int hashCode() { return view().hashCode(); } + public void addFirst(Map.Entry e) { throw new UnsupportedOperationException(); } + public void addLast(Map.Entry e) { throw new UnsupportedOperationException(); } + public Map.Entry getFirst() { return nsee(SequencedMap.this.firstEntry()); } + public Map.Entry getLast() { return nsee(SequencedMap.this.lastEntry()); } + public Map.Entry removeFirst() { + return nsee(SequencedMap.this.pollFirstEntry()); + } + public Map.Entry removeLast() { + return nsee(SequencedMap.this.pollLastEntry()); + } } return new SeqEntrySet(); } diff --git a/src/java.base/share/classes/java/util/UUID.java b/src/java.base/share/classes/java/util/UUID.java index db0dbe28802..5961fce9cb2 100644 --- a/src/java.base/share/classes/java/util/UUID.java +++ b/src/java.base/share/classes/java/util/UUID.java @@ -31,7 +31,7 @@ import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; -import jdk.internal.util.HexDigits; +import jdk.internal.util.ByteArrayLittleEndian; /** * A class that represents an immutable universally unique identifier (UUID). @@ -76,7 +76,6 @@ * @since 1.5 */ public final class UUID implements java.io.Serializable, Comparable { - /** * Explicit serialVersionUID for interoperability. */ @@ -462,31 +461,108 @@ public long node() { */ @Override public String toString() { - int i0 = (int) (mostSigBits >> 32); - int i1 = (int) mostSigBits; - int i2 = (int) (leastSigBits >> 32); - int i3 = (int) leastSigBits; - byte[] buf = new byte[36]; - HexDigits.put4(buf, 0, i0 >> 16); - HexDigits.put4(buf, 4, i0); buf[8] = '-'; - HexDigits.put4(buf, 9, i1 >> 16); buf[13] = '-'; - HexDigits.put4(buf, 14, i1); buf[18] = '-'; - HexDigits.put4(buf, 19, i2 >> 16); buf[23] = '-'; - HexDigits.put4(buf, 24, i2); - HexDigits.put4(buf, 28, i3 >> 16); - HexDigits.put4(buf, 32, i3); + + // Although the UUID byte ordering is defined to be big-endian, ByteArrayLittleEndian is used here to optimize + // for the most common architectures. hex8 reverses the order internally. + ByteArrayLittleEndian.setLong(buf, 0, hex8(mostSigBits >>> 32)); + long x0 = hex8(mostSigBits); + ByteArrayLittleEndian.setInt(buf, 9, (int) x0); + ByteArrayLittleEndian.setInt(buf, 14, (int) (x0 >>> 32)); + + long x1 = hex8(leastSigBits >>> 32); + ByteArrayLittleEndian.setInt(buf, 19, (int) (x1)); + ByteArrayLittleEndian.setInt(buf, 24, (int) (x1 >>> 32)); + ByteArrayLittleEndian.setLong(buf, 28, hex8(leastSigBits)); + try { - return jla.newStringNoRepl(buf, StandardCharsets.ISO_8859_1); + return jla.uncheckedNewStringNoRepl(buf, StandardCharsets.ISO_8859_1); } catch (CharacterCodingException cce) { throw new AssertionError(cce); } } + /** + * Efficiently converts 8 hexadecimal digits to their ASCII representation using SIMD-style vector operations. + * This method processes multiple digits in parallel by treating a long value as eight 8-bit lanes, + * achieving significantly better performance compared to traditional loop-based conversion. + * + *

              The conversion algorithm works as follows: + *

              +     * 1. Input expansion: Each 4-bit hex digit is expanded to 8 bits
              +     * 2. Vector processing:
              +     *    - Add 6 to each digit: triggers carry flag for a-f digits
              +     *    - Mask with 0x10 pattern to isolate carry flags
              +     *    - Calculate ASCII adjustment: (carry << 1) + (carry >> 1) - (carry >> 4)
              +     *    - Add ASCII '0' base (0x30) and original value
              +     * 3. Byte order adjustment for final output
              +     * 
              + * + *

              Performance characteristics: + *

                + *
              • Processes 8 digits in parallel using vector operations + *
              • Avoids branching and loops completely + *
              • Uses only integer arithmetic and bit operations + *
              • Constant time execution regardless of input values + *
              + * + *

              ASCII conversion mapping: + *

                + *
              • Digits 0-9 → ASCII '0'-'9' (0x30-0x39) + *
              • Digits a-f → ASCII 'a'-'f' (0x61-0x66) + *
              + * + * @param input A long containing 8 hex digits (each digit must be 0-15) + * @return A long containing 8 ASCII bytes representing the hex digits + * + * @implNote The implementation leverages CPU vector processing capabilities through + * long integer operations. The algorithm is based on the observation that + * ASCII hex digits have a specific pattern that can be computed efficiently + * using carry flag manipulation. + * + * @example + *
              +     * Input:  0xABCDEF01
              +     * Output: 3130666564636261 ('1','0','f','e','d','c','b','a' in ASCII)
              +     * 
              + * + * @see Long#reverseBytes(long) + */ + private static long hex8(long i) { + // Expand each 4-bit group into 8 bits, spreading them out in the long value: 0xAABBCCDD -> 0xA0A0B0B0C0C0D0D + i = Long.expand(i, 0x0F0F_0F0F_0F0F_0F0FL); + + /* + * This method efficiently converts 8 hexadecimal digits simultaneously using vector operations + * The algorithm works as follows: + * + * For input values 0-15: + * - For digits 0-9: converts to ASCII '0'-'9' (0x30-0x39) + * - For digits 10-15: converts to ASCII 'a'-'f' (0x61-0x66) + * + * The conversion process: + * 1. Add 6 to each 4-bit group: i + 0x0606_0606_0606_0606L + * 2. Mask to get the adjustment flags: & 0x1010_1010_1010_1010L + * 3. Calculate the offset: (m << 1) + (m >> 1) - (m >> 4) + * - For 0-9: offset = 0 + * - For a-f: offset = 39 (to bridge the gap between '9' and 'a' in ASCII) + * 4. Add ASCII '0' base (0x30) and the original value + * 5. Reverse byte order for correct positioning + */ + long m = (i + 0x0606_0606_0606_0606L) & 0x1010_1010_1010_1010L; + + // Calculate final ASCII values and reverse bytes for proper ordering + return Long.reverseBytes( + ((m << 1) + (m >> 1) - (m >> 4)) + + 0x3030_3030_3030_3030L // Add ASCII '0' base to all digits + + i // Add original values + ); + } + /** * Returns a hash code for this {@code UUID}. * diff --git a/src/java.base/share/classes/java/util/WeakHashMap.java b/src/java.base/share/classes/java/util/WeakHashMap.java index 276e8731d84..7f2960eb2ad 100644 --- a/src/java.base/share/classes/java/util/WeakHashMap.java +++ b/src/java.base/share/classes/java/util/WeakHashMap.java @@ -132,7 +132,7 @@ * @see java.util.HashMap * @see java.lang.ref.WeakReference */ -public class WeakHashMap +public class WeakHashMap<@jdk.internal.RequiresIdentity K,V> extends AbstractMap implements Map { @@ -457,7 +457,7 @@ Entry getEntry(Object key) { * (A {@code null} return can also indicate that the map * previously associated {@code null} with {@code key}.) */ - public V put(K key, V value) { + public V put(@jdk.internal.RequiresIdentity K key, V value) { Object k = maskNull(key); int h = hash(k); Entry[] tab = getTable(); diff --git a/src/java.base/share/classes/java/util/concurrent/AbstractExecutorService.java b/src/java.base/share/classes/java/util/concurrent/AbstractExecutorService.java index 1b1ba4b29a0..0d26607591d 100644 --- a/src/java.base/share/classes/java/util/concurrent/AbstractExecutorService.java +++ b/src/java.base/share/classes/java/util/concurrent/AbstractExecutorService.java @@ -41,6 +41,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Objects; /** * Provides default implementations of {@link ExecutorService} @@ -119,7 +120,7 @@ protected RunnableFuture newTaskFor(Callable callable) { */ @Override public Future submit(Runnable task) { - if (task == null) throw new NullPointerException(); + Objects.requireNonNull(task, "task"); RunnableFuture ftask = newTaskFor(task, null); execute(ftask); return ftask; @@ -131,7 +132,7 @@ public Future submit(Runnable task) { */ @Override public Future submit(Runnable task, T result) { - if (task == null) throw new NullPointerException(); + Objects.requireNonNull(task, "task"); RunnableFuture ftask = newTaskFor(task, result); execute(ftask); return ftask; @@ -143,7 +144,7 @@ public Future submit(Runnable task, T result) { */ @Override public Future submit(Callable task) { - if (task == null) throw new NullPointerException(); + Objects.requireNonNull(task, "task"); RunnableFuture ftask = newTaskFor(task); execute(ftask); return ftask; @@ -155,11 +156,10 @@ public Future submit(Callable task) { private T doInvokeAny(Collection> tasks, boolean timed, long nanos) throws InterruptedException, ExecutionException, TimeoutException { - if (tasks == null) - throw new NullPointerException(); + Objects.requireNonNull(tasks, "tasks"); int ntasks = tasks.size(); if (ntasks == 0) - throw new IllegalArgumentException(); + throw new IllegalArgumentException("tasks is empty"); ArrayList> futures = new ArrayList<>(ntasks); ExecutorCompletionService ecs = new ExecutorCompletionService(this); @@ -262,8 +262,7 @@ public T invokeAny(Collection> tasks, @Override public List> invokeAll(Collection> tasks) throws InterruptedException { - if (tasks == null) - throw new NullPointerException(); + Objects.requireNonNull(tasks, "tasks"); ArrayList> futures = new ArrayList<>(tasks.size()); try { for (Callable t : tasks) { @@ -294,8 +293,8 @@ public List> invokeAll(Collection> tasks) public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { - if (tasks == null) - throw new NullPointerException(); + Objects.requireNonNull(tasks, "tasks"); + Objects.requireNonNull(unit, "unit"); final long nanos = unit.toNanos(timeout); final long deadline = System.nanoTime() + nanos; ArrayList> futures = new ArrayList<>(tasks.size()); diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java index 649eaa563c7..0b0db4e8120 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListSet.java @@ -35,7 +35,9 @@ package java.util.concurrent; -import java.lang.reflect.Field; +import jdk.internal.misc.Unsafe; + +import java.lang.invoke.VarHandle; import java.util.AbstractSet; import java.util.Collection; import java.util.Collections; @@ -176,6 +178,8 @@ public ConcurrentSkipListSet clone() { ConcurrentSkipListSet clone = (ConcurrentSkipListSet) super.clone(); clone.setMap(new ConcurrentSkipListMap(m)); + // Needed to ensure safe publication of setMap() + VarHandle.releaseFence(); return clone; } catch (CloneNotSupportedException e) { throw new InternalError(); @@ -527,12 +531,11 @@ public Spliterator spliterator() { /** Initializes map field; for use in clone. */ private void setMap(ConcurrentNavigableMap map) { - try { - Field mapField = ConcurrentSkipListSet.class.getDeclaredField("m"); - mapField.setAccessible(true); - mapField.set(this, map); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new Error(e); - } + final Unsafe U = Unsafe.getUnsafe(); + U.putReference( + this, + U.objectFieldOffset(ConcurrentSkipListSet.class, "m"), + map + ); } } diff --git a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java index 2d3bdb429e9..9024fca8024 100644 --- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java +++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java @@ -35,7 +35,6 @@ package java.util.concurrent; import java.lang.invoke.VarHandle; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -57,6 +56,7 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.Unsafe; import jdk.internal.util.ArraysSupport; /** @@ -2095,12 +2095,11 @@ public List reversed() { /** Initializes the lock; for use when deserializing or cloning. */ private void resetLock() { - try { - Field lockField = CopyOnWriteArrayList.class.getDeclaredField("lock"); - lockField.setAccessible(true); - lockField.set(this, new Object()); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new Error(e); - } + final Unsafe U = Unsafe.getUnsafe(); + U.putReference( + this, + U.objectFieldOffset(CopyOnWriteArrayList.class, "lock"), + new Object() + ); } } diff --git a/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java b/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java index 3c09b4882d0..249c2ebf4d9 100644 --- a/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java +++ b/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java @@ -35,6 +35,8 @@ package java.util.concurrent; +import java.util.Objects; + /** * A {@link CompletionService} that uses a supplied {@link Executor} * to execute tasks. This class arranges that submitted tasks are, @@ -145,8 +147,7 @@ private RunnableFuture newTaskFor(Runnable task, V result) { * @throws NullPointerException if executor is {@code null} */ public ExecutorCompletionService(Executor executor) { - if (executor == null) - throw new NullPointerException(); + Objects.requireNonNull(executor, "executor"); this.executor = executor; this.aes = (executor instanceof AbstractExecutorService) ? (AbstractExecutorService) executor : null; @@ -168,8 +169,8 @@ public ExecutorCompletionService(Executor executor) { */ public ExecutorCompletionService(Executor executor, BlockingQueue> completionQueue) { - if (executor == null || completionQueue == null) - throw new NullPointerException(); + Objects.requireNonNull(executor, "executor"); + Objects.requireNonNull(completionQueue, "completionQueue"); this.executor = executor; this.aes = (executor instanceof AbstractExecutorService) ? (AbstractExecutorService) executor : null; @@ -181,7 +182,7 @@ public ExecutorCompletionService(Executor executor, * @throws NullPointerException {@inheritDoc} */ public Future submit(Callable task) { - if (task == null) throw new NullPointerException(); + Objects.requireNonNull(task, "task"); RunnableFuture f = newTaskFor(task); executor.execute(new QueueingFuture(f, completionQueue)); return f; @@ -192,7 +193,7 @@ public Future submit(Callable task) { * @throws NullPointerException {@inheritDoc} */ public Future submit(Runnable task, V result) { - if (task == null) throw new NullPointerException(); + Objects.requireNonNull(task, "task"); RunnableFuture f = newTaskFor(task, result); executor.execute(new QueueingFuture(f, completionQueue)); return f; diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index eac0f5bdc18..a7821921bc9 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -3452,9 +3452,9 @@ private DelayScheduler startDelayScheduler() { String name = poolName + "-delayScheduler"; if (workerNamePrefix == null) asyncCommonPool(); // override common parallelism zero - lockRunState(); + long isShutdown = lockRunState() & SHUTDOWN; try { - if ((ds = delayScheduler) == null) { + if (isShutdown == 0L && (ds = delayScheduler) == null) { ds = delayScheduler = new DelayScheduler(this, name); start = true; } @@ -3462,12 +3462,20 @@ private DelayScheduler startDelayScheduler() { unlockRunState(); } if (start) { // start outside of lock - // exceptions on start passed to (external) callers SharedThreadContainer ctr; - if ((ctr = container) != null) - ctr.start(ds); - else - ds.start(); + try { + if ((ctr = container) != null) + ctr.start(ds); + else + ds.start(); + } catch (RuntimeException | Error ex) { // back out + lockRunState(); + ds = delayScheduler = null; + unlockRunState(); + tryTerminate(false, false); + if (ex instanceof Error) + throw ex; + } } } return ds; diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java index 5f2dcb30d41..51b2488264e 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java @@ -131,11 +131,11 @@ * (including the case where a task was cancelled without executing); * {@link #isCompletedNormally} is true if a task completed without * cancellation or encountering an exception; {@link #isCancelled} is - * true if the task was cancelled (in which case {@link #getException} + * true if the task was cancelled (in which case {@link #getException()} * returns a {@link CancellationException}); and * {@link #isCompletedAbnormally} is true if a task was either * cancelled or encountered an exception, in which case {@link - * #getException} will return either the encountered exception or + * #getException()} will return either the encountered exception or * {@link CancellationException}. * *

              The ForkJoinTask class is not usually directly subclassed. diff --git a/src/java.base/share/classes/java/util/concurrent/Joiners.java b/src/java.base/share/classes/java/util/concurrent/Joiners.java new file mode 100644 index 00000000000..768e260803e --- /dev/null +++ b/src/java.base/share/classes/java/util/concurrent/Joiners.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.util.concurrent; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.concurrent.StructuredTaskScope.Joiner; +import java.util.concurrent.StructuredTaskScope.Subtask; +import java.util.function.Predicate; +import java.util.stream.Stream; +import jdk.internal.invoke.MhUtil; + +/** + * Built-in StructuredTaskScope.Joiner implementations. + */ +class Joiners { + private Joiners() { } + + /** + * Throws IllegalArgumentException if the subtask is not in the UNAVAILABLE state. + */ + private static void ensureUnavailable(Subtask subtask) { + if (subtask.state() != Subtask.State.UNAVAILABLE) { + throw new IllegalArgumentException("Subtask not in UNAVAILABLE state"); + } + } + + /** + * Throws IllegalArgumentException if the subtask has not completed. + */ + private static Subtask.State ensureCompleted(Subtask subtask) { + Subtask.State state = subtask.state(); + if (state == Subtask.State.UNAVAILABLE) { + throw new IllegalArgumentException("Subtask has not completed"); + } + return state; + } + + /** + * A joiner that returns a stream of all subtasks when all subtasks complete + * successfully. Cancels the scope if any subtask fails. + */ + static final class AllSuccessful implements Joiner>> { + private static final VarHandle FIRST_EXCEPTION = + MhUtil.findVarHandle(MethodHandles.lookup(), "firstException", Throwable.class); + + // list of forked subtasks, only accessed by owner thread + private final List> subtasks = new ArrayList<>(); + + private volatile Throwable firstException; + + @Override + public boolean onFork(Subtask subtask) { + ensureUnavailable(subtask); + @SuppressWarnings("unchecked") + var s = (Subtask) subtask; + subtasks.add(s); + return false; + } + + @Override + public boolean onComplete(Subtask subtask) { + Subtask.State state = ensureCompleted(subtask); + return (state == Subtask.State.FAILED) + && (firstException == null) + && FIRST_EXCEPTION.compareAndSet(this, null, subtask.exception()); + } + + @Override + public Stream> result() throws Throwable { + Throwable ex = firstException; + if (ex != null) { + throw ex; + } else { + return subtasks.stream(); + } + } + } + + /** + * A joiner that returns the result of the first subtask to complete successfully. + * Cancels the scope if any subtasks succeeds. + */ + static final class AnySuccessful implements Joiner { + private static final VarHandle SUBTASK = + MhUtil.findVarHandle(MethodHandles.lookup(), "subtask", Subtask.class); + + // UNAVAILABLE < FAILED < SUCCESS + private static final Comparator SUBTASK_STATE_COMPARATOR = + Comparator.comparingInt(AnySuccessful::stateToInt); + + private volatile Subtask subtask; + + /** + * Maps a Subtask.State to an int that can be compared. + */ + private static int stateToInt(Subtask.State s) { + return switch (s) { + case UNAVAILABLE -> 0; + case FAILED -> 1; + case SUCCESS -> 2; + }; + } + + @Override + public boolean onComplete(Subtask subtask) { + Subtask.State state = ensureCompleted(subtask); + Subtask s; + while (((s = this.subtask) == null) + || SUBTASK_STATE_COMPARATOR.compare(s.state(), state) < 0) { + if (SUBTASK.compareAndSet(this, s, subtask)) { + return (state == Subtask.State.SUCCESS); + } + } + return false; + } + + @Override + public T result() throws Throwable { + Subtask subtask = this.subtask; + if (subtask == null) { + throw new NoSuchElementException("No subtasks completed"); + } + return switch (subtask.state()) { + case SUCCESS -> subtask.get(); + case FAILED -> throw subtask.exception(); + default -> throw new InternalError(); + }; + } + } + + /** + * A joiner that that waits for all successful subtasks. Cancels the scope if any + * subtask fails. + */ + static final class AwaitSuccessful implements Joiner { + private static final VarHandle FIRST_EXCEPTION = + MhUtil.findVarHandle(MethodHandles.lookup(), "firstException", Throwable.class); + private volatile Throwable firstException; + + @Override + public boolean onComplete(Subtask subtask) { + Subtask.State state = ensureCompleted(subtask); + return (state == Subtask.State.FAILED) + && (firstException == null) + && FIRST_EXCEPTION.compareAndSet(this, null, subtask.exception()); + } + + @Override + public Void result() throws Throwable { + Throwable ex = firstException; + if (ex != null) { + throw ex; + } else { + return null; + } + } + } + + /** + * A joiner that returns a stream of all subtasks. + */ + static final class AllSubtasks implements Joiner>> { + private final Predicate> isDone; + + // list of forked subtasks, only accessed by owner thread + private final List> subtasks = new ArrayList<>(); + + AllSubtasks(Predicate> isDone) { + this.isDone = Objects.requireNonNull(isDone); + } + + @Override + public boolean onFork(Subtask subtask) { + ensureUnavailable(subtask); + @SuppressWarnings("unchecked") + var s = (Subtask) subtask; + subtasks.add(s); + return false; + } + + @Override + public boolean onComplete(Subtask subtask) { + ensureCompleted(subtask); + return isDone.test(subtask); + } + + @Override + public Stream> result() { + return subtasks.stream(); + } + } +} diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java index 41c6b4914b9..fb16e0a615e 100644 --- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,315 +24,348 @@ */ package java.util.concurrent; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; import java.time.Duration; -import java.time.Instant; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.stream.Stream; import jdk.internal.javac.PreviewFeature; -import jdk.internal.misc.ThreadFlock; -import jdk.internal.invoke.MhUtil; /** - * A basic API for structured concurrency. {@code StructuredTaskScope} supports - * cases where a task splits into several concurrent subtasks, and where the subtasks must - * complete before the main task continues. A {@code StructuredTaskScope} can be used to - * ensure that the lifetime of a concurrent operation is confined by a syntax block, - * just like that of a sequential operation in structured programming. - * - *

              Basic operation

              - * - * A {@code StructuredTaskScope} is created with one of its public constructors. It defines - * the {@link #fork(Callable) fork} method to start a thread to execute a subtask, the {@link - * #join() join} method to wait for all subtasks to finish, and the {@link #close() close} - * method to close the task scope. The API is intended to be used with the {@code - * try-with-resources} statement. The intention is that code in the try block - * uses the {@code fork} method to fork threads to execute the subtasks, wait for the - * subtasks to finish with the {@code join} method, and then process the results. - * A call to the {@code fork} method returns a {@link Subtask Subtask} to representing - * the forked subtask. Once {@code join} is called, the {@code Subtask} can be - * used to get the result completed successfully, or the exception if the subtask failed. - * {@snippet lang=java : - * Callable task1 = ... - * Callable task2 = ... + * An API for structured concurrency. {@code StructuredTaskScope} supports cases + * where execution of a task (a unit of work) splits into several concurrent + * subtasks, and where the subtasks must complete before the task continues. A {@code + * StructuredTaskScope} can be used to ensure that the lifetime of a concurrent operation + * is confined by a syntax block, similar to that of a sequential operation in + * structured programming. + * + *

              {@code StructuredTaskScope} defines the static method {@link #open() open} to open + * a new {@code StructuredTaskScope} and the {@link #close() close} method to close it. + * The API is designed to be used with the {@code try}-with-resources statement where + * the {@code StructuredTaskScope} is opened as a resource and then closed automatically. + * The code inside the block uses the {@link #fork(Callable) fork} method to fork subtasks. + * After forking, it uses the {@link #join() join} method to wait for all subtasks to + * finish (or some other outcome) as a single operation. Forking a subtask starts a new + * {@link Thread} to run the subtask. The thread executing the task does not continue + * beyond the {@code close} method until all threads started to execute subtasks have finished. + * To ensure correct usage, the {@code fork}, {@code join} and {@code close} methods may + * only be invoked by the owner thread (the thread that opened the {@code + * StructuredTaskScope}), the {@code fork} method may not be called after {@code join}, + * the {@code join} method may only be invoked once, and the {@code close} method throws + * an exception after closing if the owner did not invoke the {@code join} method after + * forking subtasks. * - * try (var scope = new StructuredTaskScope()) { + *

              As a first example, consider a task that splits into two subtasks to concurrently + * fetch resources from two URL locations "left" and "right". Both subtasks may complete + * successfully, one subtask may succeed and the other may fail, or both subtasks may + * fail. The task in this example is interested in the successful result from both + * subtasks. It waits in the {@link #join() join} method for both subtasks to complete + * successfully or for either subtask to fail. + * {@snippet lang=java : + * // @link substring="open" target="#open()" : + * try (var scope = StructuredTaskScope.open()) { * - * Subtask subtask1 = scope.fork(task1); // @highlight substring="fork" - * Subtask subtask2 = scope.fork(task2); // @highlight substring="fork" + * // @link substring="fork" target="#fork(Callable)" : + * Subtask subtask1 = scope.fork(() -> query(left)); + * Subtask subtask2 = scope.fork(() -> query(right)); * - * scope.join(); // @highlight substring="join" + * // throws if either subtask fails + * scope.join(); // @link substring="join" target="#join()" * - * ... process results/exceptions ... + * // both subtasks completed successfully + * // @link substring="get" target="Subtask#get()" : + * return new MyResult(subtask1.get(), subtask2.get()); * - * } // close // @highlight substring="close" + * // @link substring="close" target="#close()" : + * } // close * } - *

              The following example forks a collection of homogeneous subtasks, waits for all of - * them to complete with the {@code join} method, and uses the {@link Subtask.State - * Subtask.State} to partition the subtasks into a set of the subtasks that completed - * successfully and another for the subtasks that failed. - * {@snippet lang=java : - * List> callables = ... * - * try (var scope = new StructuredTaskScope()) { + *

              If both subtasks complete successfully then the {@code join} method completes + * normally and the task uses the {@link Subtask#get() Subtask.get()} method to get + * the result of each subtask. If one of the subtasks fails then the other subtask is + * cancelled (this will {@linkplain Thread#interrupt() interrupt} the thread executing the + * other subtask) and the {@code join} method throws {@link FailedException} with the + * exception from the failed subtask as the {@linkplain Throwable#getCause() cause}. + * + *

              To allow for cancellation, subtasks must be coded so that they finish as soon as + * possible when interrupted. Subtasks that do not respond to interrupt, e.g. block on + * methods that are not interruptible, may delay the closing of a scope indefinitely. The + * {@link #close() close} method always waits for threads executing subtasks to finish, + * even if the scope is cancelled, so execution cannot continue beyond the {@code close} + * method until the interrupted threads finish. + * + *

              In the example, the subtasks produce results of different types ({@code String} and + * {@code Integer}). In other cases the subtasks may all produce results of the same type. + * If the example had used {@code StructuredTaskScope.open()} then it could + * only be used to fork subtasks that return a {@code String} result. * - * List> subtasks = callables.stream().map(scope::fork).toList(); + *

              Joiners

              * - * scope.join(); + *

              In the example above, the task fails if any subtask fails. If all subtasks + * succeed then the {@code join} method completes normally. Other policy and outcome is + * supported by creating a {@code StructuredTaskScope} with a {@link Joiner} that + * implements the desired policy. A {@code Joiner} handles subtask completion and produces + * the outcome for the {@link #join() join} method. In the example above, {@code join} + * returns {@code null}. Depending on the {@code Joiner}, {@code join} may return a + * result, a stream of elements, or some other object. The {@code Joiner} interface defines + * factory methods to create {@code Joiner}s for some common cases. * - * Map>> map = subtasks.stream() - * .collect(Collectors.partitioningBy(h -> h.state() == Subtask.State.SUCCESS, - * Collectors.toSet())); + *

              A {@code Joiner} may cancel the scope (sometimes called + * "short-circuiting") when some condition is reached that does not require the result of + * subtasks that are still executing. Cancelling the scope prevents new threads from being + * started to execute further subtasks, {@linkplain Thread#interrupt() interrupts} the + * threads executing subtasks that have not completed, and causes the {@code join} method + * to wakeup with the outcome (result or exception). In the above example, the outcome is + * that {@code join} completes with a result of {@code null} when all subtasks succeed. + * The scope is cancelled if any of the subtasks fail and {@code join} throws {@code + * FailedException} with the exception from the failed subtask as the cause. Other {@code + * Joiner} implementations may cancel the scope for other reasons. * - * } // close + *

              Now consider another example that splits into two subtasks. In this example, + * each subtask produces a {@code String} result and the task is only interested in + * the result from the first subtask to complete successfully. The example uses {@link + * Joiner#anySuccessfulResultOrThrow() Joiner.anySuccessfulResultOrThrow()} to + * create a {@code Joiner} that makes available the result of the first subtask to + * complete successfully. The type parameter in the example is "{@code String}" so that + * only subtasks that return a {@code String} can be forked. + * {@snippet lang=java : + * // @link substring="open" target="#open(Joiner)" : + * try (var scope = StructuredTaskScope.open(Joiner.anySuccessfulResultOrThrow())) { + * + * scope.fork(callable1); + * scope.fork(callable2); + * + * // throws if both subtasks fail + * String firstResult = scope.join(); + * + * } * } * - *

              To ensure correct usage, the {@code join} and {@code close} methods may only be - * invoked by the owner (the thread that opened/created the task scope), and the - * {@code close} method throws an exception after closing if the owner did not invoke the - * {@code join} method after forking. - * - *

              {@code StructuredTaskScope} defines the {@link #shutdown() shutdown} method to shut - * down a task scope without closing it. The {@code shutdown()} method cancels all - * unfinished subtasks by {@linkplain Thread#interrupt() interrupting} the threads. It - * prevents new threads from starting in the task scope. If the owner is waiting in the - * {@code join} method then it will wakeup. - * - *

              Shutdown is used for short-circuiting and allow subclasses to implement - * policy that does not require all subtasks to finish. - * - *

              Subclasses with policies for common cases

              - * - * Two subclasses of {@code StructuredTaskScope} are defined to implement policy for - * common cases: - *
                - *
              1. {@link ShutdownOnSuccess ShutdownOnSuccess} captures the result of the first - * subtask to complete successfully. Once captured, it shuts down the task scope to - * interrupt unfinished threads and wakeup the owner. This class is intended for cases - * where the result of any subtask will do ("invoke any") and where there is no need to - * wait for results of other unfinished subtasks. It defines methods to get the first - * result or throw an exception if all subtasks fail. - *
              2. {@link ShutdownOnFailure ShutdownOnFailure} captures the exception of the first - * subtask to fail. Once captured, it shuts down the task scope to interrupt unfinished - * threads and wakeup the owner. This class is intended for cases where the results of all - * subtasks are required ("invoke all"); if any subtask fails then the results of other - * unfinished subtasks are no longer needed. If defines methods to throw an exception if - * any of the subtasks fail. - *
              - * - *

              The following are two examples that use the two classes. In both cases, a pair of - * subtasks are forked to fetch resources from two URL locations "left" and "right". The - * first example creates a ShutdownOnSuccess object to capture the result of the first - * subtask to complete successfully, cancelling the other by way of shutting down the task - * scope. The main task waits in {@code join} until either subtask completes with a result - * or both subtasks fail. It invokes {@link ShutdownOnSuccess#result(Function) - * result(Function)} method to get the captured result. If both subtasks fail then this - * method throws a {@code WebApplicationException} with the exception from one of the - * subtasks as the cause. + *

              In the example, the task forks the two subtasks, then waits in the {@code + * join} method for either subtask to complete successfully or for both subtasks to fail. + * If one of the subtasks completes successfully then the {@code Joiner} causes the other + * subtask to be cancelled (this will interrupt the thread executing the subtask), and + * the {@code join} method returns the result from the successful subtask. Cancelling the + * other subtask avoids the task waiting for a result that it doesn't care about. If + * both subtasks fail then the {@code join} method throws {@code FailedException} with the + * exception from one of the subtasks as the {@linkplain Throwable#getCause() cause}. + * + *

              Whether code uses the {@code Subtask} returned from {@code fork} will depend on + * the {@code Joiner} and usage. Some {@code Joiner} implementations are suited to subtasks + * that return results of the same type and where the {@code join} method returns a result + * for the task to use. Code that forks subtasks that return results of different + * types, and uses a {@code Joiner} such as {@code Joiner.awaitAllSuccessfulOrThrow()} that + * does not return a result, will use {@link Subtask#get() Subtask.get()} after joining. + * + *

              Exception handling

              + * + *

              A {@code StructuredTaskScope} is opened with a {@link Joiner Joiner} that + * handles subtask completion and produces the outcome for the {@link #join() join} method. + * In some cases, the outcome will be a result, in other cases it will be an exception. + * If the outcome is an exception then the {@code join} method throws {@link + * FailedException} with the exception as the {@linkplain Throwable#getCause() + * cause}. For many {@code Joiner} implementations, the exception will be an exception + * thrown by a subtask that failed. In the case of {@link Joiner#allSuccessfulOrThrow() + * allSuccessfulOrThrow} and {@link Joiner#awaitAllSuccessfulOrThrow() awaitAllSuccessfulOrThrow} + * for example, the exception is from the first subtask to fail. + * + *

              Many of the details for how exceptions are handled will depend on usage. In some + * cases it may be useful to add a {@code catch} block to the {@code try}-with-resources + * statement to catch {@code FailedException}. The exception handling may use {@code + * instanceof} with pattern matching to handle specific causes. * {@snippet lang=java : - * try (var scope = new StructuredTaskScope.ShutdownOnSuccess()) { + * try (var scope = StructuredTaskScope.open()) { * - * scope.fork(() -> fetch(left)); - * scope.fork(() -> fetch(right)); + * .. * - * scope.join(); + * } catch (StructuredTaskScope.FailedException e) { * - * // @link regex="result(?=\()" target="ShutdownOnSuccess#result" : - * String result = scope.result(e -> new WebApplicationException(e)); + * Throwable cause = e.getCause(); + * switch (cause) { + * case IOException ioe -> .. + * default -> .. + * } * - * ... - * } + * } * } - * The second example creates a ShutdownOnFailure object to capture the exception of the - * first subtask to fail, cancelling the other by way of shutting down the task scope. The - * main task waits in {@link #joinUntil(Instant)} until both subtasks complete with a - * result, either fails, or a deadline is reached. It invokes {@link - * ShutdownOnFailure#throwIfFailed(Function) throwIfFailed(Function)} to throw an exception - * if either subtask fails. This method is a no-op if both subtasks complete successfully. - * The example uses {@link Supplier#get()} to get the result of each subtask. Using - * {@code Supplier} instead of {@code Subtask} is preferred for common cases where the - * object returned by fork is only used to get the result of a subtask that completed - * successfully. - * {@snippet lang=java : - * Instant deadline = ... + * In other cases it may not be useful to catch {@code FailedException} but instead leave + * it to propagate to the configured {@linkplain Thread.UncaughtExceptionHandler uncaught + * exception handler} for logging purposes. + * + *

              For cases where a specific exception triggers the use of a default result then it + * may be more appropriate to handle this in the subtask itself rather than the subtask + * failing and the scope owner handling the exception. + * + *

              Configuration

              * - * try (var scope = new StructuredTaskScope.ShutdownOnFailure()) { * - * Supplier supplier1 = scope.fork(() -> query(left)); - * Supplier supplier2 = scope.fork(() -> query(right)); + * A {@code StructuredTaskScope} is opened with {@linkplain Configuration configuration} + * that consists of a {@link ThreadFactory} to create threads, an optional name for + * monitoring and management purposes, and an optional timeout. * - * scope.joinUntil(deadline); + *

              The {@link #open()} and {@link #open(Joiner)} methods create a {@code StructuredTaskScope} + * with the default configuration. The default + * configuration has a {@code ThreadFactory} that creates unnamed + * virtual threads, + * is unnamed for monitoring and management purposes, and has no timeout. * - * // @link substring="throwIfFailed" target="ShutdownOnFailure#throwIfFailed" : - * scope.throwIfFailed(e -> new WebApplicationException(e)); + *

              The 2-arg {@link #open(Joiner, Function) open} method can be used to create a + * {@code StructuredTaskScope} that uses a different {@code ThreadFactory}, has a name for + * the purposes of monitoring and management, or has a timeout that cancels the scope if + * the timeout expires before or while waiting for subtasks to complete. The {@code open} + * method is called with a {@linkplain Function function} that is applied to the default + * configuration and returns a {@link Configuration Configuration} for the + * {@code StructuredTaskScope} under construction. * - * // both subtasks completed successfully - * String result = Stream.of(supplier1, supplier2) - * .map(Supplier::get) - * .collect(Collectors.joining(", ", "{ ", " }")); + *

              The following example opens a new {@code StructuredTaskScope} with a {@code + * ThreadFactory} that creates virtual threads {@linkplain Thread#setName(String) named} + * "duke-0", "duke-1" ... + * {@snippet lang = java: + * // @link substring="name" target="Thread.Builder#name(String, long)" : + * ThreadFactory factory = Thread.ofVirtual().name("duke-", 0).factory(); + * + * // @link substring="withThreadFactory" target="Configuration#withThreadFactory(ThreadFactory)" : + * try (var scope = StructuredTaskScope.open(joiner, cf -> cf.withThreadFactory(factory))) { + * + * scope.fork( .. ); // runs in a virtual thread with name "duke-0" + * scope.fork( .. ); // runs in a virtual thread with name "duke-1" + * + * scope.join(); * - * ... * } - * } + *} * - *

              Extending StructuredTaskScope

              - * - * {@code StructuredTaskScope} can be extended, and the {@link #handleComplete(Subtask) - * handleComplete} method overridden, to implement policies other than those implemented - * by {@code ShutdownOnSuccess} and {@code ShutdownOnFailure}. A subclass may, for example, - * collect the results of subtasks that complete successfully and ignore subtasks that - * fail. It may collect exceptions when subtasks fail. It may invoke the {@link #shutdown() - * shutdown} method to shut down and cause {@link #join() join} to wakeup when some - * condition arises. - * - *

              A subclass will typically define methods to make available results, state, or other - * outcome to code that executes after the {@code join} method. A subclass that collects - * results and ignores subtasks that fail may define a method that returns the results. - * A subclass that implements a policy to shut down when a subtask fails may define a - * method to get the exception of the first subtask to fail. - * - *

              The following is an example of a simple {@code StructuredTaskScope} implementation - * that collects homogenous subtasks that complete successfully. It defines the method - * "{@code completedSuccessfully()}" that the main task can invoke after it joins. + *

              A second example sets a timeout, represented by a {@link Duration}. The timeout + * starts when the new scope is opened. If the timeout expires before the {@code join} + * method has completed then the scope is cancelled. This + * interrupts the threads executing the two subtasks and causes the {@link #join() join} + * method to throw {@link TimeoutException}. * {@snippet lang=java : - * class CollectingScope extends StructuredTaskScope { - * private final Queue> subtasks = new LinkedTransferQueue<>(); - * - * @Override - * protected void handleComplete(Subtask subtask) { - * if (subtask.state() == Subtask.State.SUCCESS) { - * subtasks.add(subtask); - * } - * } + * Duration timeout = Duration.ofSeconds(10); * - * @Override - * public CollectingScope join() throws InterruptedException { - * super.join(); - * return this; - * } + * // @link substring="allSuccessfulOrThrow" target="Joiner#allSuccessfulOrThrow()" : + * try (var scope = StructuredTaskScope.open(Joiner.allSuccessfulOrThrow(), + * // @link substring="withTimeout" target="Configuration#withTimeout(Duration)" : + * cf -> cf.withTimeout(timeout))) { * - * public Stream> completedSuccessfully() { - * // @link substring="ensureOwnerAndJoined" target="ensureOwnerAndJoined" : - * super.ensureOwnerAndJoined(); - * return subtasks.stream(); - * } - * } + * scope.fork(callable1); + * scope.fork(callable2); + * + * List result = scope.join() + * .map(Subtask::get) + * .toList(); + * + * } * } - *

              The implementations of the {@code completedSuccessfully()} method in the example - * invokes {@link #ensureOwnerAndJoined()} to ensure that the method can only be invoked - * by the owner thread and only after it has joined. - * - *

              Tree structure

              - * - * Task scopes form a tree where parent-child relations are established implicitly when - * opening a new task scope: - *
                - *
              • A parent-child relation is established when a thread started in a task scope - * opens its own task scope. A thread started in task scope "A" that opens task scope - * "B" establishes a parent-child relation where task scope "A" is the parent of task - * scope "B". - *
              • A parent-child relation is established with nesting. If a thread opens task - * scope "B", then opens task scope "C" (before it closes "B"), then the enclosing task - * scope "B" is the parent of the nested task scope "C". - *
              - * - * The descendants of a task scope are the child task scopes that it is a parent - * of, plus the descendants of the child task scopes, recursively. - * - *

              The tree structure supports: - *

                - *
              • Inheritance of {@linkplain ScopedValue scoped values} across threads. - *
              • Confinement checks. The phrase "threads contained in the task scope" in method - * descriptions means threads started in the task scope or descendant scopes. - *
              - * - *

              The following example demonstrates the inheritance of a scoped value. A scoped - * value {@code USERNAME} is bound to the value "{@code duke}". A {@code StructuredTaskScope} - * is created and its {@code fork} method invoked to start a thread to execute {@code - * childTask}. The thread inherits the scoped value bindings captured when - * creating the task scope. The code in {@code childTask} uses the value of the scoped - * value and so reads the value "{@code duke}". + * + *

              Inheritance of scoped value bindings

              + * + * {@link ScopedValue} supports the execution of a method with a {@code ScopedValue} bound + * to a value for the bounded period of execution of the method by the current thread. + * It allows a value to be safely and efficiently shared to methods without using method + * parameters. + * + *

              When used in conjunction with a {@code StructuredTaskScope}, a {@code ScopedValue} + * can also safely and efficiently share a value to methods executed by subtasks forked + * in the scope. When a {@code ScopedValue} object is bound to a value in the thread + * executing the task then that binding is inherited by the threads created to + * execute the subtasks. The thread executing the task does not continue beyond the + * {@link #close() close} method until all threads executing the subtasks have finished. + * This ensures that the {@code ScopedValue} is not reverted to being {@linkplain + * ScopedValue#isBound() unbound} (or its previous value) while subtasks are executing. + * In addition to providing a safe and efficient means to inherit a value into subtasks, + * the inheritance allows sequential code using {@code ScopedValue} be refactored to use + * structured concurrency. + * + *

              To ensure correctness, opening a new {@code StructuredTaskScope} captures the + * current thread's scoped value bindings. These are the scoped values bindings that are + * inherited by the threads created to execute subtasks in the scope. Forking a + * subtask checks that the bindings in effect at the time that the subtask is forked + * match the bindings when the {@code StructuredTaskScope} was created. This check ensures + * that a subtask does not inherit a binding that is reverted in the task before the + * subtask has completed. + * + *

              A {@code ScopedValue} that is shared across threads requires that the value be an + * immutable object or for all access to the value to be appropriately synchronized. + * + *

              The following example demonstrates the inheritance of scoped value bindings. The + * scoped value USERNAME is bound to the value "duke" for the bounded period of a lambda + * expression by the thread executing it. The code in the block opens a {@code + * StructuredTaskScope} and forks two subtasks, it then waits in the {@code join} method + * and aggregates the results from both subtasks. If code executed by the threads + * running subtask1 and subtask2 uses {@link ScopedValue#get()}, to get the value of + * USERNAME, then value "duke" will be returned. * {@snippet lang=java : + * // @link substring="newInstance" target="ScopedValue#newInstance()" : * private static final ScopedValue USERNAME = ScopedValue.newInstance(); * - * // @link substring="run" target="ScopedValue.Carrier#run(Runnable)" : - * ScopedValue.where(USERNAME, "duke").run(() -> { - * try (var scope = new StructuredTaskScope()) { + * // @link substring="where" target="ScopedValue#where(ScopedValue, Object)" : + * MyResult result = ScopedValue.where(USERNAME, "duke").call(() -> { * - * scope.fork(() -> childTask()); // @highlight substring="fork" - * ... - * } - * }); + * try (var scope = StructuredTaskScope.open()) { * - * ... + * Subtask subtask1 = scope.fork( .. ); // inherits binding + * Subtask subtask2 = scope.fork( .. ); // inherits binding * - * String childTask() { - * // @link substring="get" target="ScopedValue#get()" : - * String name = USERNAME.get(); // "duke" - * ... - * } + * scope.join(); + * return new MyResult(subtask1.get(), subtask2.get()); + * } + * + * }); * } * - *

              {@code StructuredTaskScope} does not define APIs that exposes the tree structure - * at this time. + *

              A scoped value inherited into a subtask may be + * rebound to a new + * value in the subtask for the bounded execution of some method executed in the subtask. + * When the method completes, the value of the {@code ScopedValue} reverts to its previous + * value, the value inherited from the thread executing the task. * - *

              Unless otherwise specified, passing a {@code null} argument to a constructor - * or method in this class will cause a {@link NullPointerException} to be thrown. + *

              A subtask may execute code that itself opens a new {@code StructuredTaskScope}. + * A task executing in thread T1 opens a {@code StructuredTaskScope} and forks a + * subtask that runs in thread T2. The scoped value bindings captured when T1 opens the + * scope are inherited into T2. The subtask (in thread T2) executes code that opens a + * new {@code StructuredTaskScope} and forks a subtask that runs in thread T3. The scoped + * value bindings captured when T2 opens the scope are inherited into T3. These + * include (or may be the same) as the bindings that were inherited from T1. In effect, + * scoped values are inherited into a tree of subtasks, not just one level of subtask. * *

              Memory consistency effects

              * - *

              Actions in the owner thread of, or a thread contained in, the task scope prior to + *

              Actions in the owner thread of a {@code StructuredTaskScope} prior to * {@linkplain #fork forking} of a subtask * - * happen-before any actions taken by that subtask, which in turn happen-before - * the subtask result is {@linkplain Subtask#get() retrieved} or happen-before any - * actions taken in a thread after {@linkplain #join() joining} of the task scope. + * happen-before any actions taken by that subtask, which in turn + * happen-before the subtask result is {@linkplain Subtask#get() retrieved}. * - * @jls 17.4.5 Happens-before Order + *

              General exceptions

              + * + *

              Unless otherwise specified, passing a {@code null} argument to a method in this + * class will cause a {@link NullPointerException} to be thrown. + * + * @param the result type of subtasks executed in the scope + * @param the result type of the scope * - * @param the result type of tasks executed in the task scope + * @jls 17.4.5 Happens-before Order * @since 21 */ @PreviewFeature(feature = PreviewFeature.Feature.STRUCTURED_CONCURRENCY) -public class StructuredTaskScope implements AutoCloseable { - private final ThreadFactory factory; - private final ThreadFlock flock; - private final ReentrantLock shutdownLock = new ReentrantLock(); - - // states: OPEN -> SHUTDOWN -> CLOSED - private static final int OPEN = 0; // initial state - private static final int SHUTDOWN = 1; - private static final int CLOSED = 2; - - // state: set to SHUTDOWN by any thread, set to CLOSED by owner, read by any thread - private volatile int state; - - // Counters to support checking that the task scope owner joins before processing - // results and attempts join before closing the task scope. These counters are - // accessed only by the owner thread. - private int forkRound; // incremented when the first subtask is forked after join - private int lastJoinAttempted; // set to the current fork round when join is attempted - private int lastJoinCompleted; // set to the current fork round when join completes +public sealed interface StructuredTaskScope + extends AutoCloseable + permits StructuredTaskScopeImpl { /** - * Represents a subtask forked with {@link #fork(Callable)}. + * Represents a subtask forked with {@link #fork(Callable)} or {@link #fork(Runnable)}. + * + *

              Code that forks subtasks can use the {@link #get() get()} method after {@linkplain + * #join() joining} to obtain the result of a subtask that completed successfully. It + * can use the {@link #exception()} method to obtain the exception thrown by a subtask + * that failed. + * * @param the result type * @since 21 */ @PreviewFeature(feature = PreviewFeature.Feature.STRUCTURED_CONCURRENCY) - public sealed interface Subtask extends Supplier permits SubtaskImpl { - /** - * {@return the value returning task provided to the {@code fork} method} - * - * @apiNote Task objects with unique identity may be used for correlation by - * implementations of {@link #handleComplete(Subtask) handleComplete}. - */ - Callable task(); - + sealed interface Subtask extends Supplier permits StructuredTaskScopeImpl.SubtaskImpl { /** * Represents the state of a subtask. * @see Subtask#state() @@ -342,964 +375,698 @@ public sealed interface Subtask extends Supplier permits SubtaskImpl { enum State { /** * The subtask result or exception is not available. This state indicates that - * the subtask was forked but has not completed, it completed after the task - * scope was {@linkplain #shutdown() shut down}, or it was forked after the - * task scope was shut down. + * the subtask was forked but has not completed, it completed after the scope + * was cancelled, or it was forked after the scoped was cancelled (in which + * case a thread was not created to execute the subtask). */ UNAVAILABLE, /** - * The subtask completed successfully with a result. The {@link Subtask#get() - * Subtask.get()} method can be used to obtain the result. This is a terminal - * state. + * The subtask completed successfully. The {@link Subtask#get() Subtask.get()} + * method can be used to get the result. This is a terminal state. */ SUCCESS, /** * The subtask failed with an exception. The {@link Subtask#exception() - * Subtask.exception()} method can be used to obtain the exception. This is a + * Subtask.exception()} method can be used to get the exception. This is a * terminal state. */ FAILED, } /** - * {@return the state of the subtask} + * {@return the subtask state} */ State state(); /** - * Returns the result of the subtask. + * Returns the result of this subtask if it completed successfully. If the subtask + * was forked with {@link #fork(Callable) fork(Callable)} then the result from the + * {@link Callable#call() call} method is returned. If the subtask was forked with + * {@link #fork(Runnable) fork(Runnable)} then {@code null} is returned. + * + *

              Code executing in the scope owner thread can use this method to get the + * result of a successful subtask only after it has {@linkplain #join() joined}. * - *

              To ensure correct usage, if the scope owner {@linkplain #fork(Callable) forks} - * a subtask, then it must join (with {@link #join() join} or {@link #joinUntil(Instant) - * joinUntil}) before it can obtain the result of the subtask. + *

              Code executing in the {@code Joiner} {@link Joiner#onComplete(Subtask) + * onComplete} method should test that the {@linkplain #state() subtask state} is + * {@link State#SUCCESS SUCCESS} before using this method to get the result. * * @return the possibly-null result * @throws IllegalStateException if the subtask has not completed, did not complete - * successfully, or the current thread is the task scope owner and did not join - * after forking + * successfully, or the current thread is the scope owner invoking this + * method before {@linkplain #join() joining} * @see State#SUCCESS */ T get(); /** - * {@return the exception thrown by the subtask} + * {@return the exception or error thrown by this subtask if it failed} + * If the subtask was forked with {@link #fork(Callable) fork(Callable)} then the + * exception or error thrown by the {@link Callable#call() call} method is returned. + * If the subtask was forked with {@link #fork(Runnable) fork(Runnable)} then the + * exception or error thrown by the {@link Runnable#run() run} method is returned. + * + *

              Code executing in the scope owner thread can use this method to get the + * exception thrown by a failed subtask only after it has {@linkplain #join() joined}. * - *

              To ensure correct usage, if the scope owner {@linkplain #fork(Callable) forks} - * a subtask, then it must join (with {@link #join() join} or {@link #joinUntil(Instant) - * joinUntil}) before it can obtain the exception thrown by the subtask. + *

              Code executing in a {@code Joiner} {@link Joiner#onComplete(Subtask) + * onComplete} method should test that the {@linkplain #state() subtask state} is + * {@link State#FAILED FAILED} before using this method to get the exception. * * @throws IllegalStateException if the subtask has not completed, completed with - * a result, or the current thread is the task scope owner and did not join after - * forking + * a result, or the current thread is the scope owner invoking this method + * before {@linkplain #join() joining} * @see State#FAILED */ Throwable exception(); } /** - * Creates a structured task scope with the given name and thread factory. The task - * scope is optionally named for the purposes of monitoring and management. The thread - * factory is used to {@link ThreadFactory#newThread(Runnable) create} threads when - * subtasks are {@linkplain #fork(Callable) forked}. The task scope is owned by the - * current thread. - * - *

              Construction captures the current thread's {@linkplain ScopedValue scoped value} - * bindings for inheritance by threads started in the task scope. The - * Tree Structure section in the class description details - * how parent-child relations are established implicitly for the purpose of inheritance - * of scoped value bindings. - * - * @param name the name of the task scope, can be null - * @param factory the thread factory - */ - @SuppressWarnings("this-escape") - public StructuredTaskScope(String name, ThreadFactory factory) { - this.factory = Objects.requireNonNull(factory, "'factory' is null"); - if (name == null) - name = Objects.toIdentityString(this); - this.flock = ThreadFlock.open(name); - } - - /** - * Creates an unnamed structured task scope that creates virtual threads. The task - * scope is owned by the current thread. - * - * @implSpec This constructor is equivalent to invoking the 2-arg constructor with a - * name of {@code null} and a thread factory that creates virtual threads. - */ - public StructuredTaskScope() { - this(null, Thread.ofVirtual().factory()); - } - - private IllegalStateException newIllegalStateExceptionScopeClosed() { - return new IllegalStateException("Task scope is closed"); - } - - private IllegalStateException newIllegalStateExceptionNoJoin() { - return new IllegalStateException("Owner did not join after forking subtasks"); - } - - /** - * Throws IllegalStateException if the scope is closed, returning the state if not - * closed. - */ - private int ensureOpen() { - int s = state; - if (s == CLOSED) - throw newIllegalStateExceptionScopeClosed(); - return s; - } - - /** - * Throws WrongThreadException if the current thread is not the owner. - */ - private void ensureOwner() { - if (Thread.currentThread() != flock.owner()) - throw new WrongThreadException("Current thread not owner"); - } - - /** - * Throws WrongThreadException if the current thread is not the owner - * or a thread contained in the tree. - */ - private void ensureOwnerOrContainsThread() { - Thread currentThread = Thread.currentThread(); - if (currentThread != flock.owner() && !flock.containsThread(currentThread)) - throw new WrongThreadException("Current thread not owner or thread in the tree"); - } - - /** - * Throws IllegalStateException if the current thread is the owner, and the owner did - * not join after forking a subtask in the given fork round. - */ - private void ensureJoinedIfOwner(int round) { - if (Thread.currentThread() == flock.owner() && (round > lastJoinCompleted)) { - throw newIllegalStateExceptionNoJoin(); - } - } - - /** - * Ensures that the current thread is the owner of this task scope and that it joined - * (with {@link #join()} or {@link #joinUntil(Instant)}) after {@linkplain #fork(Callable) - * forking} subtasks. - * - * @apiNote This method can be used by subclasses that define methods to make available - * results, state, or other outcome to code intended to execute after the join method. - * - * @throws WrongThreadException if the current thread is not the task scope owner - * @throws IllegalStateException if the task scope is open and task scope owner did - * not join after forking - */ - protected final void ensureOwnerAndJoined() { - ensureOwner(); - if (forkRound > lastJoinCompleted) { - throw newIllegalStateExceptionNoJoin(); - } - } - - /** - * Invoked by a subtask when it completes successfully or fails in this task scope. - * This method is not invoked if a subtask completes after the task scope is - * {@linkplain #shutdown() shut down}. - * - * @implSpec The default implementation throws {@code NullPointerException} if the - * subtask is {@code null}. It throws {@link IllegalArgumentException} if the subtask - * has not completed. - * - * @apiNote The {@code handleComplete} method should be thread safe. It may be - * invoked by several threads concurrently. - * - * @param subtask the subtask + * An object used with a {@link StructuredTaskScope} to handle subtask completion and + * produce the result for the scope owner waiting in the {@link #join() join} method + * for subtasks to complete. * - * @throws IllegalArgumentException if called with a subtask that has not completed - */ - protected void handleComplete(Subtask subtask) { - if (subtask.state() == Subtask.State.UNAVAILABLE) - throw new IllegalArgumentException(); - } - - /** - * Starts a new thread in this task scope to execute a value-returning task, thus - * creating a subtask of this task scope. - * - *

              The value-returning task is provided to this method as a {@link Callable}, the - * thread executes the task's {@link Callable#call() call} method. The thread is - * created with the task scope's {@link ThreadFactory}. It inherits the current thread's - * {@linkplain ScopedValue scoped value} bindings. The bindings must match the bindings - * captured when the task scope was created. - * - *

              This method returns a {@link Subtask Subtask} to represent the forked - * subtask. The {@code Subtask} object can be used to obtain the result when - * the subtask completes successfully, or the exception when the subtask fails. To - * ensure correct usage, the {@link Subtask#get() get()} and {@link Subtask#exception() - * exception()} methods may only be called by the task scope owner after it has waited - * for all threads to finish with the {@link #join() join} or {@link #joinUntil(Instant)} - * methods. When the subtask completes, the thread invokes the {@link - * #handleComplete(Subtask) handleComplete} method to consume the completed subtask. - * If the task scope is {@linkplain #shutdown() shut down} before the subtask completes - * then the {@code handleComplete} method will not be invoked. - * - *

              If this task scope is {@linkplain #shutdown() shutdown} (or in the process of - * shutting down) then the subtask will not run and the {@code handleComplete} method - * will not be invoked. - * - *

              This method may only be invoked by the task scope owner or threads contained - * in the task scope. - * - * @implSpec This method may be overridden for customization purposes, wrapping tasks - * for example. If overridden, the subclass must invoke {@code super.fork} to start a - * new thread in this task scope. - * - * @param task the value-returning task for the thread to execute - * @param the result type - * @return the subtask - * @throws IllegalStateException if this task scope is closed - * @throws WrongThreadException if the current thread is not the task scope owner or a - * thread contained in the task scope - * @throws StructureViolationException if the current scoped value bindings are not - * the same as when the task scope was created - * @throws RejectedExecutionException if the thread factory rejected creating a - * thread to run the subtask - */ - public Subtask fork(Callable task) { - Objects.requireNonNull(task, "'task' is null"); - int s = ensureOpen(); // throws ISE if closed - - // when forked by the owner, the subtask is forked in the current or next round - int round = -1; - if (Thread.currentThread() == flock.owner()) { - round = forkRound; - if (forkRound == lastJoinCompleted) { - // new round if first fork after join - round++; - } - } - - SubtaskImpl subtask = new SubtaskImpl<>(this, task, round); - if (s < SHUTDOWN) { - // create thread to run task - Thread thread = factory.newThread(subtask); - if (thread == null) { - throw new RejectedExecutionException("Rejected by thread factory"); - } - - // attempt to start the thread - try { - flock.start(thread); - } catch (IllegalStateException e) { - // shutdown by another thread, or underlying flock is shutdown due - // to unstructured use - } - } - - // force owner to join if this is the first fork in the round - if (Thread.currentThread() == flock.owner() && round > forkRound) { - forkRound = round; - } - - // return forked subtask or a subtask that did not run - return subtask; - } - - /** - * Wait for all threads to finish or the task scope to shut down. - */ - private void implJoin(Duration timeout) - throws InterruptedException, TimeoutException - { - ensureOwner(); - lastJoinAttempted = forkRound; - int s = ensureOpen(); // throws ISE if closed - if (s == OPEN) { - // wait for all threads, wakeup, interrupt, or timeout - if (timeout != null) { - flock.awaitAll(timeout); - } else { - flock.awaitAll(); - } - } - lastJoinCompleted = forkRound; - } - - /** - * Wait for all subtasks started in this task scope to finish or the task scope to - * shut down. - * - *

              This method waits for all subtasks by waiting for all threads {@linkplain - * #fork(Callable) started} in this task scope to finish execution. It stops waiting - * when all threads finish, the task scope is {@linkplain #shutdown() shut down}, or - * the current thread is {@linkplain Thread#interrupt() interrupted}. - * - *

              This method may only be invoked by the task scope owner. - * - * @implSpec This method may be overridden for customization purposes or to return a - * more specific return type. If overridden, the subclass must invoke {@code - * super.join} to ensure that the method waits for threads in this task scope to - * finish. - * - * @return this task scope - * @throws IllegalStateException if this task scope is closed - * @throws WrongThreadException if the current thread is not the task scope owner - * @throws InterruptedException if interrupted while waiting - */ - public StructuredTaskScope join() throws InterruptedException { - try { - implJoin(null); - } catch (TimeoutException e) { - throw new InternalError(); - } - return this; - } - - /** - * Wait for all subtasks started in this task scope to finish or the task scope to - * shut down, up to the given deadline. - * - *

              This method waits for all subtasks by waiting for all threads {@linkplain - * #fork(Callable) started} in this task scope to finish execution. It stops waiting - * when all threads finish, the task scope is {@linkplain #shutdown() shut down}, the - * deadline is reached, or the current thread is {@linkplain Thread#interrupt() - * interrupted}. - * - *

              This method may only be invoked by the task scope owner. - * - * @implSpec This method may be overridden for customization purposes or to return a - * more specific return type. If overridden, the subclass must invoke {@code - * super.joinUntil} to ensure that the method waits for threads in this task scope to - * finish. - * - * @param deadline the deadline - * @return this task scope - * @throws IllegalStateException if this task scope is closed - * @throws WrongThreadException if the current thread is not the task scope owner - * @throws InterruptedException if interrupted while waiting - * @throws TimeoutException if the deadline is reached while waiting - */ - public StructuredTaskScope joinUntil(Instant deadline) - throws InterruptedException, TimeoutException - { - Duration timeout = Duration.between(Instant.now(), deadline); - implJoin(timeout); - return this; - } - - /** - * Interrupt all unfinished threads. - */ - private void interruptAll() { - flock.threads() - .filter(t -> t != Thread.currentThread()) - .forEach(t -> { - try { - t.interrupt(); - } catch (Throwable ignore) { } - }); - } - - /** - * Shutdown the task scope if not already shutdown. Return true if this method - * shutdowns the task scope, false if already shutdown. - */ - private boolean implShutdown() { - shutdownLock.lock(); - try { - if (state < SHUTDOWN) { - // prevent new threads from starting - flock.shutdown(); - - // set status before interrupting tasks - state = SHUTDOWN; - - // interrupt all unfinished threads - interruptAll(); - - return true; - } else { - // already shutdown - return false; - } - } finally { - shutdownLock.unlock(); - } - } - - /** - * Shut down this task scope without closing it. Shutting down a task scope prevents - * new threads from starting, interrupts all unfinished threads, and causes the - * {@link #join() join} method to wakeup. Shutdown is useful for cases where the - * results of unfinished subtasks are no longer needed. It will typically be called - * by the {@link #handleComplete(Subtask)} implementation of a subclass that - * implements a policy to discard unfinished tasks once some outcome is reached. - * - *

              More specifically, this method: + *

              Joiner defines static methods to create {@code Joiner} objects for common cases: *

                - *
              • {@linkplain Thread#interrupt() Interrupts} all unfinished threads in the - * task scope (except the current thread). - *
              • Wakes up the task scope owner if it is waiting in {@link #join()} or {@link - * #joinUntil(Instant)}. If the task scope owner is not waiting then its next call to - * {@code join} or {@code joinUntil} will return immediately. + *
              • {@link #allSuccessfulOrThrow() allSuccessfulOrThrow()} creates a {@code Joiner} + * that yields a stream of the completed subtasks for {@code join} to return when + * all subtasks complete successfully. It cancels the scope and causes {@code join} + * to throw if any subtask fails. + *
              • {@link #anySuccessfulResultOrThrow() anySuccessfulResultOrThrow()} creates a + * {@code Joiner} that yields the result of the first subtask to succeed for {@code + * join} to return. It causes {@code join} to throw if all subtasks fail. + *
              • {@link #awaitAllSuccessfulOrThrow() awaitAllSuccessfulOrThrow()} creates a + * {@code Joiner} that waits for all successful subtasks. It cancels the scope and + * causes {@code join} to throw if any subtask fails. + *
              • {@link #awaitAll() awaitAll()} creates a {@code Joiner} that waits for all + * subtasks. It does not cancel the scope or cause {@code join} to throw. *
              * - *

              The {@linkplain Subtask.State state} of unfinished subtasks that complete at - * around the time that the task scope is shutdown is not defined. A subtask that - * completes successfully with a result, or fails with an exception, at around - * the time that the task scope is shutdown may or may not transition to a - * terminal state. - * - *

              This method may only be invoked by the task scope owner or threads contained - * in the task scope. + *

              In addition to the methods to create {@code Joiner} objects for common cases, + * the {@link #allUntil(Predicate) allUntil(Predicate)} method is defined to create a + * {@code Joiner} that yields a stream of all subtasks. It is created with a {@link + * Predicate Predicate} that determines if the scope should continue or be cancelled. + * This {@code Joiner} can be built upon to create custom policies that cancel the + * scope based on some condition. * - * @implSpec This method may be overridden for customization purposes. If overridden, - * the subclass must invoke {@code super.shutdown} to ensure that the method shuts - * down the task scope. + *

              More advanced policies can be developed by implementing the {@code Joiner} + * interface. The {@link #onFork(Subtask)} method is invoked when subtasks are forked. + * The {@link #onComplete(Subtask)} method is invoked when subtasks complete with a + * result or exception. These methods return a {@code boolean} to indicate if scope + * should be cancelled. These methods can be used to collect subtasks, results, or + * exceptions, and control when to cancel the scope. The {@link #result()} method + * must be implemented to produce the result (or exception) for the {@code join} + * method. * - * @apiNote - * There may be threads that have not finished because they are executing code that - * did not respond (or respond promptly) to thread interrupt. This method does not wait - * for these threads. When the owner invokes the {@link #close() close} method - * to close the task scope then it will wait for the remaining threads to finish. + *

              Unless otherwise specified, passing a {@code null} argument to a method + * in this class will cause a {@link NullPointerException} to be thrown. * - * @throws IllegalStateException if this task scope is closed - * @throws WrongThreadException if the current thread is not the task scope owner or - * a thread contained in the task scope - * @see #isShutdown() - */ - public void shutdown() { - ensureOwnerOrContainsThread(); - int s = ensureOpen(); // throws ISE if closed - if (s < SHUTDOWN && implShutdown()) - flock.wakeup(); - } - - /** - * {@return true if this task scope is shutdown, otherwise false} - * @see #shutdown() - */ - public final boolean isShutdown() { - return state >= SHUTDOWN; - } - - /** - * Closes this task scope. + * @implSpec Implementations of this interface must be thread safe. The {@link + * #onComplete(Subtask)} method defined by this interface may be invoked by several + * threads concurrently. * - *

              This method first shuts down the task scope (as if by invoking the {@link - * #shutdown() shutdown} method). It then waits for the threads executing any - * unfinished tasks to finish. If interrupted, this method will continue to wait for - * the threads to finish before completing with the interrupt status set. + * @apiNote It is very important that a new {@code Joiner} object is created for each + * {@code StructuredTaskScope}. {@code Joiner} objects should never be shared with + * different scopes or re-used after a task is closed. * - *

              This method may only be invoked by the task scope owner. If the task scope - * is already closed then the task scope owner invoking this method has no effect. + *

              Designing a {@code Joiner} should take into account the code at the use-site + * where the results from the {@link StructuredTaskScope#join() join} method are + * processed. It should be clear what the {@code Joiner} does vs. the application + * code at the use-site. In general, the {@code Joiner} implementation is not the + * place for "business logic". A {@code Joiner} should be designed to be as general + * purpose as possible. * - *

              A {@code StructuredTaskScope} is intended to be used in a structured - * manner. If this method is called to close a task scope before nested task - * scopes are closed then it closes the underlying construct of each nested task scope - * (in the reverse order that they were created in), closes this task scope, and then - * throws {@link StructureViolationException}. - * Similarly, if this method is called to close a task scope while executing with - * {@linkplain ScopedValue scoped value} bindings, and the task scope was created - * before the scoped values were bound, then {@code StructureViolationException} is - * thrown after closing the task scope. - * If a thread terminates without first closing task scopes that it owns then - * termination will cause the underlying construct of each of its open tasks scopes to - * be closed. Closing is performed in the reverse order that the task scopes were - * created in. Thread termination may therefore be delayed when the task scope owner - * has to wait for threads forked in these task scopes to finish. - * - * @implSpec This method may be overridden for customization purposes. If overridden, - * the subclass must invoke {@code super.close} to close the task scope. - * - * @throws IllegalStateException thrown after closing the task scope if the task scope - * owner did not attempt to join after forking - * @throws WrongThreadException if the current thread is not the task scope owner - * @throws StructureViolationException if a structure violation was detected - */ - @Override - public void close() { - ensureOwner(); - int s = state; - if (s == CLOSED) - return; - - try { - if (s < SHUTDOWN) - implShutdown(); - flock.close(); - } finally { - state = CLOSED; - } - - // throw ISE if the owner didn't attempt to join after forking - if (forkRound > lastJoinAttempted) { - lastJoinCompleted = forkRound; - throw newIllegalStateExceptionNoJoin(); - } - } - - @Override - public String toString() { - String name = flock.name(); - return switch (state) { - case OPEN -> name; - case SHUTDOWN -> name + "/shutdown"; - case CLOSED -> name + "/closed"; - default -> throw new InternalError(); - }; - } - - /** - * Subtask implementation, runs the task specified to the fork method. + * @param the result type of subtasks executed in the scope + * @param the result type of the scope + * @since 25 + * @see #open(Joiner) */ - private static final class SubtaskImpl implements Subtask, Runnable { - private static final AltResult RESULT_NULL = new AltResult(Subtask.State.SUCCESS); - - private record AltResult(Subtask.State state, Throwable exception) { - AltResult(Subtask.State state) { - this(state, null); - } - } - - private final StructuredTaskScope scope; - private final Callable task; - private final int round; - private volatile Object result; - - SubtaskImpl(StructuredTaskScope scope, - Callable task, - int round) { - this.scope = scope; - this.task = task; - this.round = round; - } - - @Override - public void run() { - T result = null; - Throwable ex = null; - try { - result = task.call(); - } catch (Throwable e) { - ex = e; - } - - // nothing to do if task scope is shutdown - if (scope.isShutdown()) - return; - - // capture result or exception, invoke handleComplete - if (ex == null) { - this.result = (result != null) ? result : RESULT_NULL; - } else { - this.result = new AltResult(State.FAILED, ex); - } - scope.handleComplete(this); - } - - @Override - public Callable task() { - return task; - } - - @Override - public Subtask.State state() { - Object result = this.result; - if (result == null) { - return State.UNAVAILABLE; - } else if (result instanceof AltResult alt) { - // null or failed - return alt.state(); - } else { - return State.SUCCESS; - } - } - - @Override - public T get() { - scope.ensureJoinedIfOwner(round); - Object result = this.result; - if (result instanceof AltResult) { - if (result == RESULT_NULL) return null; - } else if (result != null) { - @SuppressWarnings("unchecked") - T r = (T) result; - return r; + @PreviewFeature(feature = PreviewFeature.Feature.STRUCTURED_CONCURRENCY) + @FunctionalInterface + interface Joiner { + /** + * Invoked by {@link #fork(Callable) fork(Callable)} and {@link #fork(Runnable) + * fork(Runnable)} when forking a subtask. The method is invoked from the task + * owner thread. The method is invoked before a thread is created to run the + * subtask. + * + * @implSpec The default implementation throws {@code NullPointerException} if the + * subtask is {@code null}. It throws {@code IllegalArgumentException} if the + * subtask is not in the {@link Subtask.State#UNAVAILABLE UNAVAILABLE} state, it + * otherwise returns {@code false}. + * + * @apiNote This method is invoked by the {@code fork} methods. It should not be + * invoked directly. + * + * @param subtask the subtask + * @return {@code true} to cancel the scope, otherwise {@code false} + */ + default boolean onFork(Subtask subtask) { + if (subtask.state() != Subtask.State.UNAVAILABLE) { + throw new IllegalArgumentException("Subtask not in UNAVAILABLE state"); } - throw new IllegalStateException( - "Result is unavailable or subtask did not complete successfully"); + return false; } - @Override - public Throwable exception() { - scope.ensureJoinedIfOwner(round); - Object result = this.result; - if (result instanceof AltResult alt && alt.state() == State.FAILED) { - return alt.exception(); + /** + * Invoked by the thread started to execute a subtask after the subtask completes + * successfully or fails with an exception. This method is not invoked if a + * subtask completes after the scope is cancelled. + * + * @implSpec The default implementation throws {@code NullPointerException} if the + * subtask is {@code null}. It throws {@code IllegalArgumentException} if the + * subtask is not in the {@link Subtask.State#SUCCESS SUCCESS} or {@link + * Subtask.State#FAILED FAILED} state, it otherwise returns {@code false}. + * + * @apiNote This method is invoked by subtasks when they complete. It should not + * be invoked directly. + * + * @param subtask the subtask + * @return {@code true} to cancel the scope, otherwise {@code false} + */ + default boolean onComplete(Subtask subtask) { + if (subtask.state() == Subtask.State.UNAVAILABLE) { + throw new IllegalArgumentException("Subtask has not completed"); } - throw new IllegalStateException( - "Exception is unavailable or subtask did not complete with exception"); - } - - @Override - public String toString() { - String stateAsString = switch (state()) { - case UNAVAILABLE -> "[Unavailable]"; - case SUCCESS -> "[Completed successfully]"; - case FAILED -> { - Throwable ex = ((AltResult) result).exception(); - yield "[Failed: " + ex + "]"; - } - }; - return Objects.toIdentityString(this) + stateAsString; - } - } - - /** - * A {@code StructuredTaskScope} that captures the result of the first subtask to - * complete {@linkplain Subtask.State#SUCCESS successfully}. Once captured, it - * {@linkplain #shutdown() shuts down} the task scope to interrupt unfinished threads - * and wakeup the task scope owner. The policy implemented by this class is intended - * for cases where the result of any subtask will do ("invoke any") and where the - * results of other unfinished subtasks are no longer needed. - * - *

              Unless otherwise specified, passing a {@code null} argument to a method - * in this class will cause a {@link NullPointerException} to be thrown. - * - * @apiNote This class implements a policy to shut down the task scope when a subtask - * completes successfully. There shouldn't be any need to directly shut down the task - * scope with the {@link #shutdown() shutdown} method. - * - * @param the result type - * @since 21 - */ - @PreviewFeature(feature = PreviewFeature.Feature.STRUCTURED_CONCURRENCY) - public static final class ShutdownOnSuccess extends StructuredTaskScope { - private static final Object RESULT_NULL = new Object(); - private static final VarHandle FIRST_RESULT; - private static final VarHandle FIRST_EXCEPTION; - static { - MethodHandles.Lookup l = MethodHandles.lookup(); - FIRST_RESULT = MhUtil.findVarHandle(l, "firstResult", Object.class); - FIRST_EXCEPTION = MhUtil.findVarHandle(l, "firstException", Throwable.class); + return false; } - private volatile Object firstResult; - private volatile Throwable firstException; /** - * Constructs a new {@code ShutdownOnSuccess} with the given name and thread factory. - * The task scope is optionally named for the purposes of monitoring and management. - * The thread factory is used to {@link ThreadFactory#newThread(Runnable) create} - * threads when subtasks are {@linkplain #fork(Callable) forked}. The task scope - * is owned by the current thread. + * Invoked by the {@link #join() join()} method to produce the result (or exception) + * after waiting for all subtasks to complete or the scope cancelled. The result + * from this method is returned by the {@code join} method. If this method throws, + * then {@code join} throws {@link FailedException} with the exception thrown by + * this method as the cause. + * + *

              In normal usage, this method will be called at most once by the {@code join} + * method to produce the result (or exception). The behavior of this method when + * invoked directly, and invoked more than once, is undefined. Where possible, an + * implementation should return an equal result (or throw the same exception) on + * second or subsequent calls to produce the outcome. * - *

              Construction captures the current thread's {@linkplain ScopedValue scoped - * value} bindings for inheritance by threads started in the task scope. The - * {@linkplain StructuredTaskScope##TreeStructure Tree Structure} section - * in the class description details how parent-child relations are established - * implicitly for the purpose of inheritance of scoped value bindings. + * @apiNote This method is invoked by the {@code join} method. It should not be + * invoked directly. * - * @param name the name of the task scope, can be null - * @param factory the thread factory + * @return the result + * @throws Throwable the exception */ - public ShutdownOnSuccess(String name, ThreadFactory factory) { - super(name, factory); - } + R result() throws Throwable; /** - * Constructs a new unnamed {@code ShutdownOnSuccess} that creates virtual threads. + * {@return a new Joiner object that yields a stream of all subtasks when all + * subtasks complete successfully} + * The {@code Joiner} cancels + * the scope and causes {@code join} to throw if any subtask fails. + * + *

              If all subtasks complete successfully, the joiner's {@link Joiner#result()} + * method returns a stream of all subtasks in the order that they were forked. + * If any subtask failed then the {@code result} method throws the exception from + * the first subtask to fail. + * + * @apiNote Joiners returned by this method are suited to cases where all subtasks + * return a result of the same type. Joiners returned by {@link + * #awaitAllSuccessfulOrThrow()} are suited to cases where the subtasks return + * results of different types. * - * @implSpec This constructor is equivalent to invoking the 2-arg constructor with - * a name of {@code null} and a thread factory that creates virtual threads. + * @param the result type of subtasks */ - public ShutdownOnSuccess() { - this(null, Thread.ofVirtual().factory()); - } - - @Override - protected void handleComplete(Subtask subtask) { - if (firstResult != null) { - // already captured a result - return; - } - - if (subtask.state() == Subtask.State.SUCCESS) { - // task succeeded - T result = subtask.get(); - Object r = (result != null) ? result : RESULT_NULL; - if (FIRST_RESULT.compareAndSet(this, null, r)) { - super.shutdown(); - } - } else if (firstException == null) { - // capture the exception thrown by the first subtask that failed - FIRST_EXCEPTION.compareAndSet(this, null, subtask.exception()); - } + static Joiner>> allSuccessfulOrThrow() { + return new Joiners.AllSuccessful<>(); } /** - * Wait for a subtask started in this task scope to complete {@linkplain - * Subtask.State#SUCCESS successfully} or all subtasks to complete. + * {@return a new Joiner object that yields the result of any subtask that + * completed successfully} + * The {@code Joiner} causes {@code join} to throw if all subtasks fail. * - *

              This method waits for all subtasks by waiting for all threads {@linkplain - * #fork(Callable) started} in this task scope to finish execution. It stops waiting - * when all threads finish, a subtask completes successfully, or the current - * thread is {@linkplain Thread#interrupt() interrupted}. It also stops waiting - * if the {@link #shutdown() shutdown} method is invoked directly to shut down - * this task scope. + *

              The joiner's {@link Joiner#result()} method returns the result of a subtask + * that completed successfully. If all subtasks fail then the {@code result} method + * throws the exception from one of the failed subtasks. The {@code result} method + * throws {@code NoSuchElementException} if no subtasks were forked. * - *

              This method may only be invoked by the task scope owner. - * - * @throws IllegalStateException {@inheritDoc} - * @throws WrongThreadException {@inheritDoc} + * @param the result type of subtasks */ - @Override - public ShutdownOnSuccess join() throws InterruptedException { - super.join(); - return this; + static Joiner anySuccessfulResultOrThrow() { + return new Joiners.AnySuccessful<>(); } /** - * Wait for a subtask started in this task scope to complete {@linkplain - * Subtask.State#SUCCESS successfully} or all subtasks to complete, up to the - * given deadline. + * {@return a new Joiner object that waits for subtasks to complete successfully} + * The {@code Joiner} cancels + * the scope and causes {@code join} to throw if any subtask fails. * - *

              This method waits for all subtasks by waiting for all threads {@linkplain - * #fork(Callable) started} in this task scope to finish execution. It stops waiting - * when all threads finish, a subtask completes successfully, the deadline is - * reached, or the current thread is {@linkplain Thread#interrupt() interrupted}. - * It also stops waiting if the {@link #shutdown() shutdown} method is invoked - * directly to shut down this task scope. + *

              The joiner's {@link Joiner#result() result} method returns {@code null} + * if all subtasks complete successfully, or throws the exception from the first + * subtask to fail. * - *

              This method may only be invoked by the task scope owner. + * @apiNote Joiners returned by this method are suited to cases where subtasks + * return results of different types. Joiners returned by {@link #allSuccessfulOrThrow()} + * are suited to cases where the subtasks return a result of the same type. * - * @throws IllegalStateException {@inheritDoc} - * @throws WrongThreadException {@inheritDoc} + * @param the result type of subtasks */ - @Override - public ShutdownOnSuccess joinUntil(Instant deadline) - throws InterruptedException, TimeoutException - { - super.joinUntil(deadline); - return this; + static Joiner awaitAllSuccessfulOrThrow() { + return new Joiners.AwaitSuccessful<>(); } /** - * {@return the result of the first subtask that completed {@linkplain - * Subtask.State#SUCCESS successfully}} + * {@return a new Joiner object that waits for all subtasks to complete} + * The {@code Joiner} does not cancel the scope if a subtask fails. + * + *

              The joiner's {@link Joiner#result() result} method returns {@code null}. + * + * @apiNote This Joiner is useful for cases where subtasks make use of + * side-effects rather than return results or fail with exceptions. + * The {@link #fork(Runnable) fork(Runnable)} method can be used to fork subtasks + * that do not return a result. * - *

              When no subtask completed successfully, but a subtask {@linkplain - * Subtask.State#FAILED failed} then {@code ExecutionException} is thrown with - * the subtask's exception as the {@linkplain Throwable#getCause() cause}. + *

              This Joiner can also be used for fan-in scenarios where subtasks + * are forked to handle incoming connections and the number of subtasks is unbounded. + * In this example, the thread executing the {@code acceptLoop} method will only + * stop when interrupted or the listener socket is closed asynchronously. + * {@snippet lang=java : + * void acceptLoop(ServerSocket listener) throws IOException, InterruptedException { + * try (var scope = StructuredTaskScope.open(Joiner.awaitAll())) { + * while (true) { + * Socket socket = listener.accept(); + * scope.fork(() -> handle(socket)); + * } + * } + * } + * } * - * @throws ExecutionException if no subtasks completed successfully but at least - * one subtask failed - * @throws IllegalStateException if no subtasks completed or the task scope owner - * did not join after forking - * @throws WrongThreadException if the current thread is not the task scope owner + * @param the result type of subtasks */ - public T result() throws ExecutionException { - return result(ExecutionException::new); + static Joiner awaitAll() { + // ensure that new Joiner object is returned + return new Joiner() { + @Override + public Void result() { + return null; + } + }; } /** - * Returns the result of the first subtask that completed {@linkplain - * Subtask.State#SUCCESS successfully}, otherwise throws an exception produced - * by the given exception supplying function. + * {@return a new Joiner object that yields a stream of all subtasks when all + * subtasks complete or a predicate returns {@code true} to cancel the scope} + * + *

              The joiner's {@link Joiner#onComplete(Subtask)} method invokes the + * predicate's {@link Predicate#test(Object) test} method with the subtask that + * completed successfully or failed with an exception. If the {@code test} method + * returns {@code true} then + * the scope is cancelled. The {@code test} method must be thread safe as it + * may be invoked concurrently from several threads. If the {@code test} method + * completes with an exception or error, then the thread that executed the subtask + * invokes the {@linkplain Thread.UncaughtExceptionHandler uncaught exception handler} + * with the exception or error before the thread terminates. * - *

              When no subtask completed successfully, but a subtask {@linkplain - * Subtask.State#FAILED failed}, then the exception supplying function is invoked - * with subtask's exception. + *

              The joiner's {@link #result()} method returns the stream of all subtasks, + * in fork order. The stream may contain subtasks that have completed + * (in {@link Subtask.State#SUCCESS SUCCESS} or {@link Subtask.State#FAILED FAILED} + * state) or subtasks in the {@link Subtask.State#UNAVAILABLE UNAVAILABLE} state + * if the scope was cancelled before all subtasks were forked or completed. * - * @param esf the exception supplying function - * @param type of the exception to be thrown - * @return the result of the first subtask that completed with a result + *

              The following example uses this method to create a {@code Joiner} that + * cancels the scope when + * two or more subtasks fail. + * {@snippet lang=java : + * class CancelAfterTwoFailures implements Predicate> { + * private final AtomicInteger failedCount = new AtomicInteger(); + * @Override + * public boolean test(Subtask subtask) { + * return subtask.state() == Subtask.State.FAILED + * && failedCount.incrementAndGet() >= 2; + * } + * } * - * @throws X if no subtasks completed successfully but at least one subtask failed - * @throws IllegalStateException if no subtasks completed or the task scope owner - * did not join after forking - * @throws WrongThreadException if the current thread is not the task scope owner + * var joiner = Joiner.all(new CancelAfterTwoFailures()); + * } + * + *

              The following example uses {@code allUntil} to wait for all subtasks to + * complete without any cancellation. This is similar to {@link #awaitAll()} + * except that it yields a stream of the completed subtasks. + * {@snippet lang=java : + * List> invokeAll(Collection> tasks) throws InterruptedException { + * try (var scope = StructuredTaskScope.open(Joiner.allUntil(_ -> false))) { + * tasks.forEach(scope::fork); + * return scope.join().toList(); + * } + * } + * } + * + * @param isDone the predicate to evaluate completed subtasks + * @param the result type of subtasks */ - public T result(Function esf) throws X { - Objects.requireNonNull(esf); - ensureOwnerAndJoined(); - - Object result = firstResult; - if (result == RESULT_NULL) { - return null; - } else if (result != null) { - @SuppressWarnings("unchecked") - T r = (T) result; - return r; - } - - Throwable exception = firstException; - if (exception != null) { - X ex = esf.apply(exception); - Objects.requireNonNull(ex, "esf returned null"); - throw ex; - } - - throw new IllegalStateException("No completed subtasks"); + static Joiner>> allUntil(Predicate> isDone) { + return new Joiners.AllSubtasks<>(isDone); } } /** - * A {@code StructuredTaskScope} that captures the exception of the first subtask to - * {@linkplain Subtask.State#FAILED fail}. Once captured, it {@linkplain #shutdown() - * shuts down} the task scope to interrupt unfinished threads and wakeup the task - * scope owner. The policy implemented by this class is intended for cases where the - * results for all subtasks are required ("invoke all"); if any subtask fails then the - * results of other unfinished subtasks are no longer needed. + * Represents the configuration for a {@code StructuredTaskScope}. + * + *

              The configuration for a {@code StructuredTaskScope} consists of a {@link + * ThreadFactory} to create threads, an optional name for the purposes of monitoring + * and management, and an optional timeout. + * + *

              Creating a {@code StructuredTaskScope} with {@link #open()} or {@link #open(Joiner)} + * uses the default + * configuration. The default configuration consists of a thread factory that + * creates unnamed + * virtual threads, no name for monitoring and management purposes, and no timeout. + * + *

              Creating a {@code StructuredTaskScope} with its 2-arg {@link #open(Joiner, Function) + * open} method allows a different configuration to be used. The function specified + * to the {@code open} method is applied to the default configuration and returns the + * configuration for the {@code StructuredTaskScope} under construction. The function + * can use the {@code with-} prefixed methods defined here to specify the components + * of the configuration to use. * *

              Unless otherwise specified, passing a {@code null} argument to a method * in this class will cause a {@link NullPointerException} to be thrown. * - * @apiNote This class implements a policy to shut down the task scope when a subtask - * fails. There shouldn't be any need to directly shut down the task scope with the - * {@link #shutdown() shutdown} method. - * - * @since 21 + * @since 25 */ @PreviewFeature(feature = PreviewFeature.Feature.STRUCTURED_CONCURRENCY) - public static final class ShutdownOnFailure extends StructuredTaskScope { - private static final VarHandle FIRST_EXCEPTION = - MhUtil.findVarHandle(MethodHandles.lookup(), "firstException", Throwable.class); - private volatile Throwable firstException; - + sealed interface Configuration permits StructuredTaskScopeImpl.ConfigImpl { /** - * Constructs a new {@code ShutdownOnFailure} with the given name and thread factory. - * The task scope is optionally named for the purposes of monitoring and management. - * The thread factory is used to {@link ThreadFactory#newThread(Runnable) create} - * threads when subtasks are {@linkplain #fork(Callable) forked}. The task scope - * is owned by the current thread. + * {@return a new {@code Configuration} object with the given thread factory} + * The other components are the same as this object. The thread factory is used by + * a scope to create threads when {@linkplain #fork(Callable) forking} subtasks. + * @param threadFactory the thread factory * - *

              Construction captures the current thread's {@linkplain ScopedValue scoped - * value} bindings for inheritance by threads started in the task scope. The - * {@linkplain StructuredTaskScope##TreeStructure Tree Structure} section in the class description - * details how parent-child relations are established implicitly for the purpose - * of inheritance of scoped value bindings. + * @apiNote The thread factory will typically create + * virtual threads, + * maybe with names for monitoring purposes, an {@linkplain Thread.UncaughtExceptionHandler + * uncaught exception handler}, or other properties configured. * - * @param name the name of the task scope, can be null - * @param factory the thread factory + * @see #fork(Callable) */ - public ShutdownOnFailure(String name, ThreadFactory factory) { - super(name, factory); - } + Configuration withThreadFactory(ThreadFactory threadFactory); /** - * Constructs a new unnamed {@code ShutdownOnFailure} that creates virtual threads. - * - * @implSpec This constructor is equivalent to invoking the 2-arg constructor with - * a name of {@code null} and a thread factory that creates virtual threads. + * {@return a new {@code Configuration} object with the given name} + * The other components are the same as this object. A scope is optionally + * named for the purposes of monitoring and management. + * @param name the name */ - public ShutdownOnFailure() { - this(null, Thread.ofVirtual().factory()); - } - - @Override - protected void handleComplete(Subtask subtask) { - if (subtask.state() == Subtask.State.FAILED - && firstException == null - && FIRST_EXCEPTION.compareAndSet(this, null, subtask.exception())) { - super.shutdown(); - } - } + Configuration withName(String name); /** - * Wait for all subtasks started in this task scope to complete or for a subtask - * to {@linkplain Subtask.State#FAILED fail}. - * - *

              This method waits for all subtasks by waiting for all threads {@linkplain - * #fork(Callable) started} in this task scope to finish execution. It stops waiting - * when all threads finish, a subtask fails, or the current thread is {@linkplain - * Thread#interrupt() interrupted}. It also stops waiting if the {@link #shutdown() - * shutdown} method is invoked directly to shut down this task scope. + * {@return a new {@code Configuration} object with the given timeout} + * The other components are the same as this object. + * @param timeout the timeout * - *

              This method may only be invoked by the task scope owner. + * @apiNote Applications using deadlines, expressed as an {@link java.time.Instant}, + * can use {@link Duration#between Duration.between(Instant.now(), deadline)} to + * compute the timeout for this method. * - * @throws IllegalStateException {@inheritDoc} - * @throws WrongThreadException {@inheritDoc} + * @see #join() */ - @Override - public ShutdownOnFailure join() throws InterruptedException { - super.join(); - return this; - } + Configuration withTimeout(Duration timeout); + } - /** - * Wait for all subtasks started in this task scope to complete or for a subtask - * to {@linkplain Subtask.State#FAILED fail}, up to the given deadline. - * - *

              This method waits for all subtasks by waiting for all threads {@linkplain - * #fork(Callable) started} in this task scope to finish execution. It stops waiting - * when all threads finish, a subtask fails, the deadline is reached, or the current - * thread is {@linkplain Thread#interrupt() interrupted}. It also stops waiting - * if the {@link #shutdown() shutdown} method is invoked directly to shut down - * this task scope. - * - *

              This method may only be invoked by the task scope owner. - * - * @throws IllegalStateException {@inheritDoc} - * @throws WrongThreadException {@inheritDoc} - */ - @Override - public ShutdownOnFailure joinUntil(Instant deadline) - throws InterruptedException, TimeoutException - { - super.joinUntil(deadline); - return this; - } + /** + * Exception thrown by {@link #join()} when the outcome is an exception rather than a + * result. + * + * @since 25 + */ + @PreviewFeature(feature = PreviewFeature.Feature.STRUCTURED_CONCURRENCY) + final class FailedException extends RuntimeException { + @java.io.Serial + static final long serialVersionUID = -1533055100078459923L; /** - * Returns the exception of the first subtask that {@linkplain Subtask.State#FAILED - * failed}. If no subtasks failed then an empty {@code Optional} is returned. - * - * @return the exception for the first subtask to fail or an empty optional if no - * subtasks failed + * Constructs a {@code FailedException} with the specified cause. * - * @throws WrongThreadException if the current thread is not the task scope owner - * @throws IllegalStateException if the task scope owner did not join after forking + * @param cause the cause, can be {@code null} */ - public Optional exception() { - ensureOwnerAndJoined(); - return Optional.ofNullable(firstException); + FailedException(Throwable cause) { + super(cause); } + } - /** - * Throws if a subtask {@linkplain Subtask.State#FAILED failed}. - * If any subtask failed with an exception then {@code ExecutionException} is - * thrown with the exception of the first subtask to fail as the {@linkplain - * Throwable#getCause() cause}. This method does nothing if no subtasks failed. - * - * @throws ExecutionException if a subtask failed - * @throws WrongThreadException if the current thread is not the task scope owner - * @throws IllegalStateException if the task scope owner did not join after forking - */ - public void throwIfFailed() throws ExecutionException { - throwIfFailed(ExecutionException::new); - } + /** + * Exception thrown by {@link #join()} if the scope was created with a timeout and + * the timeout expired before or while waiting in {@code join}. + * + * @since 25 + * @see Configuration#withTimeout(Duration) + */ + @PreviewFeature(feature = PreviewFeature.Feature.STRUCTURED_CONCURRENCY) + final class TimeoutException extends RuntimeException { + @java.io.Serial + static final long serialVersionUID = 705788143955048766L; /** - * Throws the exception produced by the given exception supplying function if a - * subtask {@linkplain Subtask.State#FAILED failed}. If any subtask failed with - * an exception then the function is invoked with the exception of the first - * subtask to fail. The exception returned by the function is thrown. This method - * does nothing if no subtasks failed. - * - * @param esf the exception supplying function - * @param type of the exception to be thrown - * - * @throws X produced by the exception supplying function - * @throws WrongThreadException if the current thread is not the task scope owner - * @throws IllegalStateException if the task scope owner did not join after forking + * Constructs a {@code TimeoutException} with no detail message. */ - public - void throwIfFailed(Function esf) throws X { - ensureOwnerAndJoined(); - Objects.requireNonNull(esf); - Throwable exception = firstException; - if (exception != null) { - X ex = esf.apply(exception); - Objects.requireNonNull(ex, "esf returned null"); - throw ex; - } - } + TimeoutException() { } + } + + /** + * Opens a new {@code StructuredTaskScope} to use the given {@code Joiner} object and + * with configuration that is the result of applying the given function to the + * default configuration. + * + *

              The {@code configFunction} is called with the default configuration and returns + * the configuration for the new scope. The function may, for example, set the + * {@linkplain Configuration#withThreadFactory(ThreadFactory) ThreadFactory} or set a + * {@linkplain Configuration#withTimeout(Duration) timeout}. If the function completes + * with an exception or error then it is propagated by this method. If the function + * returns {@code null} then {@code NullPointerException} is thrown. + * + *

              If a {@code ThreadFactory} is set then its {@link ThreadFactory#newThread(Runnable) + * newThread} method will be called to create threads when {@linkplain #fork(Callable) + * forking} subtasks in this scope. If a {@code ThreadFactory} is not set then + * forking subtasks will create an unnamed virtual thread for each subtask. + * + *

              If a {@linkplain Configuration#withTimeout(Duration) timeout} is set then it + * starts when the scope is opened. If the timeout expires before the scope has + * {@linkplain #join() joined} then the scope is cancelled + * and the {@code join} method throws {@link TimeoutException}. + * + *

              The new scope is owned by the current thread. Only code executing in this + * thread can {@linkplain #fork(Callable) fork}, {@linkplain #join() join}, or + * {@linkplain #close close} the scope. + * + *

              Construction captures the current thread's {@linkplain ScopedValue scoped + * value} bindings for inheritance by threads started in the scope. + * + * @param joiner the joiner + * @param configFunction a function to produce the configuration + * @return a new scope + * @param the result type of subtasks executed in the scope + * @param the result type of the scope + * @since 25 + */ + static StructuredTaskScope open(Joiner joiner, + Function configFunction) { + return StructuredTaskScopeImpl.open(joiner, configFunction); + } + + /** + * Opens a new {@code StructuredTaskScope}to use the given {@code Joiner} object. The + * scope is created with the default configuration. + * The default configuration has a {@code ThreadFactory} that creates unnamed + * virtual threads, + * is unnamed for monitoring and management purposes, and has no timeout. + * + * @implSpec + * This factory method is equivalent to invoking the 2-arg open method with the given + * joiner and the {@linkplain Function#identity() identity function}. + * + * @param joiner the joiner + * @return a new scope + * @param the result type of subtasks executed in the scope + * @param the result type of the scope + * @since 25 + */ + static StructuredTaskScope open(Joiner joiner) { + return open(joiner, Function.identity()); + } + + /** + * Opens a new {@code StructuredTaskScope} that can be used to fork subtasks that return + * results of any type. The scope's {@link #join()} method waits for all subtasks to + * succeed or any subtask to fail. + * + *

              The {@code join} method returns {@code null} if all subtasks complete successfully. + * It throws {@link FailedException} if any subtask fails, with the exception from + * the first subtask to fail as the cause. + * + *

              The scope is created with the default + * configuration. The default configuration has a {@code ThreadFactory} that creates + * unnamed virtual + * threads, is unnamed for monitoring and management purposes, and has no timeout. + * + * @implSpec + * This factory method is equivalent to invoking the 2-arg open method with a joiner + * created with {@link Joiner#awaitAllSuccessfulOrThrow() awaitAllSuccessfulOrThrow()} + * and the {@linkplain Function#identity() identity function}. + * + * @param the result type of subtasks + * @return a new scope + * @since 25 + */ + static StructuredTaskScope open() { + return open(Joiner.awaitAllSuccessfulOrThrow(), Function.identity()); } -} + + /** + * Fork a subtask by starting a new thread in this scope to execute a value-returning + * method. The new thread executes the subtask concurrently with the current thread. + * The parameter to this method is a {@link Callable}, the new thread executes its + * {@link Callable#call() call()} method. + * + *

              This method first creates a {@link Subtask Subtask} object to represent the + * forked subtask. It invokes the joiner's {@link Joiner#onFork(Subtask) onFork} + * method with the subtask in the {@link Subtask.State#UNAVAILABLE UNAVAILABLE} state. + * If the {@code onFork} completes with an exception or error then it is propagated by + * the {@code fork} method without creating a thread. If the scope is already + * cancelled, or {@code onFork} returns {@code true} to + * cancel the scope, then this method returns the {@code Subtask}, in the + * {@link Subtask.State#UNAVAILABLE UNAVAILABLE} state, without creating a thread to + * execute the subtask. + * + *

              If the scope is not cancelled, and the {@code onFork} method returns {@code false}, + * then a thread is created with the {@link ThreadFactory} configured when the scope + * was opened, and the thread is started. Forking a subtask inherits the current thread's + * {@linkplain ScopedValue scoped value} bindings. The bindings must match the bindings + * captured when the scope was opened. If the subtask completes (successfully or with + * an exception) before the scope is cancelled, then the thread invokes the joiner's + * {@link Joiner#onComplete(Subtask) onComplete} method with the subtask in the + * {@link Subtask.State#SUCCESS SUCCESS} or {@link Subtask.State#FAILED FAILED} state. + * If the {@code onComplete} method completes with an exception or error, then the + * {@linkplain Thread.UncaughtExceptionHandler uncaught exception handler} is invoked + * with the exception or error before the thread terminates. + * + *

              This method returns the {@link Subtask Subtask} object. In some usages, this + * object may be used to get its result. In other cases it may be used for correlation + * or be discarded. To ensure correct usage, the {@link Subtask#get() Subtask.get()} + * method may only be called by the scope owner to get the result after it has + * waited for subtasks to complete with the {@link #join() join} method and the subtask + * completed successfully. Similarly, the {@link Subtask#exception() Subtask.exception()} + * method may only be called by the scope owner after it has joined and the subtask + * failed. If the scope was cancelled before the subtask was forked, or before it + * completes, then neither method can be used to obtain the outcome. + * + *

              This method may only be invoked by the scope owner. + * + * @param task the value-returning task for the thread to execute + * @param the result type + * @return the subtask + * @throws WrongThreadException if the current thread is not the scope owner + * @throws IllegalStateException if the owner has already {@linkplain #join() joined} + * or the scope is closed + * @throws StructureViolationException if the current scoped value bindings are not + * the same as when the scope was created + * @throws RejectedExecutionException if the thread factory rejected creating a + * thread to run the subtask + */ + Subtask fork(Callable task); + + /** + * Fork a subtask by starting a new thread in this scope to execute a method that + * does not return a result. + * + *

              This method works exactly the same as {@link #fork(Callable)} except that the + * parameter to this method is a {@link Runnable}, the new thread executes its + * {@link Runnable#run() run} method, and {@link Subtask#get() Subtask.get()} returns + * {@code null} if the subtask completes successfully. + * + * @param task the task for the thread to execute + * @param the result type + * @return the subtask + * @throws WrongThreadException if the current thread is not the scope owner + * @throws IllegalStateException if the owner has already {@linkplain #join() joined} + * or the scope is closed + * @throws StructureViolationException if the current scoped value bindings are not + * the same as when the scope was created + * @throws RejectedExecutionException if the thread factory rejected creating a + * thread to run the subtask + * @since 25 + */ + Subtask fork(Runnable task); + + /** + * Returns the result, or throws, after waiting for all subtasks to complete or + * the scope to be cancelled. + * + *

              This method waits for all subtasks started in this scope to complete or the + * scope to be cancelled. If a {@linkplain Configuration#withTimeout(Duration) timeout} + * is configured and the timeout expires before or while waiting, then the scope is + * cancelled and {@link TimeoutException TimeoutException} is thrown. Once finished + * waiting, the {@code Joiner}'s {@link Joiner#result() result()} method is invoked + * to get the result or throw an exception. If the {@code result()} method throws + * then this method throws {@code FailedException} with the exception as the cause. + * + *

              This method may only be invoked by the scope owner, and only once. + * + * @return the result + * @throws WrongThreadException if the current thread is not the scope owner + * @throws IllegalStateException if already joined or this scope is closed + * @throws FailedException if the outcome is an exception, thrown with the + * exception from {@link Joiner#result() Joiner.result()} as the cause + * @throws TimeoutException if a timeout is set and the timeout expires before or + * while waiting + * @throws InterruptedException if interrupted while waiting + * @since 25 + */ + R join() throws InterruptedException; + + /** + * {@return {@code true} if this scope is cancelled or in + * the process of being cancelled, otherwise {@code false}} + * + *

              Cancelling the scope prevents new threads from starting in the scope and + * {@linkplain Thread#interrupt() interrupts} threads executing unfinished subtasks. + * It may take some time before the interrupted threads finish execution; this + * method may return {@code true} before all threads have been interrupted or before + * all threads have finished. + * + * @apiNote A task with a lengthy "forking phase" (the code that executes before + * it invokes {@link #join() join}) may use this method to avoid doing work in cases + * where scope is cancelled by the completion of a previously forked subtask or timeout. + * + * @since 25 + */ + boolean isCancelled(); + + /** + * Closes this scope. + * + *

              This method first cancels the scope, if not + * already cancelled. This interrupts the threads executing unfinished subtasks. This + * method then waits for all threads to finish. If interrupted while waiting then it + * will continue to wait until the threads finish, before completing with the interrupt + * status set. + * + *

              This method may only be invoked by the scope owner. If the scope + * is already closed then the scope owner invoking this method has no effect. + * + *

              A {@code StructuredTaskScope} is intended to be used in a structured + * manner. If this method is called to close a scope before nested task + * scopes are closed then it closes the underlying construct of each nested scope + * (in the reverse order that they were created in), closes this scope, and then + * throws {@link StructureViolationException}. + * Similarly, if this method is called to close a scope while executing with + * {@linkplain ScopedValue scoped value} bindings, and the scope was created + * before the scoped values were bound, then {@code StructureViolationException} is + * thrown after closing the scope. + * If a thread terminates without first closing scopes that it owns then + * termination will cause the underlying construct of each of its open tasks scopes to + * be closed. Closing is performed in the reverse order that the scopes were + * created in. Thread termination may therefore be delayed when the scope owner + * has to wait for threads forked in these scopes to finish. + * + * @throws IllegalStateException thrown after closing the scope if the scope + * owner did not attempt to join after forking + * @throws WrongThreadException if the current thread is not the scope owner + * @throws StructureViolationException if a structure violation was detected + */ + @Override + void close(); +} \ No newline at end of file diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScopeImpl.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScopeImpl.java new file mode 100644 index 00000000000..f65ea18e226 --- /dev/null +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScopeImpl.java @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.util.concurrent; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.time.Duration; +import java.util.Objects; +import java.util.function.Function; +import jdk.internal.misc.ThreadFlock; +import jdk.internal.invoke.MhUtil; + +/** + * StructuredTaskScope implementation. + */ +final class StructuredTaskScopeImpl implements StructuredTaskScope { + private static final VarHandle CANCELLED = + MhUtil.findVarHandle(MethodHandles.lookup(), "cancelled", boolean.class); + + private final Joiner joiner; + private final ThreadFactory threadFactory; + private final ThreadFlock flock; + + // state, only accessed by owner thread + private static final int ST_NEW = 0, + ST_FORKED = 1, // subtasks forked, need to join + ST_JOIN_STARTED = 2, // join started, can no longer fork + ST_JOIN_COMPLETED = 3, // join completed + ST_CLOSED = 4; // closed + private int state; + + // timer task, only accessed by owner thread + private Future timerTask; + + // set or read by any thread + private volatile boolean cancelled; + + // set by the timer thread, read by the owner thread + private volatile boolean timeoutExpired; + + @SuppressWarnings("this-escape") + private StructuredTaskScopeImpl(Joiner joiner, + ThreadFactory threadFactory, + String name) { + this.joiner = joiner; + this.threadFactory = threadFactory; + this.flock = ThreadFlock.open((name != null) ? name : Objects.toIdentityString(this)); + this.state = ST_NEW; + } + + /** + * Returns a new {@code StructuredTaskScope} to use the given {@code Joiner} object + * and with configuration that is the result of applying the given function to the + * default configuration. + */ + static StructuredTaskScope open(Joiner joiner, + Function configFunction) { + Objects.requireNonNull(joiner); + + var config = (ConfigImpl) configFunction.apply(ConfigImpl.defaultConfig()); + var scope = new StructuredTaskScopeImpl(joiner, config.threadFactory(), config.name()); + + // schedule timeout + Duration timeout = config.timeout(); + if (timeout != null) { + boolean scheduled = false; + try { + scope.scheduleTimeout(timeout); + scheduled = true; + } finally { + if (!scheduled) { + scope.close(); // pop if scheduling timeout failed + } + } + } + + return scope; + } + + /** + * Throws WrongThreadException if the current thread is not the owner thread. + */ + private void ensureOwner() { + if (Thread.currentThread() != flock.owner()) { + throw new WrongThreadException("Current thread not owner"); + } + } + + /** + * Throws IllegalStateException if already joined or scope is closed. + */ + private void ensureNotJoined() { + assert Thread.currentThread() == flock.owner(); + if (state > ST_FORKED) { + throw new IllegalStateException("Already joined or scope is closed"); + } + } + + /** + * Throws IllegalStateException if invoked by the owner thread and the owner thread + * has not joined. + */ + private void ensureJoinedIfOwner() { + if (Thread.currentThread() == flock.owner() && state <= ST_JOIN_STARTED) { + throw new IllegalStateException("join not called"); + } + } + + /** + * Interrupts all threads in this scope, except the current thread. + */ + private void interruptAll() { + flock.threads() + .filter(t -> t != Thread.currentThread()) + .forEach(t -> { + try { + t.interrupt(); + } catch (Throwable ignore) { } + }); + } + + /** + * Cancel the scope if not already cancelled. + */ + private void cancel() { + if (!cancelled && CANCELLED.compareAndSet(this, false, true)) { + // prevent new threads from starting + flock.shutdown(); + + // interrupt all unfinished threads + interruptAll(); + + // wakeup join + flock.wakeup(); + } + } + + /** + * Schedules a task to cancel the scope on timeout. + */ + private void scheduleTimeout(Duration timeout) { + assert Thread.currentThread() == flock.owner() && timerTask == null; + long nanos = TimeUnit.NANOSECONDS.convert(timeout); + timerTask = ForkJoinPool.commonPool().schedule(() -> { + if (!cancelled) { + timeoutExpired = true; + cancel(); + } + }, nanos, TimeUnit.NANOSECONDS); + } + + /** + * Cancels the timer task if set. + */ + private void cancelTimeout() { + assert Thread.currentThread() == flock.owner(); + if (timerTask != null) { + timerTask.cancel(false); + } + } + + /** + * Invoked by the thread for a subtask when the subtask completes before scope is cancelled. + */ + private void onComplete(SubtaskImpl subtask) { + assert subtask.state() != Subtask.State.UNAVAILABLE; + if (joiner.onComplete(subtask)) { + cancel(); + } + } + + @Override + public Subtask fork(Callable task) { + Objects.requireNonNull(task); + ensureOwner(); + ensureNotJoined(); + + var subtask = new SubtaskImpl(this, task); + + // notify joiner, even if cancelled + if (joiner.onFork(subtask)) { + cancel(); + } + + if (!cancelled) { + // create thread to run task + Thread thread = threadFactory.newThread(subtask); + if (thread == null) { + throw new RejectedExecutionException("Rejected by thread factory"); + } + + // attempt to start the thread + try { + flock.start(thread); + } catch (IllegalStateException e) { + // shutdown by another thread, or underlying flock is shutdown due + // to unstructured use + } + } + + // force owner to join + state = ST_FORKED; + return subtask; + } + + @Override + public Subtask fork(Runnable task) { + Objects.requireNonNull(task); + return fork(() -> { task.run(); return null; }); + } + + @Override + public R join() throws InterruptedException { + ensureOwner(); + ensureNotJoined(); + + // join started + state = ST_JOIN_STARTED; + + // wait for all subtasks, the scope to be cancelled, or interrupt + flock.awaitAll(); + + // throw if timeout expired + if (timeoutExpired) { + throw new TimeoutException(); + } + cancelTimeout(); + + // all subtasks completed or cancelled + state = ST_JOIN_COMPLETED; + + // invoke joiner to get result + try { + return joiner.result(); + } catch (Throwable e) { + throw new FailedException(e); + } + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void close() { + ensureOwner(); + int s = state; + if (s == ST_CLOSED) { + return; + } + + // cancel the scope if join did not complete + if (s < ST_JOIN_COMPLETED) { + cancel(); + cancelTimeout(); + } + + // wait for stragglers + try { + flock.close(); + } finally { + state = ST_CLOSED; + } + + // throw ISE if the owner didn't join after forking + if (s == ST_FORKED) { + throw new IllegalStateException("Owner did not join after forking"); + } + } + + @Override + public String toString() { + return flock.name(); + } + + /** + * Subtask implementation, runs the task specified to the fork method. + */ + static final class SubtaskImpl implements Subtask, Runnable { + private static final AltResult RESULT_NULL = new AltResult(Subtask.State.SUCCESS); + + private record AltResult(Subtask.State state, Throwable exception) { + AltResult(Subtask.State state) { + this(state, null); + } + } + + private final StructuredTaskScopeImpl scope; + private final Callable task; + private volatile Object result; + + SubtaskImpl(StructuredTaskScopeImpl scope, Callable task) { + this.scope = scope; + this.task = task; + } + + @Override + public void run() { + T result = null; + Throwable ex = null; + try { + result = task.call(); + } catch (Throwable e) { + ex = e; + } + + // nothing to do if scope is cancelled + if (scope.isCancelled()) + return; + + // set result/exception and invoke onComplete + if (ex == null) { + this.result = (result != null) ? result : RESULT_NULL; + } else { + this.result = new AltResult(State.FAILED, ex); + } + scope.onComplete(this); + } + + @Override + public Subtask.State state() { + Object result = this.result; + if (result == null) { + return State.UNAVAILABLE; + } else if (result instanceof AltResult alt) { + // null or failed + return alt.state(); + } else { + return State.SUCCESS; + } + } + + @Override + public T get() { + scope.ensureJoinedIfOwner(); + Object result = this.result; + if (result instanceof AltResult) { + if (result == RESULT_NULL) return null; + } else if (result != null) { + @SuppressWarnings("unchecked") + T r = (T) result; + return r; + } + throw new IllegalStateException( + "Result is unavailable or subtask did not complete successfully"); + } + + @Override + public Throwable exception() { + scope.ensureJoinedIfOwner(); + Object result = this.result; + if (result instanceof AltResult alt && alt.state() == State.FAILED) { + return alt.exception(); + } + throw new IllegalStateException( + "Exception is unavailable or subtask did not complete with exception"); + } + + @Override + public String toString() { + String stateAsString = switch (state()) { + case UNAVAILABLE -> "[Unavailable]"; + case SUCCESS -> "[Completed successfully]"; + case FAILED -> "[Failed: " + ((AltResult) result).exception() + "]"; + }; + return Objects.toIdentityString(this) + stateAsString; + } + } + + /** + * Configuration implementation. + */ + record ConfigImpl(ThreadFactory threadFactory, + String name, + Duration timeout) implements Configuration { + static Configuration defaultConfig() { + return new ConfigImpl(Thread.ofVirtual().factory(), null, null); + } + + @Override + public Configuration withThreadFactory(ThreadFactory threadFactory) { + return new ConfigImpl(Objects.requireNonNull(threadFactory), name, timeout); + } + + @Override + public Configuration withName(String name) { + return new ConfigImpl(threadFactory, Objects.requireNonNull(name), timeout); + } + + @Override + public Configuration withTimeout(Duration timeout) { + return new ConfigImpl(threadFactory, name, Objects.requireNonNull(timeout)); + } + } +} 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 0bf5669b6e1..029e31ef9f6 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java @@ -1251,13 +1251,19 @@ public ThreadPoolExecutor(int corePoolSize, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { - if (corePoolSize < 0 || - maximumPoolSize <= 0 || - maximumPoolSize < corePoolSize || - keepAliveTime < 0) - throw new IllegalArgumentException(); - if (workQueue == null || threadFactory == null || handler == null) - throw new NullPointerException(); + if (corePoolSize < 0) { + throw new IllegalArgumentException("corePoolSize must be non-negative"); + } else if (maximumPoolSize <= 0) { + throw new IllegalArgumentException("maximumPoolSize must be positive"); + } else if (maximumPoolSize < corePoolSize) { + throw new IllegalArgumentException("maximumPoolSize must be greater than or equal to corePoolSize"); + } else if (keepAliveTime < 0) { + throw new IllegalArgumentException("keepAliveTime must be non-negative"); + } + Objects.requireNonNull(unit, "unit"); + Objects.requireNonNull(workQueue, "workQueue"); + Objects.requireNonNull(threadFactory, "threadFactory"); + Objects.requireNonNull(handler, "handler"); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; @@ -1284,8 +1290,7 @@ public ThreadPoolExecutor(int corePoolSize, * @throws NullPointerException if {@code command} is null */ public void execute(Runnable command) { - if (command == null) - throw new NullPointerException(); + Objects.requireNonNull(command, "command"); /* * Proceed in 3 steps: * @@ -1446,8 +1451,7 @@ protected void finalize() {} * @see #getThreadFactory */ public void setThreadFactory(ThreadFactory threadFactory) { - if (threadFactory == null) - throw new NullPointerException(); + Objects.requireNonNull(threadFactory, "threadFactory"); this.threadFactory = threadFactory; } @@ -1469,8 +1473,7 @@ public ThreadFactory getThreadFactory() { * @see #getRejectedExecutionHandler */ public void setRejectedExecutionHandler(RejectedExecutionHandler handler) { - if (handler == null) - throw new NullPointerException(); + Objects.requireNonNull(handler, "handler"); this.handler = handler; } @@ -1498,8 +1501,11 @@ public RejectedExecutionHandler getRejectedExecutionHandler() { * @see #getCorePoolSize */ public void setCorePoolSize(int corePoolSize) { - if (corePoolSize < 0 || maximumPoolSize < corePoolSize) - throw new IllegalArgumentException(); + if (corePoolSize < 0) { + throw new IllegalArgumentException("corePoolSize must be non-negative"); + } else if (corePoolSize > maximumPoolSize) { + throw new IllegalArgumentException("corePoolSize must be less than or equal to maximumPoolSize"); + } int delta = corePoolSize - this.corePoolSize; this.corePoolSize = corePoolSize; if (workerCountOf(ctl.get()) > corePoolSize) @@ -1623,8 +1629,11 @@ public void allowCoreThreadTimeOut(boolean value) { * @see #getMaximumPoolSize */ public void setMaximumPoolSize(int maximumPoolSize) { - if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize) - throw new IllegalArgumentException(); + if (maximumPoolSize <= 0) { + throw new IllegalArgumentException("maximumPoolSize must be positive"); + } else if (maximumPoolSize < corePoolSize) { + throw new IllegalArgumentException("maximumPoolSize must be greater than or equal to corePoolSize"); + } this.maximumPoolSize = maximumPoolSize; if (workerCountOf(ctl.get()) > maximumPoolSize) interruptIdleWorkers(); @@ -1658,9 +1667,10 @@ public int getMaximumPoolSize() { */ public void setKeepAliveTime(long time, TimeUnit unit) { if (time < 0) - throw new IllegalArgumentException(); + throw new IllegalArgumentException("time must be non-negative"); if (time == 0 && allowsCoreThreadTimeOut()) throw new IllegalArgumentException("Core threads must have nonzero keep alive times"); + Objects.requireNonNull(unit, "unit"); long keepAliveTime = unit.toNanos(time); long delta = keepAliveTime - this.keepAliveTime; this.keepAliveTime = keepAliveTime; diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java index ff4e9fa7355..67315296a8d 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceArray.java @@ -35,10 +35,11 @@ package java.util.concurrent.atomic; +import jdk.internal.misc.Unsafe; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.lang.reflect.Array; -import java.lang.reflect.Field; import java.util.Arrays; import java.util.function.BinaryOperator; import java.util.function.UnaryOperator; @@ -330,14 +331,13 @@ private void readObject(java.io.ObjectInputStream s) throw new java.io.InvalidObjectException("Not array type"); if (a.getClass() != Object[].class) a = Arrays.copyOf((Object[])a, Array.getLength(a), Object[].class); - try { - Field arrayField = AtomicReferenceArray.class.getDeclaredField("array"); - arrayField.setAccessible(true); - arrayField.set(this, a); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new Error(e); - } + final Unsafe U = Unsafe.getUnsafe(); + U.putReference( + this, + U.objectFieldOffset(AtomicReferenceArray.class, "array"), + a + ); } // jdk9 @@ -523,5 +523,4 @@ public final boolean weakCompareAndSetAcquire(int i, E expectedValue, E newValue public final boolean weakCompareAndSetRelease(int i, E expectedValue, E newValue) { return AA.weakCompareAndSetRelease(array, i, expectedValue, newValue); } - } diff --git a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java index bdb81f3cb60..c660af6a0ba 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java @@ -1303,8 +1303,8 @@ private ConditionNode newConditionNode() { *

            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(long)} with saved state as argument. * */ public final void awaitUninterruptibly() { @@ -1346,8 +1346,8 @@ else if ((node.status & COND) != 0) { *
            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled or interrupted. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(long)} with saved state as argument. *
            • If interrupted while blocked in step 4, throw InterruptedException. * */ @@ -1398,8 +1398,8 @@ public final void await() throws InterruptedException { *
            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled, interrupted, or timed out. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(long)} with saved state as argument. *
            • If interrupted while blocked in step 4, throw InterruptedException. * */ @@ -1442,8 +1442,8 @@ public final long awaitNanos(long nanosTimeout) *
            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled, interrupted, or timed out. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(long)} with saved state as argument. *
            • If interrupted while blocked in step 4, throw InterruptedException. *
            • If timed out while blocked in step 4, return false, else true. * @@ -1485,8 +1485,8 @@ public final boolean awaitUntil(Date deadline) *
            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled, interrupted, or timed out. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(long)} with saved state as argument. *
            • If interrupted while blocked in step 4, throw InterruptedException. *
            • If timed out while blocked in step 4, return false, else true. * diff --git a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java index 5d899ffb0c5..0ff216c80a0 100644 --- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java +++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java @@ -86,9 +86,10 @@ * #isHeldExclusively} reports whether synchronization is exclusively * held with respect to the current thread, method {@link #release} * invoked with the current {@link #getState} value fully releases - * this object, and {@link #acquire}, given this saved state value, - * eventually restores this object to its previous acquired state. No - * {@code AbstractQueuedSynchronizer} method otherwise creates such a + * this object, and the underlying version of {@link #acquire(int)}, + * given this saved state value, eventually restores this object to + * its previous acquired state. + * No {@code AbstractQueuedSynchronizer} method otherwise creates such a * condition, so if this constraint cannot be met, do not use it. The * behavior of {@link ConditionObject} depends of course on the * semantics of its synchronizer implementation. @@ -1682,8 +1683,8 @@ private ConditionNode newConditionNode() { *
            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(int)} with saved state as argument. * */ public final void awaitUninterruptibly() { @@ -1725,8 +1726,8 @@ else if ((node.status & COND) != 0) { *
            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled or interrupted. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(int)} with saved state as argument. *
            • If interrupted while blocked in step 4, throw InterruptedException. * */ @@ -1777,8 +1778,8 @@ public final void await() throws InterruptedException { *
            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled, interrupted, or timed out. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(int)} with saved state as argument. *
            • If interrupted while blocked in step 4, throw InterruptedException. * */ @@ -1821,8 +1822,8 @@ public final long awaitNanos(long nanosTimeout) *
            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled, interrupted, or timed out. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(int)} with saved state as argument. *
            • If interrupted while blocked in step 4, throw InterruptedException. *
            • If timed out while blocked in step 4, return false, else true. * @@ -1864,8 +1865,8 @@ public final boolean awaitUntil(Date deadline) *
            • Invoke {@link #release} with saved state as argument, * throwing IllegalMonitorStateException if it fails. *
            • Block until signalled, interrupted, or timed out. - *
            • Reacquire by invoking specialized version of - * {@link #acquire} with saved state as argument. + *
            • Reacquire by invoking underlying version of + * {@link #acquire(int)} with saved state as argument. *
            • If interrupted while blocked in step 4, throw InterruptedException. *
            • If timed out while blocked in step 4, return false, else true. * diff --git a/src/java.base/share/classes/java/util/stream/GathererOp.java b/src/java.base/share/classes/java/util/stream/GathererOp.java index 39758bd834a..c4239b1e029 100644 --- a/src/java.base/share/classes/java/util/stream/GathererOp.java +++ b/src/java.base/share/classes/java/util/stream/GathererOp.java @@ -150,7 +150,7 @@ public void begin(long size) { final var initializer = gatherer.initializer(); if (initializer != Gatherer.defaultInitializer()) // Optimization state = initializer.get(); - sink.begin(size); + sink.begin(-1); // GathererOp does not know the size of the output } @Override diff --git a/src/java.base/share/classes/java/util/zip/Adler32.java b/src/java.base/share/classes/java/util/zip/Adler32.java index 807c08ced8a..fa2fdb1f4c3 100644 --- a/src/java.base/share/classes/java/util/zip/Adler32.java +++ b/src/java.base/share/classes/java/util/zip/Adler32.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * 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 jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.IntrinsicCandidate; -import sun.nio.ch.DirectBuffer; import static java.util.zip.ZipUtils.NIO_ACCESS; @@ -100,7 +99,7 @@ public void update(ByteBuffer buffer) { if (buffer.isDirect()) { NIO_ACCESS.acquireSession(buffer); try { - adler = updateByteBuffer(adler, ((DirectBuffer)buffer).address(), pos, rem); + adler = updateByteBuffer(adler, NIO_ACCESS.getBufferAddress(buffer), pos, rem); } finally { NIO_ACCESS.releaseSession(buffer); } diff --git a/src/java.base/share/classes/java/util/zip/CRC32.java b/src/java.base/share/classes/java/util/zip/CRC32.java index 944ccaa7e21..80b4f05a3c1 100644 --- a/src/java.base/share/classes/java/util/zip/CRC32.java +++ b/src/java.base/share/classes/java/util/zip/CRC32.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * 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.nio.ByteBuffer; import java.util.Objects; -import sun.nio.ch.DirectBuffer; import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -99,7 +98,7 @@ public void update(ByteBuffer buffer) { if (buffer.isDirect()) { NIO_ACCESS.acquireSession(buffer); try { - crc = updateByteBuffer(crc, ((DirectBuffer)buffer).address(), pos, rem); + crc = updateByteBuffer(crc, NIO_ACCESS.getBufferAddress(buffer), pos, rem); } finally { NIO_ACCESS.releaseSession(buffer); } diff --git a/src/java.base/share/classes/java/util/zip/CRC32C.java b/src/java.base/share/classes/java/util/zip/CRC32C.java index 36d37f3fe26..5b4b3597e9c 100644 --- a/src/java.base/share/classes/java/util/zip/CRC32C.java +++ b/src/java.base/share/classes/java/util/zip/CRC32C.java @@ -22,6 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package java.util.zip; import java.nio.ByteBuffer; @@ -30,7 +31,6 @@ import jdk.internal.misc.Unsafe; import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.IntrinsicCandidate; -import sun.nio.ch.DirectBuffer; import static java.util.zip.ZipUtils.NIO_ACCESS; @@ -176,7 +176,7 @@ public void update(ByteBuffer buffer) { if (buffer.isDirect()) { NIO_ACCESS.acquireSession(buffer); try { - crc = updateDirectByteBuffer(crc, ((DirectBuffer)buffer).address(), + crc = updateDirectByteBuffer(crc, NIO_ACCESS.getBufferAddress(buffer), pos, limit); } finally { NIO_ACCESS.releaseSession(buffer); 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 97a2a2d10ec..c3ce84263b2 100644 --- a/src/java.base/share/classes/java/util/zip/Deflater.java +++ b/src/java.base/share/classes/java/util/zip/Deflater.java @@ -32,7 +32,6 @@ import jdk.internal.ref.CleanerFactory; import jdk.internal.util.Preconditions; -import sun.nio.ch.DirectBuffer; import static java.util.zip.ZipUtils.NIO_ACCESS; @@ -322,7 +321,7 @@ public void setDictionary(ByteBuffer dictionary) { if (dictionary.isDirect()) { NIO_ACCESS.acquireSession(dictionary); try { - long address = ((DirectBuffer) dictionary).address(); + long address = NIO_ACCESS.getBufferAddress(dictionary); setDictionaryBuffer(zsRef.address(), address + position, remaining); } finally { NIO_ACCESS.releaseSession(dictionary); @@ -577,7 +576,7 @@ public int deflate(byte[] output, int off, int len, int flush) { if (input.isDirect()) { NIO_ACCESS.acquireSession(input); try { - long inputAddress = ((DirectBuffer) input).address(); + long inputAddress = NIO_ACCESS.getBufferAddress(input); result = deflateBufferBytes(zsRef.address(), inputAddress + inputPos, inputRem, output, off, len, @@ -701,7 +700,7 @@ public int deflate(ByteBuffer output, int flush) { if (output.isDirect()) { NIO_ACCESS.acquireSession(output); try { - long outputAddress = ((DirectBuffer) output).address(); + long outputAddress = NIO_ACCESS.getBufferAddress(output); result = deflateBytesBuffer(zsRef.address(), inputArray, inputPos, inputLim - inputPos, outputAddress + outputPos, outputRem, @@ -723,11 +722,11 @@ public int deflate(ByteBuffer output, int flush) { if (input.isDirect()) { NIO_ACCESS.acquireSession(input); try { - long inputAddress = ((DirectBuffer) input).address(); + long inputAddress = NIO_ACCESS.getBufferAddress(input); if (output.isDirect()) { NIO_ACCESS.acquireSession(output); try { - long outputAddress = outputPos + ((DirectBuffer) output).address(); + long outputAddress = outputPos + NIO_ACCESS.getBufferAddress(output); result = deflateBufferBuffer(zsRef.address(), inputAddress + inputPos, inputRem, outputAddress, outputRem, @@ -752,7 +751,7 @@ public int deflate(ByteBuffer output, int flush) { if (output.isDirect()) { NIO_ACCESS.acquireSession(output); try { - long outputAddress = ((DirectBuffer) output).address(); + long outputAddress = NIO_ACCESS.getBufferAddress(output); result = deflateBytesBuffer(zsRef.address(), inputArray, inputOffset + inputPos, inputRem, outputAddress + outputPos, outputRem, diff --git a/src/java.base/share/classes/java/util/zip/Inflater.java b/src/java.base/share/classes/java/util/zip/Inflater.java index 7c439ec812d..5ced5a4879a 100644 --- a/src/java.base/share/classes/java/util/zip/Inflater.java +++ b/src/java.base/share/classes/java/util/zip/Inflater.java @@ -32,7 +32,6 @@ import jdk.internal.ref.CleanerFactory; import jdk.internal.util.Preconditions; -import sun.nio.ch.DirectBuffer; import static java.util.zip.ZipUtils.NIO_ACCESS; @@ -243,7 +242,7 @@ public void setDictionary(ByteBuffer dictionary) { if (dictionary.isDirect()) { NIO_ACCESS.acquireSession(dictionary); try { - long address = ((DirectBuffer) dictionary).address(); + long address = NIO_ACCESS.getBufferAddress(dictionary); setDictionaryBuffer(zsRef.address(), address + position, remaining); } finally { NIO_ACCESS.releaseSession(dictionary); @@ -366,7 +365,7 @@ public int inflate(byte[] output, int off, int len) if (input.isDirect()) { NIO_ACCESS.acquireSession(input); try { - long inputAddress = ((DirectBuffer) input).address(); + long inputAddress = NIO_ACCESS.getBufferAddress(input); result = inflateBufferBytes(zsRef.address(), inputAddress + inputPos, inputRem, output, off, len); @@ -503,7 +502,7 @@ public int inflate(ByteBuffer output) throws DataFormatException { if (output.isDirect()) { NIO_ACCESS.acquireSession(output); try { - long outputAddress = ((DirectBuffer) output).address(); + long outputAddress = NIO_ACCESS.getBufferAddress(output); result = inflateBytesBuffer(zsRef.address(), inputArray, inputPos, inputLim - inputPos, outputAddress + outputPos, outputRem); @@ -528,11 +527,11 @@ public int inflate(ByteBuffer output) throws DataFormatException { if (input.isDirect()) { NIO_ACCESS.acquireSession(input); try { - long inputAddress = ((DirectBuffer) input).address(); + long inputAddress = NIO_ACCESS.getBufferAddress(input); if (output.isDirect()) { NIO_ACCESS.acquireSession(output); try { - long outputAddress = ((DirectBuffer) output).address(); + long outputAddress = NIO_ACCESS.getBufferAddress(output); result = inflateBufferBuffer(zsRef.address(), inputAddress + inputPos, inputRem, outputAddress + outputPos, outputRem); @@ -555,7 +554,7 @@ public int inflate(ByteBuffer output) throws DataFormatException { if (output.isDirect()) { NIO_ACCESS.acquireSession(output); try { - long outputAddress = ((DirectBuffer) output).address(); + long outputAddress = NIO_ACCESS.getBufferAddress(output); result = inflateBytesBuffer(zsRef.address(), inputArray, inputOffset + inputPos, inputRem, outputAddress + outputPos, outputRem); diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index 8d4a05389ee..0c3282e3518 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ import sun.nio.cs.UTF_8; /** - * Utility class for ZIP file entry name and comment decoding and encoding + * Utility class for ZIP file entry name and comment decoding and encoding. + *

              + * The {@code ZipCoder} for UTF-8 charset is thread safe, {@code ZipCoder} + * for other charsets require external synchronization. */ class ZipCoder { @@ -174,6 +177,13 @@ protected CharsetDecoder decoder() { return dec; } + /** + * {@return the {@link Charset} used by this {@code ZipCoder}} + */ + final Charset charset() { + return this.cs; + } + private CharsetEncoder encoder() { if (enc == null) { enc = cs.newEncoder() @@ -279,7 +289,7 @@ private boolean hasTrailingSlash(byte[] a, int end) { @Override byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { - byte[] encoded = JLA.getBytesNoRepl(str, UTF_8.INSTANCE); + byte[] encoded = JLA.uncheckedGetBytesNoRepl(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { return EXACT_MATCH; 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 836dda141b7..bf0bf55ff98 100644 --- a/src/java.base/share/classes/java/util/zip/ZipEntry.java +++ b/src/java.base/share/classes/java/util/zip/ZipEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ public class ZipEntry implements ZipConstants, Cloneable { byte[] extra; // optional extra field data for entry String comment; // optional comment string for entry int externalFileAttributes = -1; // File type, setuid, setgid, sticky, POSIX permissions + + // entry's LOC offset as noted in the entry's central header, -1 implies undetermined + long locOffset = -1; + /** * Compression method for uncompressed entries. */ @@ -138,6 +142,7 @@ public ZipEntry(ZipEntry e) { extra = e.extra; comment = e.comment; externalFileAttributes = e.externalFileAttributes; + locOffset = e.locOffset; } /** 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 f736a092099..7fa507980c2 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * 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,8 @@ public class ZipFile implements ZipConstants, Closeable { private final String filePath; // ZIP file path private final String fileName; // name of the file + // Used when decoding entry names and comments + private final ZipCoder zipCoder; private volatile boolean closeRequested; // The "resource" used by this ZIP file that needs to be @@ -198,7 +200,8 @@ public ZipFile(File file, int mode, Charset charset) throws IOException this.fileName = file.getName(); long t0 = System.nanoTime(); - this.res = new CleanableResource(this, ZipCoder.get(charset), file, mode); + this.zipCoder = ZipCoder.get(charset); + this.res = new CleanableResource(this, zipCoder, file, mode); PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0); PerfCounter.getZipFileCount().increment(); @@ -265,7 +268,7 @@ public String getComment() { // If there is a problem decoding the byte array which represents // the ZIP file comment, return null; try { - return res.zsrc.zc.toString(res.zsrc.comment); + return zipCoder.toString(res.zsrc.comment); } catch (IllegalArgumentException iae) { return null; } @@ -288,7 +291,7 @@ public ZipEntry getEntry(String name) { // Look up the name and CEN header position of the entry. // The resolved name may include a trailing slash. // See Source::getEntryPos for details. - EntryPos pos = res.zsrc.getEntryPos(name, true); + EntryPos pos = res.zsrc.getEntryPos(name, true, zipCoder); if (pos != null) { entry = getZipEntry(pos.name, pos.pos); } @@ -328,7 +331,7 @@ public InputStream getInputStream(ZipEntry entry) throws IOException { if (Objects.equals(lastEntryName, entry.name)) { pos = lastEntryPos; } else { - EntryPos entryPos = zsrc.getEntryPos(entry.name, false); + EntryPos entryPos = zsrc.getEntryPos(entry.name, false, zipCoder); if (entryPos != null) { pos = entryPos.pos; } else { @@ -338,7 +341,7 @@ public InputStream getInputStream(ZipEntry entry) throws IOException { if (pos == -1) { return null; } - in = new ZipFileInputStream(zsrc.cen, pos); + in = new ZipFileInputStream(zsrc.cen, pos, entry.locOffset); switch (CENHOW(zsrc.cen, pos)) { case STORED: synchronized (istreams) { @@ -348,11 +351,11 @@ public InputStream getInputStream(ZipEntry entry) throws IOException { case DEFLATED: // Inflater likes a bit of slack // MORE: Compute good size for inflater stream: - long size = CENSIZ(zsrc.cen, pos); - if (size > 65536) { - size = 8192; + long inputBufSize = CENSIZ(zsrc.cen, pos); + if (inputBufSize > 65536 || inputBufSize <= 0) { + inputBufSize = 8192; } - InputStream is = new ZipFileInflaterInputStream(in, res, (int) size); + InputStream is = new ZipFileInflaterInputStream(in, res, (int) inputBufSize); synchronized (istreams) { istreams.add(is); } @@ -363,6 +366,35 @@ public InputStream getInputStream(ZipEntry entry) throws IOException { } } + /** + * Determines and returns a {@link ZipCoder} to use for decoding + * name and comment fields of the ZIP entry identified by the {@code pos} + * in the ZIP file's {@code cen}. + *

              + * A ZIP entry's name and comment fields may be encoded using UTF-8, in + * which case this method returns a UTF-8 capable {@code ZipCoder}. If the + * entry doesn't require UTF-8, then this method returns the {@code fallback} + * {@code ZipCoder}. + * + * @param cen the CEN + * @param pos the ZIP entry's position in CEN + * @param fallback the fallback ZipCoder to return if the entry doesn't require UTF-8 + */ + private static ZipCoder zipCoderFor(final byte[] cen, final int pos, final ZipCoder fallback) { + if (fallback.isUTF8()) { + // the fallback ZipCoder is capable of handling UTF-8, + // so no need to parse the entry flags to determine if + // the entry has UTF-8 flag. + return fallback; + } + if ((CENFLG(cen, pos) & USE_UTF8) != 0) { + // entry requires a UTF-8 ZipCoder + return ZipCoder.UTF8; + } + // entry doesn't require a UTF-8 ZipCoder + return fallback; + } + private static class InflaterCleanupAction implements Runnable { private final Inflater inf; private final CleanableResource res; @@ -384,14 +416,14 @@ private class ZipFileInflaterInputStream extends InflaterInputStream { private final Cleanable cleanable; ZipFileInflaterInputStream(ZipFileInputStream zfin, - CleanableResource res, int size) { - this(zfin, res, res.getInflater(), size); + CleanableResource res, int inputBufSize) { + this(zfin, res, res.getInflater(), inputBufSize); } private ZipFileInflaterInputStream(ZipFileInputStream zfin, CleanableResource res, - Inflater inf, int size) { - super(zfin, inf, size); + Inflater inf, int inputBufSize) { + super(zfin, inf, inputBufSize); this.cleanable = CleanerFactory.cleaner().register(this, new InflaterCleanupAction(inf, res)); } @@ -561,7 +593,7 @@ public Stream stream() { private String getEntryName(int pos) { byte[] cen = res.zsrc.cen; int nlen = CENNAM(cen, pos); - ZipCoder zc = res.zsrc.zipCoderForPos(pos); + ZipCoder zc = zipCoderFor(cen, pos, zipCoder); return zc.toString(cen, pos + CENHDR, nlen); } @@ -621,6 +653,7 @@ private ZipEntry getZipEntry(String name, int pos) { // read all bits in this field, including sym link attributes e.externalFileAttributes = CENATX_PERMS(cen, pos) & 0xFFFF; } + e.locOffset = CENOFF(cen, pos); int nlen = CENNAM(cen, pos); int elen = CENEXT(cen, pos); @@ -632,7 +665,7 @@ private ZipEntry getZipEntry(String name, int pos) { } if (clen != 0) { int start = pos + CENHDR + nlen + elen; - ZipCoder zc = res.zsrc.zipCoderForPos(pos); + ZipCoder zc = zipCoderFor(cen, pos, zipCoder); e.comment = zc.toString(cen, start, clen); } lastEntryName = e.name; @@ -664,11 +697,12 @@ private static class CleanableResource implements Runnable { Source zsrc; - CleanableResource(ZipFile zf, ZipCoder zc, File file, int mode) throws IOException { + CleanableResource(ZipFile zf, ZipCoder zipCoder, File file, int mode) throws IOException { + assert zipCoder != null : "null ZipCoder"; this.cleanable = CleanerFactory.cleaner().register(zf, this); this.istreams = Collections.newSetFromMap(new WeakHashMap<>()); this.inflaterCache = new ArrayDeque<>(); - this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0, zc); + this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0, zipCoder); } void clean() { @@ -814,10 +848,21 @@ private class ZipFileInputStream extends InputStream { protected long rem; // number of remaining bytes within entry protected long size; // uncompressed size of this entry - ZipFileInputStream(byte[] cen, int cenpos) { + /** + * @param cen the ZIP's CEN + * @param cenpos the entry's offset within the CEN + * @param locOffset the entry's LOC offset in the ZIP stream. If -1 is passed + * then the LOC offset for the entry will be read from the + * entry's central header + */ + ZipFileInputStream(byte[] cen, int cenpos, long locOffset) { rem = CENSIZ(cen, cenpos); size = CENLEN(cen, cenpos); - pos = CENOFF(cen, cenpos); + if (locOffset == -1) { + pos = CENOFF(cen, cenpos); + } else { + pos = locOffset; + } // ZIP64 if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL || pos == ZIP64_MAGICVAL) { @@ -1109,6 +1154,7 @@ public void setExternalFileAttributes(ZipEntry ze, int externalFileAttributes) { // Represents the resolved name and position of a CEN record static record EntryPos(String name, int pos) {} + // Implementation note: This class is thread safe. private static class Source { // While this is only used from ZipFile, defining it there would cause // a bootstrap cycle that would leave this initialized as null @@ -1121,7 +1167,6 @@ private static class Source { private static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; private final Key key; // the key in files - private final @Stable ZipCoder zc; // ZIP coder used to decode/encode private int refs = 1; @@ -1157,8 +1202,9 @@ private static class Source { private int[] entries; // array of hashed cen entry // Checks the entry at offset pos in the CEN, calculates the Entry values as per above, - // then returns the length of the entry name. - private int checkAndAddEntry(int pos, int index) + // then returns the length of the entry name. Uses the given zipCoder for processing the + // entry name and the entry comment (if any). + private int checkAndAddEntry(final int pos, final int index, final ZipCoder zipCoder) throws ZipException { byte[] cen = this.cen; @@ -1196,21 +1242,20 @@ private int checkAndAddEntry(int pos, int index) } try { - ZipCoder zcp = zipCoderForPos(pos); - int hash = zcp.checkedHash(cen, entryPos, nlen); + int hash = zipCoder.checkedHash(cen, entryPos, nlen); int hsh = (hash & 0x7fffffff) % tablelen; int next = table[hsh]; table[hsh] = index; // Record the CEN offset and the name hash in our hash cell. - entries[index++] = hash; - entries[index++] = next; - entries[index ] = pos; + entries[index] = hash; + entries[index + 1] = next; + entries[index + 2] = 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 if (clen > 0) { int start = entryPos + nlen + elen; - zcp.toString(cen, start, clen); + zipCoder.toString(cen, start, clen); } } catch (Exception e) { zerror("invalid CEN header (bad entry name or comment)"); @@ -1389,34 +1434,47 @@ private static boolean isZip64ExtBlockSizeValid(int blockSize, long csize, private int tablelen; // number of hash heads /** - * A class representing a key to a ZIP file. A key is based - * on the file key if available, or the path value if the - * file key is not available. The key is also based on the - * file's last modified time to allow for cases where a ZIP - * file is re-opened after it has been modified. + * A class representing a key to the Source of a ZipFile. + * The Key is composed of: + * - The BasicFileAttributes.fileKey() if available, or the Path of the ZIP file + * if the fileKey() is not available. + * - The ZIP file's last modified time (to allow for cases + * where a ZIP file is re-opened after it has been modified). + * - The Charset that was provided when constructing the ZipFile instance. + * The unique combination of these components identifies a Source of a ZipFile. */ private static class Key { - final BasicFileAttributes attrs; - File file; - final boolean utf8; - - public Key(File file, BasicFileAttributes attrs, ZipCoder zc) { + private final BasicFileAttributes attrs; + private final File file; + // the Charset that was provided when constructing the ZipFile instance + private final Charset charset; + + /** + * Constructs a {@code Key} to a {@code Source} of a {@code ZipFile} + * + * @param file the ZIP file + * @param attrs the attributes of the ZIP file + * @param charset the Charset that was provided when constructing the ZipFile instance + */ + public Key(File file, BasicFileAttributes attrs, Charset charset) { this.attrs = attrs; this.file = file; - this.utf8 = zc.isUTF8(); + this.charset = charset; } + @Override public int hashCode() { - long t = utf8 ? 0 : Long.MAX_VALUE; + long t = charset.hashCode(); t += attrs.lastModifiedTime().toMillis(); Object fk = attrs.fileKey(); return Long.hashCode(t) + (fk != null ? fk.hashCode() : file.hashCode()); } + @Override public boolean equals(Object obj) { if (obj instanceof Key key) { - if (key.utf8 != utf8) { + if (!charset.equals(key.charset)) { return false; } if (!attrs.lastModifiedTime().equals(key.attrs.lastModifiedTime())) { @@ -1440,12 +1498,12 @@ public boolean equals(Object obj) { private static final java.nio.file.FileSystem builtInFS = DefaultFileSystemProvider.theFileSystem(); - static Source get(File file, boolean toDelete, ZipCoder zc) throws IOException { + static Source get(File file, boolean toDelete, ZipCoder zipCoder) throws IOException { final Key key; try { key = new Key(file, Files.readAttributes(builtInFS.getPath(file.getPath()), - BasicFileAttributes.class), zc); + BasicFileAttributes.class), zipCoder.charset()); } catch (InvalidPathException ipe) { throw new IOException(ipe); } @@ -1457,7 +1515,7 @@ static Source get(File file, boolean toDelete, ZipCoder zc) throws IOException { return src; } } - src = new Source(key, toDelete, zc); + src = new Source(key, toDelete, zipCoder); synchronized (files) { Source prev = files.putIfAbsent(key, src); @@ -1479,8 +1537,7 @@ static void release(Source src) throws IOException { } } - private Source(Key key, boolean toDelete, ZipCoder zc) throws IOException { - this.zc = zc; + private Source(Key key, boolean toDelete, ZipCoder zipCoder) throws IOException { this.key = key; if (toDelete) { if (OperatingSystem.isWindows()) { @@ -1494,7 +1551,7 @@ private Source(Key key, boolean toDelete, ZipCoder zc) throws IOException { this.zfile = new RandomAccessFile(key.file, "r"); } try { - initCEN(-1); + initCEN(-1, zipCoder); byte[] buf = new byte[4]; readFullyAt(buf, 0, 4, 0); this.startsWithLoc = (LOCSIG(buf) == LOCSIG); @@ -1649,7 +1706,7 @@ private End findEND() throws IOException { } // Reads ZIP file central directory. - private void initCEN(int knownTotal) throws IOException { + private void initCEN(final int knownTotal, final ZipCoder zipCoder) throws IOException { // Prefer locals for better performance during startup byte[] cen; if (knownTotal == -1) { @@ -1711,13 +1768,15 @@ private void initCEN(int knownTotal) throws IOException { // This will only happen if the ZIP file has an incorrect // ENDTOT field, which usually means it contains more than // 65535 entries. - initCEN(countCENHeaders(cen)); + initCEN(countCENHeaders(cen), zipCoder); return; } int entryPos = pos + CENHDR; + // the ZipCoder for any non-UTF8 entries + final ZipCoder entryZipCoder = zipCoderFor(cen, pos, zipCoder); // Checks the entry and adds values to entries[idx ... idx+2] - int nlen = checkAndAddEntry(pos, idx); + int nlen = checkAndAddEntry(pos, idx, entryZipCoder); idx += 3; // Adds name to metanames. @@ -1741,7 +1800,7 @@ private void initCEN(int knownTotal) throws IOException { try { // Compute hash code of name from "META-INF/versions/{version)/{name} int prefixLen = META_INF_VERSIONS_LEN + DecimalDigits.stringSize(version); - int hashCode = zipCoderForPos(pos).checkedHash(cen, + int hashCode = entryZipCoder.checkedHash(cen, entryPos + prefixLen, nlen - prefixLen); // Register version for this hash code @@ -1786,9 +1845,10 @@ private static void zerror(String msg) throws ZipException { /* * Returns the resolved name and position of the ZIP cen entry corresponding - * to the specified entry name, or {@code null} if not found. + * to the specified entry name, or {@code null} if not found. */ - private EntryPos getEntryPos(String name, boolean addSlash) { + private EntryPos getEntryPos(final String name, final boolean addSlash, + final ZipCoder zipCoder) { if (total == 0) { return null; } @@ -1807,8 +1867,7 @@ private EntryPos getEntryPos(String name, boolean addSlash) { int noff = pos + CENHDR; int nlen = CENNAM(cen, pos); - ZipCoder zc = zipCoderForPos(pos); - + final ZipCoder zc = zipCoderFor(cen, pos, zipCoder); // Compare the lookup name with the name encoded in the CEN switch (zc.compare(name, cen, noff, nlen, addSlash)) { case ZipCoder.EXACT_MATCH: @@ -1834,16 +1893,6 @@ private EntryPos getEntryPos(String name, boolean addSlash) { return null; } - private ZipCoder zipCoderForPos(int pos) { - if (zc.isUTF8()) { - return zc; - } - if ((CENFLG(cen, pos) & USE_UTF8) != 0) { - return ZipCoder.UTF8; - } - return zc; - } - /** * Returns true if the bytes represent a non-directory name * beginning with "META-INF/", disregarding ASCII case. diff --git a/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java b/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java index 1e4e769a83e..90316d7437e 100644 --- a/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java +++ b/src/java.base/share/classes/javax/crypto/EncryptedPrivateKeyInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,18 @@ package javax.crypto; -import java.io.*; +import jdk.internal.javac.PreviewFeature; + +import sun.security.jca.JCAUtil; +import sun.security.pkcs.PKCS8Key; +import sun.security.util.*; +import sun.security.x509.AlgorithmId; + +import javax.crypto.spec.PBEKeySpec; +import java.io.IOException; import java.security.*; import java.security.spec.*; -import sun.security.x509.AlgorithmId; -import sun.security.util.DerValue; -import sun.security.util.DerInputStream; -import sun.security.util.DerOutputStream; +import java.util.Objects; /** * This class implements the {@code EncryptedPrivateKeyInfo} type @@ -55,14 +60,14 @@ * @since 1.4 */ -public class EncryptedPrivateKeyInfo { +public non-sealed class EncryptedPrivateKeyInfo implements DEREncodable { // The "encryptionAlgorithm" is stored in either the algid or // the params field. Precisely, if this object is created by // {@link #EncryptedPrivateKeyInfo(AlgorithmParameters, byte[])} // with an uninitialized AlgorithmParameters, the AlgorithmParameters // object is stored in the params field and algid is set to null. - // In all other cases, algid is non null and params is null. + // In all other cases, algid is non-null and params is null. private final AlgorithmId algid; private final AlgorithmParameters params; @@ -73,19 +78,15 @@ public class EncryptedPrivateKeyInfo { private final byte[] encoded; /** - * Constructs (i.e., parses) an {@code EncryptedPrivateKeyInfo} from - * its ASN.1 encoding. + * Constructs an {@code EncryptedPrivateKeyInfo} from a given encrypted + * PKCS#8 ASN.1 encoding. * @param encoded the ASN.1 encoding of this object. The contents of * the array are copied to protect against subsequent modification. - * @exception NullPointerException if the {@code encoded} is - * {@code null}. - * @exception IOException if error occurs when parsing the ASN.1 encoding. + * @throws NullPointerException if {@code encoded} is {@code null}. + * @throws IOException if error occurs when parsing the ASN.1 encoding. */ public EncryptedPrivateKeyInfo(byte[] encoded) throws IOException { - if (encoded == null) { - throw new NullPointerException("the encoded parameter " + - "must be non-null"); - } + Objects.requireNonNull(encoded); this.encoded = encoded.clone(); DerValue val = DerValue.wrap(this.encoded); @@ -201,7 +202,7 @@ public EncryptedPrivateKeyInfo(AlgorithmParameters algParams, tmp = null; } - // one and only one is non null + // one and only one is non-null this.algid = tmp; this.params = this.algid != null ? null : algParams; @@ -219,6 +220,17 @@ public EncryptedPrivateKeyInfo(AlgorithmParameters algParams, this.encoded = null; } + /** + * Create an EncryptedPrivateKeyInfo object from the given components + */ + private EncryptedPrivateKeyInfo(byte[] encoded, byte[] eData, + AlgorithmId id, AlgorithmParameters p) { + this.encoded = encoded; + encryptedData = eData; + algid = id; + params = p; + } + /** * Returns the encryption algorithm. *

              Note: Standard name is returned instead of the specified one @@ -308,6 +320,242 @@ private PKCS8EncodedKeySpec getKeySpecImpl(Key decryptKey, } } + /** + * Creates and encrypts an {@code EncryptedPrivateKeyInfo} from a given + * {@code PrivateKey}. A valid password-based encryption (PBE) algorithm + * and password must be specified. + * + *

              The PBE algorithm string format details can be found in the + * + * Cipher section of the Java Security Standard Algorithm Names + * Specification. + * + * @param key the {@code PrivateKey} to be encrypted + * @param password the password used in the PBE encryption. This array + * will be cloned before being used. + * @param algorithm the PBE encryption algorithm. The default algorithm + * will be used if {@code null}. However, {@code null} is + * not allowed when {@code params} is non-null. + * @param params the {@code AlgorithmParameterSpec} to be used with + * encryption. The provider default will be used if + * {@code null}. + * @param provider the {@code Provider} will be used for PBE + * {@link SecretKeyFactory} generation and {@link Cipher} + * encryption operations. The default provider list will be + * used if {@code null}. + * @return an {@code EncryptedPrivateKeyInfo} + * @throws IllegalArgumentException on initialization errors based on the + * arguments passed to the method + * @throws RuntimeException on an encryption error + * @throws NullPointerException if the key or password are {@code null}. If + * {@code params} is non-null when {@code algorithm} is {@code null}. + * + * @implNote The {@code jdk.epkcs8.defaultAlgorithm} Security Property + * defines the default encryption algorithm and the + * {@code AlgorithmParameterSpec} are the provider's algorithm defaults. + * + * @since 25 + */ + @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) + public static EncryptedPrivateKeyInfo encryptKey(PrivateKey key, + char[] password, String algorithm, AlgorithmParameterSpec params, + Provider provider) { + + SecretKey skey; + Objects.requireNonNull(key, "key cannot be null"); + Objects.requireNonNull(password, "password cannot be null."); + PBEKeySpec keySpec = new PBEKeySpec(password); + if (algorithm == null) { + if (params != null) { + throw new NullPointerException("algorithm must be specified" + + " if params is non-null."); + } + algorithm = Pem.DEFAULT_ALGO; + } + + try { + SecretKeyFactory factory; + if (provider == null) { + factory = SecretKeyFactory.getInstance(algorithm); + } else { + factory = SecretKeyFactory.getInstance(algorithm, provider); + } + skey = factory.generateSecret(keySpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + throw new IllegalArgumentException(e); + } + return encryptKeyImpl(key, algorithm, skey, params, provider, null); + } + + /** + * Creates and encrypts an {@code EncryptedPrivateKeyInfo} from a given + * {@code PrivateKey} and password. Default algorithm and parameters are + * used. + * + * @param key the {@code PrivateKey} to be encrypted + * @param password the password used in the PBE encryption. This array + * will be cloned before being used. + * @return an {@code EncryptedPrivateKeyInfo} + * @throws IllegalArgumentException on initialization errors based on the + * arguments passed to the method + * @throws RuntimeException on an encryption error + * @throws NullPointerException when the {@code key} or {@code password} + * is {@code null} + * + * @implNote The {@code jdk.epkcs8.defaultAlgorithm} Security Property + * defines the default encryption algorithm and the + * {@code AlgorithmParameterSpec} are the provider's algorithm defaults. + * + * @since 25 + */ + @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) + public static EncryptedPrivateKeyInfo encryptKey(PrivateKey key, + char[] password) { + return encryptKey(key, password, Pem.DEFAULT_ALGO, null, null); + } + + /** + * Creates and encrypts an {@code EncryptedPrivateKeyInfo} from the given + * {@link PrivateKey} using the {@code encKey} and given parameters. + * + * @param key the {@code PrivateKey} to be encrypted + * @param encKey the password-based encryption (PBE) {@code Key} used to + * encrypt {@code key}. + * @param algorithm the PBE encryption algorithm. The default algorithm is + * will be used if {@code null}; however, {@code null} is + * not allowed when {@code params} is non-null. + * @param params the {@code AlgorithmParameterSpec} to be used with + * encryption. The provider list default will be used if + * {@code null}. + * @param random the {@code SecureRandom} instance used during + * encryption. The default will be used if {@code null}. + * @param provider the {@code Provider} is used for {@link Cipher} + * encryption operation. The default provider list will be + * used if {@code null}. + * @return an {@code EncryptedPrivateKeyInfo} + * @throws IllegalArgumentException on initialization errors based on the + * arguments passed to the method + * @throws RuntimeException on an encryption error + * @throws NullPointerException if the {@code key} or {@code encKey} are + * {@code null}. If {@code params} is non-null, {@code algorithm} cannot be + * {@code null}. + * + * @implNote The {@code jdk.epkcs8.defaultAlgorithm} Security Property + * defines the default encryption algorithm and the + * {@code AlgorithmParameterSpec} are the provider's algorithm defaults. + * + * @since 25 + */ + @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) + public static EncryptedPrivateKeyInfo encryptKey(PrivateKey key, Key encKey, + String algorithm, AlgorithmParameterSpec params, Provider provider, + SecureRandom random) { + + Objects.requireNonNull(key); + Objects.requireNonNull(encKey); + if (algorithm == null) { + if (params != null) { + throw new NullPointerException("algorithm must be specified " + + "if params is non-null."); + } + algorithm = Pem.DEFAULT_ALGO; + } + return encryptKeyImpl(key, algorithm, encKey, params, provider, random); + } + + private static EncryptedPrivateKeyInfo encryptKeyImpl(PrivateKey key, + String algorithm, Key encryptKey, AlgorithmParameterSpec params, + Provider provider, SecureRandom random) { + AlgorithmId algId; + byte[] encryptedData; + Cipher c; + DerOutputStream out; + + if (random == null) { + random = JCAUtil.getDefSecureRandom(); + } + try { + if (provider == null) { + c = Cipher.getInstance(algorithm); + } else { + c = Cipher.getInstance(algorithm, provider); + } + c.init(Cipher.ENCRYPT_MODE, encryptKey, params, random); + encryptedData = c.doFinal(key.getEncoded()); + algId = new AlgorithmId(Pem.getPBEID(algorithm), c.getParameters()); + out = new DerOutputStream(); + algId.encode(out); + out.putOctetString(encryptedData); + } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | + NoSuchPaddingException e) { + throw new IllegalArgumentException(e); + } catch (IllegalBlockSizeException | BadPaddingException | + InvalidKeyException e) { + throw new RuntimeException(e); + } + return new EncryptedPrivateKeyInfo( + DerValue.wrap(DerValue.tag_Sequence, out).toByteArray(), + encryptedData, algId, c.getParameters()); + } + + /** + * Extract the enclosed {@code PrivateKey} object from the encrypted data + * and return it. + * + * @param password the password used in the PBE encryption. This array + * will be cloned before being used. + * @return a {@code PrivateKey} + * @throws GeneralSecurityException if an error occurs parsing or + * decrypting the encrypted data, or producing the key object. + * @throws NullPointerException if {@code password} is null + * + * @since 25 + */ + @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) + public PrivateKey getKey(char[] password) throws GeneralSecurityException { + SecretKeyFactory skf; + PKCS8EncodedKeySpec p8KeySpec; + Objects.requireNonNull(password, "password cannot be null"); + PBEKeySpec keySpec = new PBEKeySpec(password); + skf = SecretKeyFactory.getInstance(getAlgName()); + p8KeySpec = getKeySpec(skf.generateSecret(keySpec)); + + return PKCS8Key.parseKey(p8KeySpec.getEncoded()); + } + + /** + * Extract the enclosed {@code PrivateKey} object from the encrypted data + * and return it. + * + * @param decryptKey the decryption key and cannot be {@code null} + * @param provider the {@code Provider} used for Cipher decryption and + * {@code PrivateKey} generation. A {@code null} value will + * use the default provider configuration. + * @return a {@code PrivateKey} + * @throws GeneralSecurityException if an error occurs parsing or + * decrypting the encrypted data, or producing the key object. + * @throws NullPointerException if {@code decryptKey} is null + * + * @since 25 + */ + @PreviewFeature(feature = PreviewFeature.Feature.PEM_API) + public PrivateKey getKey(Key decryptKey, Provider provider) + throws GeneralSecurityException { + Objects.requireNonNull(decryptKey,"decryptKey cannot be null."); + PKCS8EncodedKeySpec p = getKeySpecImpl(decryptKey, provider); + try { + if (provider == null) { + return KeyFactory.getInstance( + KeyUtil.getAlgorithm(p.getEncoded())). + generatePrivate(p); + } + return KeyFactory.getInstance(KeyUtil.getAlgorithm(p.getEncoded()), + provider).generatePrivate(p); + } catch (IOException e) { + throw new GeneralSecurityException(e); + } + } + /** * Extract the enclosed PKCS8EncodedKeySpec object from the * encrypted data and return it. @@ -353,12 +601,8 @@ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey) public PKCS8EncodedKeySpec getKeySpec(Key decryptKey, String providerName) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException { - if (decryptKey == null) { - throw new NullPointerException("decryptKey is null"); - } - if (providerName == null) { - throw new NullPointerException("provider is null"); - } + Objects.requireNonNull(decryptKey, "decryptKey is null"); + Objects.requireNonNull(providerName, "provider is null"); Provider provider = Security.getProvider(providerName); if (provider == null) { throw new NoSuchProviderException("provider " + @@ -387,12 +631,8 @@ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey, public PKCS8EncodedKeySpec getKeySpec(Key decryptKey, Provider provider) throws NoSuchAlgorithmException, InvalidKeyException { - if (decryptKey == null) { - throw new NullPointerException("decryptKey is null"); - } - if (provider == null) { - throw new NullPointerException("provider is null"); - } + Objects.requireNonNull(decryptKey, "decryptKey is null"); + Objects.requireNonNull(provider, "provider is null"); return getKeySpecImpl(decryptKey, provider); } @@ -438,23 +678,9 @@ private static void checkTag(DerValue val, byte tag, String valName) } } - @SuppressWarnings("fallthrough") private static PKCS8EncodedKeySpec pkcs8EncodingToSpec(byte[] encodedKey) throws IOException { - DerInputStream in = new DerInputStream(encodedKey); - DerValue[] values = in.getSequence(3); - - switch (values.length) { - case 4: - checkTag(values[3], DerValue.TAG_CONTEXT, "attributes"); - /* fall through */ - case 3: - checkTag(values[0], DerValue.tag_Integer, "version"); - String keyAlg = AlgorithmId.parse(values[1]).getName(); - checkTag(values[2], DerValue.tag_OctetString, "privateKey"); - return new PKCS8EncodedKeySpec(encodedKey, keyAlg); - default: - throw new IOException("invalid key encoding"); - } + return new PKCS8EncodedKeySpec(encodedKey, + KeyUtil.getAlgorithm(encodedKey)); } } diff --git a/src/java.base/share/classes/javax/crypto/KDF.java b/src/java.base/share/classes/javax/crypto/KDF.java index 5c9c7e71ce4..ec7bcfa199c 100644 --- a/src/java.base/share/classes/javax/crypto/KDF.java +++ b/src/java.base/share/classes/javax/crypto/KDF.java @@ -25,7 +25,6 @@ package javax.crypto; -import jdk.internal.javac.PreviewFeature; import sun.security.jca.GetInstance; import sun.security.jca.GetInstance.Instance; import sun.security.util.Debug; @@ -98,9 +97,8 @@ * * @see KDFParameters * @see SecretKey - * @since 24 + * @since 25 */ -@PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) public final class KDF { private static final Debug pdebug = Debug.getInstance("provider", @@ -479,6 +477,25 @@ private static KDF handleException(NoSuchAlgorithmException e) throw e; } + // Rethrows the IAPE thrown by an implementation, adding an explanation + // for the situation in which it fails. + private void rethrow(InvalidAlgorithmParameterException e) + throws InvalidAlgorithmParameterException { + var source = serviceIterator == null + ? "specified" : "previously selected"; + if (!skipDebug && pdebug != null) { + pdebug.println("A " + this.getAlgorithm() + + " derivation cannot be performed " + + "using the supplied derivation " + + "inputs with the " + source + " " + + theOne.provider().getName() + + " provider."); + } + throw new InvalidAlgorithmParameterException( + "The " + source + " " + theOne.provider.getName() + + " provider does not support this input", e); + } + /** * Derives a key, returned as a {@code SecretKey} object. * @@ -523,7 +540,12 @@ public SecretKey deriveKey(String alg, } Objects.requireNonNull(derivationSpec); if (checkSpiNonNull(theOne)) { - return theOne.spi().engineDeriveKey(alg, derivationSpec); + try { + return theOne.spi().engineDeriveKey(alg, derivationSpec); + } catch (InvalidAlgorithmParameterException e) { + rethrow(e); + return null; // will not be called + } } else { return (SecretKey) chooseProvider(alg, derivationSpec); } @@ -554,7 +576,12 @@ public byte[] deriveData(AlgorithmParameterSpec derivationSpec) Objects.requireNonNull(derivationSpec); if (checkSpiNonNull(theOne)) { - return theOne.spi().engineDeriveData(derivationSpec); + try { + return theOne.spi().engineDeriveData(derivationSpec); + } catch (InvalidAlgorithmParameterException e) { + rethrow(e); + return null; // will not be called + } } else { try { return (byte[]) chooseProvider(null, derivationSpec); @@ -613,6 +640,11 @@ private Object chooseProvider(String algorithm, derivationSpec); // found a working KDFSpi this.theOne = currOne; + if (!skipDebug && pdebug != null) { + pdebug.println("The provider " + + currOne.provider().getName() + + " is selected"); + } return result; } catch (Exception e) { if (!skipDebug && pdebug != null) { @@ -649,7 +681,8 @@ private Object chooseProvider(String algorithm, e.printStackTrace(pdebug.getPrintStream()); } // getNext reached end without finding an implementation - throw new InvalidAlgorithmParameterException(lastException); + throw new InvalidAlgorithmParameterException( + "No provider supports this input", lastException); } } } diff --git a/src/java.base/share/classes/javax/crypto/KDFParameters.java b/src/java.base/share/classes/javax/crypto/KDFParameters.java index 5f83204f3c4..b9bd2765883 100644 --- a/src/java.base/share/classes/javax/crypto/KDFParameters.java +++ b/src/java.base/share/classes/javax/crypto/KDFParameters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,8 +24,6 @@ */ package javax.crypto; -import jdk.internal.javac.PreviewFeature; - /** * A specification of Key Derivation Function ({@link KDF}) parameters. *

              @@ -44,7 +42,6 @@ * @see KDF#getInstance(String, KDFParameters) * @see KDF#getParameters() * @see KDF - * @since 24 + * @since 25 */ -@PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) public interface KDFParameters {} diff --git a/src/java.base/share/classes/javax/crypto/KDFSpi.java b/src/java.base/share/classes/javax/crypto/KDFSpi.java index e2625a1930d..6d0eb90b397 100644 --- a/src/java.base/share/classes/javax/crypto/KDFSpi.java +++ b/src/java.base/share/classes/javax/crypto/KDFSpi.java @@ -25,8 +25,6 @@ package javax.crypto; -import jdk.internal.javac.PreviewFeature; - import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.spec.AlgorithmParameterSpec; @@ -69,9 +67,8 @@ * @see KDFParameters * @see KDF#getParameters() * @see SecretKey - * @since 24 + * @since 25 */ -@PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) public abstract class KDFSpi { /** diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index f19d3306266..58089b38666 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.java @@ -707,8 +707,8 @@ public Encapsulator newEncapsulator(PublicKey publicKey, SecureRandom secureRand * the same key can be used to derive shared secrets in different ways. * If any extra information inside this object needs to be transmitted along * with the key encapsulation message so that the receiver is able to create - * a matching decapsulator, it will be included as a byte array in the - * {@link Encapsulated#params} field inside the encapsulation output. + * a matching decapsulator, it will be included as a byte array returned by the + * {@link Encapsulated#params()} method within the encapsulation output. * In this case, the security provider should provide an * {@code AlgorithmParameters} implementation using the same algorithm name * as the KEM. The receiver can initiate such an {@code AlgorithmParameters} diff --git a/src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.java index 8f697d12e60..c4ca9e1e183 100644 --- a/src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/HKDFParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,6 @@ package javax.crypto.spec; -import jdk.internal.javac.PreviewFeature; - import javax.crypto.SecretKey; import java.security.spec.AlgorithmParameterSpec; import java.util.ArrayList; @@ -75,9 +73,8 @@ * @spec https://www.rfc-editor.org/info/rfc5869 * RFC 5869: HMAC-based Extract-and-Expand Key Derivation Function (HKDF) * @see javax.crypto.KDF - * @since 24 + * @since 25 */ -@PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) public interface HKDFParameterSpec extends AlgorithmParameterSpec { /** @@ -92,7 +89,6 @@ public interface HKDFParameterSpec extends AlgorithmParameterSpec { * use-cases respectively. Note that the {@code Builder} is not * thread-safe. */ - @PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) final class Builder { private List ikms = new ArrayList<>(); @@ -296,7 +292,6 @@ static Expand expandOnly(SecretKey prk, byte[] info, int length) { * Defines the input parameters of an Extract operation as defined in RFC 5869. */ - @PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) final class Extract implements HKDFParameterSpec { // HKDF-Extract(salt, IKM) -> PRK @@ -350,7 +345,6 @@ public List salts() { * Defines the input parameters of an Expand operation as defined in RFC 5869. */ - @PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) final class Expand implements HKDFParameterSpec { // HKDF-Expand(PRK, info, L) -> OKM @@ -419,7 +413,6 @@ public int length() { * Defines the input parameters of an Extract-then-Expand operation as * defined in RFC 5869. */ - @PreviewFeature(feature = PreviewFeature.Feature.KEY_DERIVATION) final class ExtractThenExpand implements HKDFParameterSpec { private final Extract ext; private final Expand exp; diff --git a/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java b/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java index e37e3872ff2..0e664510324 100644 --- a/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java +++ b/src/java.base/share/classes/javax/crypto/spec/RC2ParameterSpec.java @@ -98,7 +98,12 @@ public RC2ParameterSpec(int effectiveKeyBits, byte[] iv) { */ public RC2ParameterSpec(int effectiveKeyBits, byte[] iv, int offset) { this.effectiveKeyBits = effectiveKeyBits; - if (iv == null) throw new IllegalArgumentException("IV missing"); + if (iv == null) { + throw new IllegalArgumentException("IV missing"); + } + if (offset < 0) { + throw new ArrayIndexOutOfBoundsException("offset is negative"); + } int blockSize = 8; if (iv.length - offset < blockSize) { throw new IllegalArgumentException("IV too short"); diff --git a/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java b/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java index 2b98f4845cf..980ff77d83a 100644 --- a/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java +++ b/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package javax.net.ssl; import java.util.List; +import javax.crypto.SecretKey; /** * Extends the {@code SSLSession} interface to support additional @@ -163,4 +164,113 @@ public List getRequestedServerNames() { public List getStatusResponses() { throw new UnsupportedOperationException(); } + + /** + * Generates Exported Keying Material (EKM) calculated according to the + * algorithms defined in RFCs 5705/8446. + *

              + * RFC 5705 (for (D)TLSv1.2 and earlier) calculates different EKM + * values depending on whether {@code context} is null or non-null/empty. + * RFC 8446 (TLSv1.3) treats a null context as non-null/empty. + *

              + * {@code label} will be converted to bytes using + * the {@link java.nio.charset.StandardCharsets#UTF_8} + * character encoding. + * + * @spec https://www.rfc-editor.org/info/rfc5705 + * RFC 5705: Keying Material Exporters for Transport Layer + * Security (TLS) + * @spec https://www.rfc-editor.org/info/rfc8446 + * RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3 + * + * @implSpec The default implementation throws + * {@code UnsupportedOperationException}. + * + * @param keyAlg the algorithm of the resultant {@code SecretKey} object. + * See the SecretKey Algorithms section in the + * + * Java Security Standard Algorithm Names Specification + * for information about standard secret key algorithm + * names. + * @param label the label bytes used in the EKM calculation. + * {@code label} will be converted to a {@code byte[]} + * before the operation begins. + * @param context the context bytes used in the EKM calculation, or null + * @param length the number of bytes of EKM material needed + * + * @throws SSLKeyException if the key cannot be generated + * @throws IllegalArgumentException if {@code keyAlg} is empty, + * {@code length} is non-positive, or if the {@code label} or + * {@code context} length can not be accommodated + * @throws NullPointerException if {@code keyAlg} or {@code label} is null + * @throws IllegalStateException if this session does not have the + * necessary key generation material (for example, a session + * under construction during handshaking) + * @throws UnsupportedOperationException if the underlying provider + * does not implement the operation + * + * @return a {@code SecretKey} that contains {@code length} bytes of the + * EKM material + * + * @since 25 + */ + public SecretKey exportKeyingMaterialKey(String keyAlg, + String label, byte[] context, int length) throws SSLKeyException { + throw new UnsupportedOperationException( + "Underlying provider does not implement the method"); + } + + /** + * Generates Exported Keying Material (EKM) calculated according to the + * algorithms defined in RFCs 5705/8446. + *

              + * RFC 5705 (for (D)TLSv1.2 and earlier) calculates different EKM + * values depending on whether {@code context} is null or non-null/empty. + * RFC 8446 (TLSv1.3) treats a null context as non-null/empty. + *

              + * {@code label} will be converted to bytes using + * the {@link java.nio.charset.StandardCharsets#UTF_8} + * character encoding. + *

              + * Depending on the chosen underlying key derivation mechanism, the + * raw bytes might not be extractable/exportable. In such cases, the + * {@link #exportKeyingMaterialKey(String, String, byte[], int)} method + * should be used instead to access the generated key material. + * + * @spec https://www.rfc-editor.org/info/rfc5705 + * RFC 5705: Keying Material Exporters for Transport Layer + * Security (TLS) + * @spec https://www.rfc-editor.org/info/rfc8446 + * RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3 + * + * @implSpec The default implementation throws + * {@code UnsupportedOperationException}. + * + * @param label the label bytes used in the EKM calculation. + * {@code label} will be converted to a {@code byte[]} + * before the operation begins. + * @param context the context bytes used in the EKM calculation, or null + * @param length the number of bytes of EKM material needed + * + * @throws SSLKeyException if the key cannot be generated + * @throws IllegalArgumentException if {@code length} is non-positive, + * or if the {@code label} or {@code context} length can + * not be accommodated + * @throws NullPointerException if {@code label} is null + * @throws IllegalStateException if this session does not have the + * necessary key generation material (for example, a session + * under construction during handshaking) + * @throws UnsupportedOperationException if the underlying provider + * does not implement the operation, or if the derived + * keying material is not extractable + * + * @return a byte array of size {@code length} that contains the EKM + * material + * @since 25 + */ + public byte[] exportKeyingMaterialData( + String label, byte[] context, int length) throws SSLKeyException { + throw new UnsupportedOperationException( + "Underlying provider does not implement the method"); + } } 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 ceb860e653a..dd1e2333005 100644 --- a/src/java.base/share/classes/javax/security/auth/Subject.java +++ b/src/java.base/share/classes/javax/security/auth/Subject.java @@ -300,7 +300,7 @@ public static Subject getSubject(final AccessControlContext acc) { * @since 18 */ public static Subject current() { - return SCOPED_SUBJECT.orElse(null); + return SCOPED_SUBJECT.isBound() ? SCOPED_SUBJECT.get() : null; } /** diff --git a/src/java.base/share/classes/javax/security/auth/callback/CallbackHandler.java b/src/java.base/share/classes/javax/security/auth/callback/CallbackHandler.java index 03e1b14a5ff..5fff3177e4f 100644 --- a/src/java.base/share/classes/javax/security/auth/callback/CallbackHandler.java +++ b/src/java.base/share/classes/javax/security/auth/callback/CallbackHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,7 +113,9 @@ public interface CallbackHandler { * System.err.print(nc.getPrompt()); * System.err.flush(); * nc.setName((new BufferedReader - * (new InputStreamReader(System.in))).readLine()); + * (new InputStreamReader( + * System.in, + * System.getProperty("stdin.encoding")))).readLine()); * * } else if (callbacks[i] instanceof PasswordCallback) { * diff --git a/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_en_GB.java b/src/java.base/share/classes/jdk/internal/RequiresIdentity.java similarity index 50% rename from src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_en_GB.java rename to src/java.base/share/classes/jdk/internal/RequiresIdentity.java index 43922dcb032..5b54debd095 100644 --- a/src/jdk.localedata/share/classes/sun/util/resources/ext/TimeZoneNames_en_GB.java +++ b/src/java.base/share/classes/jdk/internal/RequiresIdentity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,32 +23,29 @@ * questions. */ -/* - * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved - * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved - * - * The original version of this source code and documentation - * is copyrighted and owned by Taligent, Inc., a wholly-owned - * subsidiary of IBM. These materials are provided under terms - * of a License Agreement between Taligent and Sun. This technology - * is protected by multiple US and International patents. - * - * This notice and attribution to Taligent may not be removed. - * Taligent is a registered trademark of Taligent, Inc. - * - */ +package jdk.internal; -package sun.util.resources.ext; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; -import sun.util.resources.TimeZoneNamesBundle; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE_PARAMETER; -public final class TimeZoneNames_en_GB extends TimeZoneNamesBundle { - - protected final Object[][] getContents() { - return new Object[][] { - {"Europe/London", new String[] {"Greenwich Mean Time", "GMT", - "British Summer Time", "BST", - "British Time", "BT"}}, - }; - } +/** + * Indicates that the annotated parameter or type parameter is not expected to be a + * Value Based class. + * Using a parameter or type parameter of a value-based classes + * should produce warnings about behavior that is inconsistent with identity based semantics. + * + * Note this internal annotation is handled specially by the javac compiler. + * To work properly with {@code --release older-release}, it requires special + * handling in {@code make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java} + * and {@code src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java}. + * + * @since 25 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value={PARAMETER, TYPE_PARAMETER}) +public @interface RequiresIdentity { } diff --git a/src/java.base/share/classes/jdk/internal/ValueBased.java b/src/java.base/share/classes/jdk/internal/ValueBased.java index d27ab73c01f..160ffce874a 100644 --- a/src/java.base/share/classes/jdk/internal/ValueBased.java +++ b/src/java.base/share/classes/jdk/internal/ValueBased.java @@ -46,4 +46,3 @@ @Target(value={TYPE}) public @interface ValueBased { } - diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index 8edeb731cee..e8343274cac 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -119,6 +119,12 @@ public interface JavaLangAccess { */ > E[] getEnumConstantsShared(Class klass); + /** + * Returns the big-endian packed minor-major version of the class file + * of this class. + */ + int classFileVersion(Class clazz); + /** * Set current thread's blocker field. */ @@ -230,11 +236,6 @@ public interface JavaLangAccess { */ void addOpensToAllUnnamed(Module m, String pkg); - /** - * Updates module m to open all packages in the given sets. - */ - void addOpensToAllUnnamed(Module m, Set concealedPkgs, Set exportedPkgs); - /** * Updates module m to use a service. */ @@ -301,6 +302,8 @@ public interface JavaLangAccess { /** * Count the number of leading positive bytes in the range. + * + * @implSpec Implementations of this method must perform bounds checks. */ int countPositives(byte[] ba, int off, int len); @@ -310,37 +313,40 @@ public interface JavaLangAccess { int countNonZeroAscii(String s); /** - * Constructs a new {@code String} by decoding the specified subarray of - * bytes using the specified {@linkplain java.nio.charset.Charset charset}. - * - * The caller of this method shall relinquish and transfer the ownership of - * the byte array to the callee since the later will not make a copy. + * Constructs a new {@code String} by decoding the specified byte array + * using the specified {@linkplain java.nio.charset.Charset charset}. + *

              + * WARNING: The caller of this method shall relinquish and transfer the + * ownership of the byte array to the callee, since the latter will not + * make a copy. * * @param bytes the byte array source * @param cs the Charset * @return the newly created string * @throws CharacterCodingException for malformed or unmappable bytes */ - String newStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException; + String uncheckedNewStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException; /** - * Encode the given string into a sequence of bytes using the specified Charset. - * - * This method avoids copying the String's internal representation if the input - * is ASCII. - * - * This method throws CharacterCodingException instead of replacing when - * malformed input or unmappable characters are encountered. + * Encode the given string into a sequence of bytes using the specified + * {@linkplain java.nio.charset.Charset charset}. + *

              + * WARNING: This method returns the {@code byte[]} backing the provided + * {@code String}, if the input is ASCII. Hence, the returned byte array + * must not be modified. + *

              + * This method throws {@code CharacterCodingException} instead of replacing + * when malformed input or unmappable characters are encountered. * * @param s the string to encode * @param cs the charset * @return the encoded bytes * @throws CharacterCodingException for malformed input or unmappable characters */ - byte[] getBytesNoRepl(String s, Charset cs) throws CharacterCodingException; + byte[] uncheckedGetBytesNoRepl(String s, Charset cs) throws CharacterCodingException; /** - * Returns a new string by decoding from the given utf8 bytes array. + * Returns a new string by decoding from the given UTF-8 bytes array. * * @param off the index of the first byte to decode * @param len the number of bytes to decode @@ -350,23 +356,27 @@ public interface JavaLangAccess { String newStringUTF8NoRepl(byte[] bytes, int off, int len); /** - * Get the char at index in a byte[] in internal UTF-16 representation, - * with no bounds checks. + * Get the {@code char} at {@code index} in a {@code byte[]} in internal + * UTF-16 representation. + *

              + * WARNING: This method does not perform any bound checks. * * @param bytes the UTF-16 encoded bytes * @param index of the char to retrieve, 0 <= index < (bytes.length >> 1) * @return the char value */ - char getUTF16Char(byte[] bytes, int index); + char uncheckedGetUTF16Char(byte[] bytes, int index); /** - * Put the char at index in a byte[] in internal UTF-16 representation, - * with no bounds checks. + * Put the {@code ch} at {@code index} in a {@code byte[]} in internal + * UTF-16 representation. + *

              + * WARNING: This method does not perform any bound checks. * * @param bytes the UTF-16 encoded bytes * @param index of the char to retrieve, 0 <= index < (bytes.length >> 1) */ - void putCharUTF16(byte[] bytes, int index, int ch); + void uncheckedPutCharUTF16(byte[] bytes, int index, int ch); /** * Encode the given string into a sequence of bytes using utf8. @@ -378,7 +388,10 @@ public interface JavaLangAccess { byte[] getBytesUTF8NoRepl(String s); /** - * Inflated copy from byte[] to char[], as defined by StringLatin1.inflate + * Inflated copy from {@code byte[]} to {@code char[]}, as defined by + * {@code StringLatin1.inflate}. + * + * @implSpec Implementations of this method must perform bounds checks. */ void inflateBytesToChars(byte[] src, int srcOff, char[] dst, int dstOff, int len); @@ -386,6 +399,8 @@ public interface JavaLangAccess { * Decodes ASCII from the source byte array into the destination * char array. * + * @implSpec Implementations of this method must perform bounds checks. + * * @return the number of bytes successfully decoded, at most len */ int decodeASCII(byte[] src, int srcOff, char[] dst, int dstOff, int len); @@ -402,13 +417,15 @@ public interface JavaLangAccess { PrintStream initialSystemErr(); /** - * Encodes ASCII codepoints as possible from the source array into + * Encodes as many ASCII codepoints as possible from the source array into * the destination byte array, assuming that the encoding is ASCII - * compatible + * compatible. + *

              + * WARNING: This method does not perform any bound checks. * * @return the number of bytes successfully encoded, or 0 if none */ - int encodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len); + int uncheckedEncodeASCII(char[] src, int srcOff, byte[] dst, int dstOff, int len); /** * Set the cause of Throwable @@ -441,7 +458,14 @@ public interface JavaLangAccess { */ long stringConcatMix(long lengthCoder, char value); - Object stringConcat1(String[] constants); + /** + * Creates helper for string concatenation. + *

              + * WARNING: The caller of this method shall relinquish and transfer the + * ownership of the string array to the callee, since the latter will not + * make a copy. + */ + Object uncheckedStringConcat1(String[] constants); /** * Get the string initial coder, When COMPACT_STRINGS is on, it returns 0, and when it is off, it returns 1. @@ -522,12 +546,6 @@ public interface JavaLangAccess { */ void removeCarrierThreadLocal(CarrierThreadLocal local); - /** - * Returns {@code true} if there is a value in the current carrier thread's copy of - * thread-local, even if that values is {@code null}. - */ - boolean isCarrierThreadLocalPresent(CarrierThreadLocal local); - /** * Returns the current thread's scoped values cache */ diff --git a/src/java.base/share/classes/jdk/internal/access/JavaUtilCollectionAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaUtilCollectionAccess.java index f88d57521ac..cac8785b158 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaUtilCollectionAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaUtilCollectionAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,14 @@ package jdk.internal.access; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.IntFunction; public interface JavaUtilCollectionAccess { List listFromTrustedArray(Object[] array); List listFromTrustedArrayNullsAllowed(Object[] array); + List stableList(int size, IntFunction mapper); + Map stableMap(Set keys, Function mapper); } diff --git a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java index 3ec9d6d4bae..bc955a76abb 100644 --- a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java +++ b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java @@ -69,7 +69,6 @@ public class SharedSecrets { private static JavaLangReflectAccess javaLangReflectAccess; private static JavaIOAccess javaIOAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; - private static JavaIOFilePermissionAccess javaIOFilePermissionAccess; private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess; private static JavaObjectInputStreamReadString javaObjectInputStreamReadString; private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; @@ -287,20 +286,6 @@ public static void setJavaIOFileDescriptorAccess(JavaIOFileDescriptorAccess jiof javaIOFileDescriptorAccess = jiofda; } - @SuppressWarnings("removal") - public static JavaIOFilePermissionAccess getJavaIOFilePermissionAccess() { - var access = javaIOFilePermissionAccess; - if (access == null) { - ensureClassInitialized(FilePermission.class); - access = javaIOFilePermissionAccess; - } - return access; - } - - public static void setJavaIOFilePermissionAccess(JavaIOFilePermissionAccess jiofpa) { - javaIOFilePermissionAccess = jiofpa; - } - public static JavaIOFileDescriptorAccess getJavaIOFileDescriptorAccess() { var access = javaIOFileDescriptorAccess; if (access == null) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index 3e50773d59e..962a2057585 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,8 @@ import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.constant.ClassOrInterfaceDescImpl; +import jdk.internal.constant.PrimitiveClassDescImpl; import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.Stable; @@ -73,11 +75,6 @@ static int hashClassFromDescriptor(int descriptorHash) { return hash1(PoolEntry.TAG_CLASS, descriptorHash); } - static boolean isArrayDescriptor(Utf8EntryImpl cs) { - // Do not throw out-of-bounds for empty strings - return !cs.isEmpty() && cs.charAt(0) == '['; - } - @SuppressWarnings("unchecked") public static T maybeClone(ConstantPoolBuilder cp, T entry) { if (cp.canWriteDirect(entry.constantPool())) @@ -298,9 +295,13 @@ private ConstantPoolException malformedInput(int px) { @Override public Utf8EntryImpl clone(ConstantPoolBuilder cp) { - return (state == State.STRING && rawBytes == null) + var ret = (state == State.STRING && rawBytes == null) ? (Utf8EntryImpl) cp.utf8Entry(stringValue) : ((SplitConstantPool) cp).maybeCloneUtf8Entry(this); + var mySym = this.typeSym; + if (ret.typeSym == null && mySym != null) + ret.typeSym = mySym; + return ret; } @Override @@ -438,6 +439,79 @@ public MethodTypeDesc methodTypeSymbol() { typeSym = ret; return ret; } + + @Override + public boolean isFieldType(ClassDesc desc) { + var sym = typeSym; + if (sym != null) { + return sym instanceof ClassDesc cd && cd.equals(desc); + } + + // In parsing, Utf8Entry is not even inflated by this point + // We can operate on the raw byte arrays, as all ascii are compatible + var ret = state == State.RAW + ? rawEqualsSym(desc) + : equalsString(desc.descriptorString()); + if (ret) + this.typeSym = desc; + return ret; + } + + private boolean rawEqualsSym(ClassDesc desc) { + int len = rawLen; + if (len < 1) { + return false; + } + int c = rawBytes[offset]; + if (len == 1) { + return desc instanceof PrimitiveClassDescImpl pd && pd.wrapper().basicTypeChar() == c; + } else if (c == 'L') { + return desc.isClassOrInterface() && equalsString(desc.descriptorString()); + } else if (c == '[') { + return desc.isArray() && equalsString(desc.descriptorString()); + } else { + return false; + } + } + + boolean mayBeArrayDescriptor() { + if (state == State.RAW) { + return rawLen > 0 && rawBytes[offset] == '['; + } else { + return charLen > 0 && charAt(0) == '['; + } + } + + @Override + public boolean isMethodType(MethodTypeDesc desc) { + var sym = typeSym; + if (sym != null) { + return sym instanceof MethodTypeDesc mtd && mtd.equals(desc); + } + + // In parsing, Utf8Entry is not even inflated by this point + // We can operate on the raw byte arrays, as all ascii are compatible + var ret = state == State.RAW + ? rawEqualsSym(desc) + : equalsString(desc.descriptorString()); + if (ret) + this.typeSym = desc; + return ret; + } + + private boolean rawEqualsSym(MethodTypeDesc desc) { + if (rawLen < 3) { + return false; + } + var bytes = rawBytes; + int index = offset; + int c = bytes[index] | (bytes[index + 1] << Byte.SIZE); + if ((desc.parameterCount() == 0) != (c == ('(' | (')' << Byte.SIZE)))) { + // heuristic - avoid inflation for no-arg status mismatch + return false; + } + return (c & 0xFF) == '(' && equalsString(desc.descriptorString()); + } } abstract static sealed class AbstractRefEntry extends AbstractPoolEntry { @@ -538,7 +612,7 @@ public ClassDesc asSymbol() { return sym; } - if (isArrayDescriptor(ref1)) { + if (ref1.mayBeArrayDescriptor()) { sym = ref1.fieldTypeSymbol(); // array, symbol already available } else { sym = ClassDesc.ofInternalName(asInternalName()); // class or interface @@ -546,6 +620,28 @@ public ClassDesc asSymbol() { return this.sym = sym; } + @Override + public boolean matches(ClassDesc desc) { + var sym = this.sym; + if (sym != null) { + return sym.equals(desc); + } + + var ret = rawEqualsSymbol(desc); + if (ret) + this.sym = desc; + return ret; + } + + private boolean rawEqualsSymbol(ClassDesc desc) { + if (ref1.mayBeArrayDescriptor()) { + return desc.isArray() && ref1.isFieldType(desc); + } else { + return desc instanceof ClassOrInterfaceDescImpl coid + && ref1.equalsString(coid.internalName()); + } + } + @Override public boolean equals(Object o) { if (o == this) return true; @@ -571,7 +667,7 @@ public int hashCode() { if (hash != 0) return hash; - return this.hash = hashClassFromUtf8(isArrayDescriptor(ref1), ref1); + return this.hash = hashClassFromUtf8(ref1.mayBeArrayDescriptor(), ref1); } } @@ -596,6 +692,11 @@ public PackageDesc asSymbol() { return PackageDesc.ofInternalName(asInternalName()); } + @Override + public boolean matches(PackageDesc desc) { + return ref1.equalsString(desc.internalName()); + } + @Override public boolean equals(Object o) { if (o == this) return true; @@ -627,6 +728,11 @@ public ModuleDesc asSymbol() { return ModuleDesc.of(asInternalName()); } + @Override + public boolean matches(ModuleDesc desc) { + return ref1.equalsString(desc.name()); + } + @Override public boolean equals(Object o) { if (o == this) return true; @@ -837,6 +943,8 @@ public static final class InvokeDynamicEntryImpl extends AbstractDynamicConstantPoolEntry implements InvokeDynamicEntry { + public @Stable DynamicCallSiteDesc sym; + InvokeDynamicEntryImpl(ConstantPool cpm, int index, int hash, BootstrapMethodEntryImpl bootstrapMethod, NameAndTypeEntryImpl nameAndType) { super(cpm, index, hash, bootstrapMethod, nameAndType); @@ -855,13 +963,27 @@ public int tag() { @Override public InvokeDynamicEntry clone(ConstantPoolBuilder cp) { - return cp.invokeDynamicEntry(bootstrap(), nameAndType()); + var ret = (InvokeDynamicEntryImpl) cp.invokeDynamicEntry(bootstrap(), nameAndType()); + var mySym = this.sym; + if (ret.sym == null && mySym != null) + ret.sym = mySym; + return ret; + } + + @Override + public DynamicCallSiteDesc asSymbol() { + var cache = this.sym; + if (cache != null) + return cache; + return this.sym = InvokeDynamicEntry.super.asSymbol(); } } public static final class ConstantDynamicEntryImpl extends AbstractDynamicConstantPoolEntry implements ConstantDynamicEntry { + public @Stable DynamicConstantDesc sym; + ConstantDynamicEntryImpl(ConstantPool cpm, int index, int hash, BootstrapMethodEntryImpl bootstrapMethod, NameAndTypeEntryImpl nameAndType) { super(cpm, index, hash, bootstrapMethod, nameAndType); @@ -880,7 +1002,19 @@ public int tag() { @Override public ConstantDynamicEntry clone(ConstantPoolBuilder cp) { - return cp.constantDynamicEntry(bootstrap(), nameAndType()); + var ret = (ConstantDynamicEntryImpl) cp.constantDynamicEntry(bootstrap(), nameAndType()); + var mySym = this.sym; + if (ret.sym == null && mySym != null) + ret.sym = mySym; + return ret; + } + + @Override + public DynamicConstantDesc asSymbol() { + var cache = this.sym; + if (cache != null) + return cache; + return this.sym = ConstantDynamicEntry.super.asSymbol(); } } @@ -889,6 +1023,7 @@ public static final class MethodHandleEntryImpl extends AbstractPoolEntry private final int refKind; private final AbstractPoolEntry.AbstractMemberRefEntry reference; + public @Stable DirectMethodHandleDesc sym; MethodHandleEntryImpl(ConstantPool cpm, int index, int hash, int refKind, AbstractPoolEntry.AbstractMemberRefEntry reference) { @@ -921,7 +1056,14 @@ public AbstractPoolEntry.AbstractMemberRefEntry reference() { @Override public DirectMethodHandleDesc asSymbol() { - return MethodHandleDesc.of( + var cache = this.sym; + if (cache != null) + return cache; + return computeSymbol(); + } + + private DirectMethodHandleDesc computeSymbol() { + return this.sym = MethodHandleDesc.of( DirectMethodHandleDesc.Kind.valueOf(kind(), reference() instanceof InterfaceMethodRefEntry), ((MemberRefEntry) reference()).owner().asSymbol(), ((MemberRefEntry) reference()).nameAndType().name().stringValue(), @@ -935,7 +1077,11 @@ void writeTo(BufWriterImpl pool) { @Override public MethodHandleEntry clone(ConstantPoolBuilder cp) { - return cp.methodHandleEntry(refKind, reference); + var ret = (MethodHandleEntryImpl) cp.methodHandleEntry(refKind, reference); + var mySym = this.sym; + if (ret.sym == null && mySym != null) + ret.sym = mySym; + return ret; } @Override @@ -983,6 +1129,11 @@ public MethodTypeDesc asSymbol() { return ref1.methodTypeSymbol(); } + @Override + public boolean matches(MethodTypeDesc desc) { + return ref1.isMethodType(desc); + } + @Override public boolean equals(Object o) { if (o == this) return true; @@ -1016,6 +1167,11 @@ public String stringValue() { return ref1.toString(); } + @Override + public boolean equalsString(String value) { + return ref1.equalsString(value); + } + @Override public ConstantDesc constantValue() { return stringValue(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java index 62d812ce8d4..56682214566 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BlockCodeBuilderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,11 +72,10 @@ public boolean isEmpty() { } private int topLocal(CodeBuilder parent) { - return switch (parent) { - case BlockCodeBuilderImpl b -> b.topLocal; - case ChainedCodeBuilder b -> b.terminal.curTopLocal(); - case TerminalCodeBuilder b -> b.curTopLocal(); - }; + if (parent instanceof BlockCodeBuilderImpl bcb) { + return bcb.topLocal; + } + return findTerminal(parent).curTopLocal(); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index 25daf4e4648..a51728eb3e9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,12 +29,10 @@ import java.lang.classfile.Opcode; import java.lang.classfile.TypeKind; import java.lang.classfile.constantpool.*; -import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; import java.lang.constant.ConstantDescs; import java.lang.constant.DirectMethodHandleDesc; import java.lang.constant.DynamicConstantDesc; -import java.lang.constant.MethodTypeDesc; import java.lang.invoke.MethodHandleInfo; import java.util.ArrayList; import java.util.List; @@ -515,38 +513,6 @@ public static Opcode ldcOpcode(LoadableConstantEntry entry) { : Opcode.LDC; } - public static LoadableConstantEntry constantEntry(ConstantPoolBuilder constantPool, - ConstantDesc constantValue) { - // this method is invoked during JVM bootstrap - cannot use pattern switch - if (constantValue instanceof Integer value) { - return constantPool.intEntry(value); - } - if (constantValue instanceof String value) { - return constantPool.stringEntry(value); - } - if (constantValue instanceof ClassDesc value && !value.isPrimitive()) { - return constantPool.classEntry(value); - } - if (constantValue instanceof Long value) { - return constantPool.longEntry(value); - } - if (constantValue instanceof Float value) { - return constantPool.floatEntry(value); - } - if (constantValue instanceof Double value) { - return constantPool.doubleEntry(value); - } - if (constantValue instanceof MethodTypeDesc value) { - return constantPool.methodTypeEntry(value); - } - if (constantValue instanceof DirectMethodHandleDesc value) { - return handleDescToHandleInfo(constantPool, value); - } if (constantValue instanceof DynamicConstantDesc value) { - return handleConstantDescToHandleInfo(constantPool, value); - } - throw new UnsupportedOperationException("not yet: " + requireNonNull(constantValue)); - } - public static ConstantDesc intrinsicConstantValue(Opcode opcode) { return switch (opcode) { case ACONST_NULL -> ConstantDescs.NULL; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java index 48d5ceb72d6..b4c8ad58705 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,10 +39,8 @@ public final class ChainedClassBuilder public ChainedClassBuilder(ClassBuilder downstream, Consumer consumer) { this.consumer = consumer; - this.terminal = switch (downstream) { - case ChainedClassBuilder cb -> cb.terminal; - case DirectClassBuilder db -> db; - }; + this.terminal = downstream instanceof ChainedClassBuilder ccb ? + ccb.terminal : (DirectClassBuilder) downstream; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java index 13ca52f18de..9eac25d567c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedFieldBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,10 +38,8 @@ public final class ChainedFieldBuilder implements FieldBuilder { public ChainedFieldBuilder(FieldBuilder downstream, Consumer consumer) { this.consumer = consumer; - this.terminal = switch (downstream) { - case ChainedFieldBuilder cb -> cb.terminal; - case TerminalFieldBuilder tb -> tb; - }; + this.terminal = downstream instanceof ChainedFieldBuilder cfb ? + cfb.terminal : (TerminalFieldBuilder) downstream; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java index 7bd0fc2ca1b..e96351b8856 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ChainedMethodBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,10 +41,8 @@ public final class ChainedMethodBuilder implements MethodBuilder { public ChainedMethodBuilder(MethodBuilder downstream, Consumer consumer) { this.consumer = consumer; - this.terminal = switch (downstream) { - case ChainedMethodBuilder cb -> cb.terminal; - case TerminalMethodBuilder tb -> tb; - }; + this.terminal = downstream instanceof ChainedMethodBuilder cmb ? + cmb.terminal : (TerminalMethodBuilder) downstream; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index 286d29029ad..c8c6d254650 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -264,14 +264,16 @@ private void inflateJumpTargets() { //fallback to jump targets inflation without StackMapTableAttribute for (int pos=codeStart; pos br.target(); - case DiscontinuedInstruction.JsrInstruction jsr -> jsr.target(); - case LookupSwitchInstruction ls -> { + switch (i.opcode().kind()) { + case BRANCH -> ((BranchInstruction) i).target(); + case DISCONTINUED_JSR -> ((DiscontinuedInstruction.JsrInstruction) i).target(); + case LOOKUP_SWITCH -> { + var ls = (LookupSwitchInstruction) i; ls.defaultTarget(); ls.cases(); } - case TableSwitchInstruction ts -> { + case TABLE_SWITCH -> { + var ts = (TableSwitchInstruction) i; ts.defaultTarget(); ts.cases(); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 6dc62511639..1e12969f204 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -42,7 +42,7 @@ public final class DirectClassBuilder implements ClassBuilder { /** The value of default class access flags */ - static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC; + static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC | ClassFile.ACC_SUPER; static final Util.Writable[] EMPTY_WRITABLE_ARRAY = {}; static final ClassEntry[] EMPTY_CLASS_ENTRY_ARRAY = {}; final ClassEntry thisClassEntry; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 2741d1918ca..bc563482f79 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -48,10 +48,8 @@ public final class DirectCodeBuilder extends AbstractDirectBuilder implements TerminalCodeBuilder { private static final CharacterRange[] EMPTY_CHARACTER_RANGE = {}; - private static final DeferredLabel[] EMPTY_LABEL_ARRAY = {}; private static final LocalVariable[] EMPTY_LOCAL_VARIABLE_ARRAY = {}; private static final LocalVariableType[] EMPTY_LOCAL_VARIABLE_TYPE_ARRAY = {}; - private static final AbstractPseudoInstruction.ExceptionCatchImpl[] EMPTY_HANDLER_ARRAY = {}; private static final DeferredLabel[] EMPTY_DEFERRED_LABEL_ARRAY = {}; final List handlers = new ArrayList<>(); @@ -74,6 +72,9 @@ public final class DirectCodeBuilder private DeferredLabel[] deferredLabels = EMPTY_DEFERRED_LABEL_ARRAY; private int deferredLabelsCount = 0; + private int maxStackHint = -1; + private int maxLocalsHint = -1; + /* Locals management lazily computed maxLocal = -1 first time: derive count from methodType descriptor (for new methods) & ACC_STATIC, @@ -173,6 +174,12 @@ public MethodInfo methodInfo() { return methodInfo; } + public static void withMaxs(CodeBuilder cob, int stacks, int locals) { + var dcb = (DirectCodeBuilder) cob; + dcb.maxStackHint = stacks; + dcb.maxLocalsHint = locals; + } + private UnboundAttribute content = null; private void writeExceptionHandlers(BufWriterImpl buf) { @@ -319,6 +326,8 @@ private void writeCounters(boolean codeMatch, BufWriterImpl buf) { if (codeMatch) { var originalAttribute = (CodeImpl) original; buf.writeU2U2(originalAttribute.maxStack(), originalAttribute.maxLocals()); + } else if (maxLocalsHint >= 0 && maxStackHint >= 0) { + buf.writeU2U2(maxStackHint, maxLocalsHint); } else { StackCounter cntr = StackCounter.of(DirectCodeBuilder.this, buf); buf.writeU2U2(cntr.maxStack(), cntr.maxLocals()); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/NonterminalCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/NonterminalCodeBuilder.java index f40da3a2bea..d7eaffb3250 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/NonterminalCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/NonterminalCodeBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,10 +35,12 @@ public abstract sealed class NonterminalCodeBuilder implements CodeBuilder public NonterminalCodeBuilder(CodeBuilder parent) { this.parent = parent; - this.terminal = switch (parent) { - case NonterminalCodeBuilder cb -> cb.terminal; - case TerminalCodeBuilder cb -> cb; - }; + this.terminal = findTerminal(parent); + } + + static TerminalCodeBuilder findTerminal(CodeBuilder cob) { + return cob instanceof NonterminalCodeBuilder ncb ? + ncb.terminal : (TerminalCodeBuilder) cob; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index 5ba81fc2927..5a5f2908ae6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.lang.classfile.attribute.BootstrapMethodsAttribute; import java.lang.classfile.constantpool.*; import java.lang.constant.ClassDesc; +import java.lang.constant.DynamicCallSiteDesc; import java.lang.constant.MethodTypeDesc; import java.util.Arrays; import java.util.List; @@ -497,7 +498,7 @@ AbstractPoolEntry.Utf8EntryImpl maybeCloneUtf8Entry(Utf8Entry entry) { @Override public AbstractPoolEntry.ClassEntryImpl classEntry(Utf8Entry nameEntry) { var ne = maybeCloneUtf8Entry(nameEntry); - return classEntry(ne, AbstractPoolEntry.isArrayDescriptor(ne)); + return classEntry(ne, ne.mayBeArrayDescriptor()); } AbstractPoolEntry.ClassEntryImpl classEntry(AbstractPoolEntry.Utf8EntryImpl ne, boolean isArray) { @@ -521,6 +522,10 @@ public ClassEntry classEntry(ClassDesc cd) { AbstractPoolEntry.ClassEntryImpl cloneClassEntry(AbstractPoolEntry.ClassEntryImpl e) { var ce = tryFindClassEntry(e.hashCode(), e.ref1); if (ce != null) { + var mySym = e.sym; + if (ce.sym == null && mySym != null) { + ce.sym = mySym; + } return ce; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 7e16aea5a52..eb17e99a94d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -716,7 +716,7 @@ private void processLdc(int index) { case TAG_METHOD_TYPE -> currentFrame.pushStack(Type.METHOD_TYPE); case TAG_DYNAMIC -> - currentFrame.pushStack(cp.entryByIndex(index, ConstantDynamicEntry.class).asSymbol().constantType()); + currentFrame.pushStack(cp.entryByIndex(index, ConstantDynamicEntry.class).typeSymbol()); default -> throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag())); } diff --git a/src/java.base/share/classes/jdk/internal/event/ExceptionThrownEvent.java b/src/java.base/share/classes/jdk/internal/event/ExceptionThrownEvent.java index 45c13e3010d..355ee81c0fc 100644 --- a/src/java.base/share/classes/jdk/internal/event/ExceptionThrownEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/ExceptionThrownEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,11 @@ public final class ExceptionThrownEvent extends Event { public String message; public Class thrownClass; + public static boolean shouldThrottleCommit(long timestamp) { + // Generated by JFR + return false; + } + public static void commit(long start, String message, Class thrownClass) { // Generated by JFR } diff --git a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java index 34ff4e9d4ed..77b2568802e 100644 --- a/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/FileReadEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,11 +45,33 @@ public static long timestamp() { return 0L; } - public static boolean shouldCommit(long duration) { + public static boolean shouldThrottleCommit(long duration, long end) { // Generated by JFR return false; } + /** + * Helper method to offer the data needed to potentially commit an event. + * The duration of the operation is computed using the current + * timestamp and the given start time. If the duration meets + * or exceeds the configured value and is not throttled (determined by calling the + * generated method {@link #shouldThrottleCommit(long, long)}), an event will be + * emitted by calling {@link #commit(long, long, String, long, boolean)} + * + * @param start the start time + * @param path the path + * @param bytesRead the number of bytes that were read, or -1 if the end of the file was reached + */ + public static void offer(long start, String path, long bytesRead) { + long end = timestamp(); + long duration = end - start; + if (shouldThrottleCommit(duration, end)) { + boolean endOfFile = bytesRead < 0; + long bytes = endOfFile ? 0 : bytesRead; + commit(start, duration, path, bytes, endOfFile); + } + } + public static void commit(long start, long duration, String path, long bytesRead, boolean endOfFile) { // Generated by JFR } diff --git a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java index f6c27960430..3fa7dbe9822 100644 --- a/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/FileWriteEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,11 +44,32 @@ public static long timestamp() { return 0L; } - public static boolean shouldCommit(long duration) { + public static boolean shouldThrottleCommit(long duration, long end) { // Generated by JFR return false; } + /** + * Helper method to offer the data needed to potentially commit an event. + * The duration of the operation is computed using the current + * timestamp and the given start time. If the duration meets + * or exceeds the configured value and is not throttled (determined by calling the + * generated method {@link #shouldThrottleCommit(long, long)}), an event will be + * emitted by calling {@link #commit(long, long, String, long)} + * + * @param start the start time + * @param path the path + * @param bytesRead the number of bytes that were written, or -1 if the end of the file was reached + */ + public static void offer(long start, String path, long bytesWritten) { + long end = timestamp(); + long duration = end - start; + if (shouldThrottleCommit(duration, end)) { + long bytes = bytesWritten > 0 ? bytesWritten : 0; + commit(start, duration, path, bytes); + } + } + public static void commit(long start, long duration, String path, long bytesWritten) { // Generated by JFR } diff --git a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java index d5f6c3241d9..09b3f23b07f 100644 --- a/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/SocketReadEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,9 +74,10 @@ public static void commit(long start, long duration, String host, String address * of this method is generated automatically if jfr is enabled. * * @param duration time in nanoseconds to complete the operation + * @param end timestamp at the end of the operation * @return true if the event should be commited */ - public static boolean shouldCommit(long duration) { + public static boolean shouldThrottleCommit(long duration, long end) { // Generated by JFR return false; } @@ -118,8 +119,9 @@ public static long timestamp() { * @param timeout maximum time to wait */ public static void offer(long start, long nbytes, SocketAddress remote, long timeout) { - long duration = timestamp() - start; - if (shouldCommit(duration)) { + long end = timestamp(); + long duration = end - start; + if (shouldThrottleCommit(duration, end)) { emit(start, duration, nbytes, remote, timeout); } } diff --git a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java index 7c56ef826a5..12d8ffbf65b 100644 --- a/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java +++ b/src/java.base/share/classes/jdk/internal/event/SocketWriteEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,10 +68,11 @@ public static void commit(long start, long duration, String host, String address * must exceed some threshold in order to commit the event. The implementation * of this method is generated automatically if jfr is enabled. * - * @param duration time in nanoseconds to complete the operation + * @param duration time to complete the operation + * @param end timestamp at the end of the operation * @return true if the event should be commited */ - public static boolean shouldCommit(long duration) { + public static boolean shouldThrottleCommit(long duration, long end) { // Generated by JFR return false; } @@ -104,7 +105,7 @@ public static long timestamp() { * The duration of the operation is computed using the current * timestamp and the given start time. If the duration is meets * or exceeds the configured value (determined by calling the generated method - * {@link #shouldCommit(long)}), an event will be emitted by calling + * {@link #shouldThrottleCommit(long)}), an event will be emitted by calling * {@link #emit(long, long, long, SocketAddress)}. * * @param start the start time @@ -112,8 +113,9 @@ public static long timestamp() { * @param remote the address of the remote socket being written to */ public static void offer(long start, long bytesWritten, SocketAddress remote) { - long duration = timestamp() - start; - if (shouldCommit(duration)) { + long end = timestamp(); + long duration = end - start; + if (shouldThrottleCommit(duration, end)) { emit(start, duration, bytesWritten, remote); } } diff --git a/src/java.base/share/classes/jdk/internal/event/ThrowableTracer.java b/src/java.base/share/classes/jdk/internal/event/ThrowableTracer.java index f7076b44e90..6502cbc8002 100644 --- a/src/java.base/share/classes/jdk/internal/event/ThrowableTracer.java +++ b/src/java.base/share/classes/jdk/internal/event/ThrowableTracer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,22 +37,24 @@ public static void traceError(Class clazz, String message) { if (OutOfMemoryError.class.isAssignableFrom(clazz)) { return; } - - if (ErrorThrownEvent.enabled()) { + if (ErrorThrownEvent.enabled() || ExceptionThrownEvent.enabled()) { long timestamp = ErrorThrownEvent.timestamp(); - ErrorThrownEvent.commit(timestamp, message, clazz); - } - if (ExceptionThrownEvent.enabled()) { - long timestamp = ExceptionThrownEvent.timestamp(); - ExceptionThrownEvent.commit(timestamp, message, clazz); + if (ErrorThrownEvent.enabled()) { + ErrorThrownEvent.commit(timestamp, message, clazz); + } + if (ExceptionThrownEvent.shouldThrottleCommit(timestamp)) { + ExceptionThrownEvent.commit(timestamp, message, clazz); + } } numThrowables.incrementAndGet(); } public static void traceThrowable(Class clazz, String message) { if (ExceptionThrownEvent.enabled()) { - long timestamp = ExceptionThrownEvent.timestamp(); - ExceptionThrownEvent.commit(timestamp, message, clazz); + long timestamp = ErrorThrownEvent.timestamp(); + if (ExceptionThrownEvent.shouldThrottleCommit(timestamp)) { + ExceptionThrownEvent.commit(timestamp, message, clazz); + } } numThrowables.incrementAndGet(); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java b/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java new file mode 100644 index 00000000000..dbf21601c53 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.foreign; + +import jdk.internal.misc.CarrierThreadLocal; +import jdk.internal.vm.annotation.ForceInline; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.ref.Reference; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; + +/** + * A buffer stack that allows efficient reuse of memory segments. This is useful in cases + * where temporary memory is needed. + *

              + * Use the factories {@code BufferStack.of(...)} to create new instances of this class. + *

              + * Note: The reused segments are neither zeroed out before nor after re-use. + */ +public final class BufferStack { + + private final long byteSize; + private final long byteAlignment; + private final CarrierThreadLocal tl; + + private BufferStack(long byteSize, long byteAlignment) { + this.byteSize = byteSize; + this.byteAlignment = byteAlignment; + this.tl = new CarrierThreadLocal<>() { + @Override + protected BufferStack.PerThread initialValue() { + return BufferStack.PerThread.of(byteSize, byteAlignment); + } + }; + } + + /** + * {@return a new Arena that tries to provide {@code byteSize} and {@code byteAlignment} + * allocations by recycling the BufferStack's internal memory} + * + * @param byteSize to be reserved from this BufferStack's internal memory + * @param byteAlignment to be used for reservation + */ + @ForceInline + public Arena pushFrame(long byteSize, long byteAlignment) { + return tl.get().pushFrame(byteSize, byteAlignment); + } + + /** + * {@return a new Arena that tries to provide {@code byteSize} + * allocations by recycling the BufferStack's internal memory} + * + * @param byteSize to be reserved from this BufferStack's internal memory + */ + @ForceInline + public Arena pushFrame(long byteSize) { + return pushFrame(byteSize, 1); + } + + /** + * {@return a new Arena that tries to provide {@code layout} + * allocations by recycling the BufferStack's internal memory} + * + * @param layout for which to reserve internal memory + */ + @ForceInline + public Arena pushFrame(MemoryLayout layout) { + return pushFrame(layout.byteSize(), layout.byteAlignment()); + } + + @Override + public String toString() { + return "BufferStack[byteSize=" + byteSize + ", byteAlignment=" + byteAlignment + "]"; + } + + private record PerThread(ReentrantLock lock, + Arena arena, + SlicingAllocator stack, + CleanupAction cleanupAction) { + + @ForceInline + public Arena pushFrame(long size, long byteAlignment) { + boolean needsLock = Thread.currentThread().isVirtual() && !lock.isHeldByCurrentThread(); + if (needsLock && !lock.tryLock()) { + // Rare: another virtual thread on the same carrier competed for acquisition. + return Arena.ofConfined(); + } + if (!stack.canAllocate(size, byteAlignment)) { + if (needsLock) lock.unlock(); + return Arena.ofConfined(); + } + return new Frame(needsLock, size, byteAlignment); + } + + static PerThread of(long byteSize, long byteAlignment) { + final Arena arena = Arena.ofAuto(); + return new PerThread(new ReentrantLock(), + arena, + new SlicingAllocator(arena.allocate(byteSize, byteAlignment)), + new CleanupAction(arena)); + } + + private record CleanupAction(Arena arena) implements Consumer { + @Override + public void accept(MemorySegment memorySegment) { + Reference.reachabilityFence(arena); + } + } + + private final class Frame implements Arena { + + private final boolean locked; + private final long parentOffset; + private final long topOfStack; + private final Arena confinedArena; + private final SegmentAllocator frame; + + @SuppressWarnings("restricted") + @ForceInline + public Frame(boolean locked, long byteSize, long byteAlignment) { + this.locked = locked; + this.parentOffset = stack.currentOffset(); + final MemorySegment frameSegment = stack.allocate(byteSize, byteAlignment); + this.topOfStack = stack.currentOffset(); + this.confinedArena = Arena.ofConfined(); + // The cleanup action will keep the original automatic `arena` (from which + // the reusable segment is first allocated) alive even if this Frame + // becomes unreachable but there are reachable segments still alive. + this.frame = new SlicingAllocator(frameSegment.reinterpret(confinedArena, cleanupAction)); + } + + @ForceInline + private void assertOrder() { + if (topOfStack != stack.currentOffset()) + throw new IllegalStateException("Out of order access: frame not top-of-stack"); + } + + @ForceInline + @Override + @SuppressWarnings("restricted") + public MemorySegment allocate(long byteSize, long byteAlignment) { + // Make sure we are on the right thread and not closed + MemorySessionImpl.toMemorySession(confinedArena).checkValidState(); + return frame.allocate(byteSize, byteAlignment); + } + + @ForceInline + @Override + public MemorySegment.Scope scope() { + return confinedArena.scope(); + } + + @ForceInline + @Override + public void close() { + assertOrder(); + // the Arena::close method is called "early" as it checks thread + // confinement and crucially before any mutation of the internal + // state takes place. + confinedArena.close(); + stack.resetTo(parentOffset); + if (locked) { + lock.unlock(); + } + } + } + } + + public static BufferStack of(long byteSize, long byteAlignment) { + if (byteSize < 0) { + throw new IllegalArgumentException("Negative byteSize: " + byteSize); + } + if (byteAlignment < 0) { + throw new IllegalArgumentException("Negative byteAlignment: " + byteAlignment); + } + return new BufferStack(byteSize, byteAlignment); + } + + public static BufferStack of(long byteSize) { + return new BufferStack(byteSize, 1); + } + + public static BufferStack of(MemoryLayout layout) { + // Implicit null check + return of(layout.byteSize(), layout.byteAlignment()); + } +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java b/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java new file mode 100644 index 00000000000..2f3ba7d9e05 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.foreign; + +import jdk.internal.invoke.MhUtil; +import jdk.internal.vm.annotation.ForceInline; + +import java.lang.foreign.Arena; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.StructLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.function.IntFunction; + +/** + * An internal utility class that can be used to adapt system-call-styled method handles + * for efficient and easy use. + */ +public final class CaptureStateUtil { + + private static final StructLayout CAPTURE_LAYOUT = Linker.Option.captureStateLayout(); + private static final BufferStack POOL = BufferStack.of(CAPTURE_LAYOUT); + + // The `BASIC_HANDLE_CACHE` contains the common "basic handles" that can be reused for + // all adapted method handles. Keeping as much as possible reusable reduces the number + // of combinators needed to form an adapted method handle. + // The function is lazily computed. + // + private static final Function SEGMENT_EXTRACTION_HANDLE_CACHE; + + static { + final Set inputs = new HashSet<>(); + // The Cartesian product : (int.class, long.class) x ("errno", ...) + // Do not use Streams in order to enable "early" use in the init sequence. + for (Class c : new Class[]{int.class, long.class}) { + for (MemoryLayout layout : CAPTURE_LAYOUT.memberLayouts()) { + inputs.add(new SegmentExtractorKey(c, layout.name().orElseThrow())); + } + } + + // Do not use a lambda in order to allow early use in the init sequence + final Function segmentExtractionHandle = new Function<>() { + @Override + public MethodHandle apply(SegmentExtractorKey basicKey) { + return makeSegmentExtractionHandle(basicKey); + } + }; + + SEGMENT_EXTRACTION_HANDLE_CACHE = StableValue.function(inputs, segmentExtractionHandle); + } + + // A key that holds both the `returnType` and the `stateName` needed to look up a + // specific "basic handle" in the `BASIC_HANDLE_CACHE`. + // returnType in {int.class | long.class} + // stateName can be anything non-null but should be in {"GetLastError" | "WSAGetLastError" | "errno"} + private record SegmentExtractorKey(Class returnType, String stateName) { + + SegmentExtractorKey(MethodHandle target, String stateName) { + this(returnType(target), Objects.requireNonNull(stateName)); + } + + static Class returnType(MethodHandle target) { + // Implicit null check + final MethodType type = target.type(); + final Class returnType = type.returnType(); + + if (!(returnType.equals(int.class) || returnType.equals(long.class))) { + throw illegalArgDoesNot(target, "return an int or a long"); + } + if (type.parameterCount() == 0 || type.parameterType(0) != MemorySegment.class) { + throw illegalArgDoesNot(target, "have a MemorySegment as the first parameter"); + } + return returnType; + } + + private static IllegalArgumentException illegalArgDoesNot(MethodHandle target, String info) { + return new IllegalArgumentException("The provided target " + target + + " does not " + info); + } + + } + + private CaptureStateUtil() {} + + /** + * {@return a new MethodHandle that adapts the provided {@code target} so that it + * directly returns the same value as the {@code target} if it is non-negative, + * otherwise returns the negated captured state defined by the provided + * {@code stateName}} + *

              + * This method is suitable for adapting system-call method handles(e.g. + * {@code open()}, {@code read()}, and {@code close()}). Clients can check the return + * value as shown in this example: + * {@snippet lang = java: + * // (MemorySegment capture, MemorySegment pathname, int flags)int + * static final MethodHandle CAPTURING_OPEN = ... + * + * // (MemorySegment pathname, int flags)int + * static final MethodHandle OPEN = CaptureStateUtil + * .adaptSystemCall(CAPTURING_OPEN, "errno"); + * + * try { + * int fh = (int)OPEN.invokeExact(pathName, flags); + * if (fh < 0) { + * throw new IOException("Error opening file: errno = " + (-fh)); + * } + * processFile(fh); + * } catch (Throwable t) { + * throw new RuntimeException(t); + * } + * + *} + * + * For a {@code target} method handle that takes a {@code MemorySegment} and two + * {@code int} parameters and returns an {@code int} value, the method returns a new + * method handle that is doing the equivalent of: + *

              + * {@snippet lang = java: + * private static final MemoryLayout CAPTURE_LAYOUT = + * Linker.Option.captureStateLayout(); + * private static final BufferStack POOL = + * BufferStack.of(CAPTURE_LAYOUT); + * + * public int invoke(MethodHandle target, + * String stateName, + * int a, int b) { + * try (var arena = POOL.pushFrame(CAPTURE_LAYOUT)) { + * final MemorySegment segment = arena.allocate(CAPTURE_LAYOUT); + * final int result = (int) handle.invoke(segment, a, b); + * if (result >= 0) { + * return result; + * } + * return -(int) CAPTURE_LAYOUT + * .varHandle(MemoryLayout.PathElement.groupElement(stateName)) + * .get(segment, 0); + * } + * } + *} + * except it is more performant. In the above {@code stateName} is the name of the + * captured state (e.g. {@code errno}). The static {@code CAPTURE_LAYOUT} is shared + * across all target method handles adapted by this method. + * + * @param target method handle that returns an {@code int} or a {@code long} and + * has a capturing state MemorySegment as its first parameter + * @param stateName the name of the capturing state member layout (i.e. "errno", + * "GetLastError", or "WSAGetLastError") + * @throws IllegalArgumentException if the provided {@code target}'s return type is + * not {@code int} or {@code long} + * @throws IllegalArgumentException if the provided {@code target}'s first parameter + * type is not {@linkplain MemorySegment} + * @throws IllegalArgumentException if the provided {@code stateName} is unknown on + * the current platform + */ + public static MethodHandle adaptSystemCall(MethodHandle target, + String stateName) { + // Invariants checked in the BasicKey record + final SegmentExtractorKey key = new SegmentExtractorKey(target, stateName); + + // ((int | long), MemorySegment)(int | long) + final MethodHandle segmentExtractor = SEGMENT_EXTRACTION_HANDLE_CACHE.apply(key); + + // Make `target` specific adaptations of the basic handle + + // Pre-pend all the parameters from the `target` MH. + // (C0=MemorySegment, C1-Cn, MemorySegment)(int|long) + MethodHandle innerAdapted = MethodHandles.collectArguments(segmentExtractor, 0, target); + + final int[] perm = new int[target.type().parameterCount() + 1]; + for (int i = 0; i < target.type().parameterCount(); i++) { + perm[i] = i; + } + // Last takes first + perm[perm.length - 1] = 0; + // Deduplicate the first and last coordinate and only use the first one. + // (C0=MemorySegment, C1-Cn)(int|long) + innerAdapted = MethodHandles.permuteArguments(innerAdapted, target.type(), perm); + + // Use an `Arena` for the first argument instead and extract a segment from it. + // (C0=Arena, C1-Cn)(int|long) + innerAdapted = MethodHandles.collectArguments(innerAdapted, 0, HANDLES_CACHE.apply(ALLOCATE)); + + // Add an identity function for the result of the cleanup action. + // ((int|long))(int|long) + MethodHandle cleanup = MethodHandles.identity(key.returnType()); + // Add a dummy `Throwable` argument for the cleanup action. + // This means, anything thrown will just be propagated. + // (Throwable, (int|long))(int|long) + cleanup = MethodHandles.dropArguments(cleanup, 0, Throwable.class); + // Add the first `Arena` parameter of the `innerAdapted` method handle to the + // cleanup action and invoke `Arena::close` when it is run. The `cleanup` handle + // does not have to have all parameters. It can have zero or more. + // (Throwable, (int|long), Arena)(int|long) + cleanup = MethodHandles.collectArguments(cleanup, 2, HANDLES_CACHE.apply(ARENA_CLOSE)); + + // Combine the `innerAdapted` and `cleanup` action into a try/finally block. + // (Arena, C1-Cn)(int|long) + final MethodHandle tryFinally = MethodHandles.tryFinally(innerAdapted, cleanup); + + // Acquire the arena from the global pool. + // With this, we finally arrive at the intended method handle: + // (C1-Cn)(int|long) + return MethodHandles.collectArguments(tryFinally, 0, HANDLES_CACHE.apply(ACQUIRE_ARENA)); + } + + private static MethodHandle makeSegmentExtractionHandle(SegmentExtractorKey segmentExtractorKey) { + final VarHandle vh = CAPTURE_LAYOUT.varHandle( + MemoryLayout.PathElement.groupElement(segmentExtractorKey.stateName())); + // This MH is used to extract the named captured state + // from the capturing `MemorySegment`. + // (MemorySegment, long)int + MethodHandle intExtractor = vh.toMethodHandle(VarHandle.AccessMode.GET); + // As the MH is already adapted to use the appropriate + // offset, we just insert `0L` for the offset. + // (MemorySegment)int + intExtractor = MethodHandles.insertArguments(intExtractor, 1, 0L); + + // If X is the `returnType` (either `int` or `long`) then + // the code below is equivalent to: + // + // X handle(X returnValue, MemorySegment segment) + // if (returnValue >= 0) { + // // Ignore the segment + // return returnValue; + // } else { + // // ignore the returnValue + // return -(X)intExtractor.invokeExact(segment); + // } + // } + if (segmentExtractorKey.returnType().equals(int.class)) { + // (int, MemorySegment)int + return MethodHandles.guardWithTest( + HANDLES_CACHE.apply(NON_NEGATIVE_INT), + HANDLES_CACHE.apply(SUCCESS_INT), + HANDLES_CACHE.apply(ERROR_INT).bindTo(intExtractor)); + } else { + // (long, MemorySegment)long + return MethodHandles.guardWithTest( + HANDLES_CACHE.apply(NON_NEGATIVE_LONG), + HANDLES_CACHE.apply(SUCCESS_LONG), + HANDLES_CACHE.apply(ERROR_LONG).bindTo(intExtractor)); + } + } + + // The methods below are reflective used via static MethodHandles + + @ForceInline + private static Arena acquireArena() { + return POOL.pushFrame(CAPTURE_LAYOUT); + } + + @ForceInline + private static MemorySegment allocate(Arena arena) { + return arena.allocate(CAPTURE_LAYOUT.byteSize(), CAPTURE_LAYOUT.byteAlignment()); + } + + @ForceInline + private static boolean nonNegative(int value) { + return value >= 0; + } + + @ForceInline + private static int success(int value, + MemorySegment segment) { + return value; + } + + @ForceInline + private static int error(MethodHandle errorHandle, + int value, + MemorySegment segment) throws Throwable { + return -(int) errorHandle.invokeExact(segment); + } + + @ForceInline + private static boolean nonNegative(long value) { + return value >= 0L; + } + + @ForceInline + private static long success(long value, + MemorySegment segment) { + return value; + } + + @ForceInline + private static long error(MethodHandle errorHandle, + long value, + MemorySegment segment) throws Throwable { + return -(int) errorHandle.invokeExact(segment); + } + + // The method handles below are bound to static methods residing in this class + + private static final int + NON_NEGATIVE_INT = 0, + SUCCESS_INT = 1, + ERROR_INT = 2, + NON_NEGATIVE_LONG = 3, + SUCCESS_LONG = 4, + ERROR_LONG = 5, + ACQUIRE_ARENA = 6, + ALLOCATE = 7, + ARENA_CLOSE = 8; + + // Do not use a lambda in order to allow early use in the init sequence + private static final IntFunction UNDERLYING_MAKE_HANDLE = new IntFunction() { + @Override + public MethodHandle apply(int value) { + return makeHandle(value); + } + }; + + private static final IntFunction HANDLES_CACHE = + StableValue.intFunction(ARENA_CLOSE + 1, UNDERLYING_MAKE_HANDLE); + + private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + + private static MethodHandle makeHandle(int index) { + return switch (index) { + case NON_NEGATIVE_INT -> MhUtil.findStatic(LOOKUP, "nonNegative", + MethodType.methodType(boolean.class, int.class)); + case SUCCESS_INT -> MhUtil.findStatic(LOOKUP, "success", + MethodType.methodType(int.class, int.class, MemorySegment.class)); + case ERROR_INT -> MhUtil.findStatic(LOOKUP, "error", + MethodType.methodType(int.class, MethodHandle.class, int.class, MemorySegment.class)); + case NON_NEGATIVE_LONG -> MhUtil.findStatic(LOOKUP, "nonNegative", + MethodType.methodType(boolean.class, long.class)); + case SUCCESS_LONG -> MhUtil.findStatic(LOOKUP, "success", + MethodType.methodType(long.class, long.class, MemorySegment.class)); + case ERROR_LONG -> MhUtil.findStatic(LOOKUP, "error", + MethodType.methodType(long.class, MethodHandle.class, long.class, MemorySegment.class)); + case ACQUIRE_ARENA -> MhUtil.findStatic(LOOKUP, "acquireArena", + MethodType.methodType(Arena.class)); + case ALLOCATE -> MhUtil.findStatic(LOOKUP, "allocate", + MethodType.methodType(MemorySegment.class, Arena.class)); + case ARENA_CLOSE -> MhUtil.findVirtual(LOOKUP, Arena.class, "close", + MethodType.methodType(void.class)); + default -> throw new InternalError("Unknown index: " + index); + }; + } + +} diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java index 5f0794c81d9..76513c6772c 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java @@ -53,7 +53,7 @@ private SegmentBulkOperations() {} // All the threshold values below MUST be a power of two and should preferably be // greater or equal to 2^3. - private static final int NATIVE_THRESHOLD_FILL = powerOfPropertyOr("fill", Architecture.isAARCH64() ? 18 : 5); + private static final int NATIVE_THRESHOLD_FILL = powerOfPropertyOr("fill", 5); private static final int NATIVE_THRESHOLD_MISMATCH = powerOfPropertyOr("mismatch", 6); private static final int NATIVE_THRESHOLD_COPY = powerOfPropertyOr("copy", 6); diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index f4ea2ed8c74..3edcac2e44c 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -192,6 +192,13 @@ private static long allocateNativeInternal(long byteSize, long byteAlignment, Me } // Align the allocation size up to a multiple of 8 so we can init the memory with longs long alignedSize = init ? Utils.alignUp(byteSize, Long.BYTES) : byteSize; + // Check for wrap around + if (alignedSize < 0) { + throw new OutOfMemoryError(); + } + // Always allocate at least some memory so that zero-length segments have distinct + // non-zero addresses. + alignedSize = Math.max(1, alignedSize); long allocationSize; long allocationBase; diff --git a/src/java.base/share/classes/jdk/internal/foreign/SlicingAllocator.java b/src/java.base/share/classes/jdk/internal/foreign/SlicingAllocator.java index db7d476053e..6b1a071c2af 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SlicingAllocator.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SlicingAllocator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,22 @@ public SlicingAllocator(MemorySegment segment) { this.segment = segment; } + public long currentOffset() { + return sp; + } + + public void resetTo(long offset) { + if (offset < 0 || offset > sp) + throw new IllegalArgumentException(String.format("offset %d should be in [0, %d] ", offset, sp)); + this.sp = offset; + } + + public boolean canAllocate(long byteSize, long byteAlignment) { + long min = segment.address(); + long start = Utils.alignUp(min + sp, byteAlignment) - min; + return start + byteSize <= segment.byteSize(); + } + MemorySegment trySlice(long byteSize, long byteAlignment) { long min = segment.address(); long start = Utils.alignUp(min + sp, byteAlignment) - min; diff --git a/src/java.base/share/classes/jdk/internal/foreign/SystemLookup.java b/src/java.base/share/classes/jdk/internal/foreign/SystemLookup.java index bf5371d43a0..640c7580d15 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SystemLookup.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SystemLookup.java @@ -25,6 +25,7 @@ package jdk.internal.foreign; +import jdk.internal.loader.NativeLibraries; import jdk.internal.loader.NativeLibrary; import jdk.internal.loader.RawNativeLibraries; import jdk.internal.util.OperatingSystem; @@ -66,7 +67,7 @@ private static SymbolLookup makeSystemLookup() { if (OperatingSystem.isWindows()) { return makeWindowsLookup(); } else { - return libLookup(libs -> libs.load(jdkLibraryPath("syslookup"))); + return sysLookup(); } } catch (Throwable ex) { // This can happen in the event of a library loading failure - e.g. if one of the libraries the @@ -84,13 +85,12 @@ private static SymbolLookup makeWindowsLookup() { boolean useUCRT = Files.exists(ucrtbase); Path stdLib = useUCRT ? ucrtbase : msvcrt; - SymbolLookup lookup = libLookup(libs -> libs.load(stdLib)); + SymbolLookup lookup = stdLibLookup(libs -> libs.load(stdLib)); if (useUCRT) { // use a fallback lookup to look up inline functions from fallback lib - SymbolLookup fallbackLibLookup = - libLookup(libs -> libs.load(jdkLibraryPath("syslookup"))); + SymbolLookup fallbackLibLookup = sysLookup(); @SuppressWarnings("restricted") MemorySegment funcs = fallbackLibLookup.findOrThrow("funcs") @@ -110,8 +110,7 @@ private static SymbolLookup makeWindowsLookup() { return lookup; } - private static SymbolLookup libLookup(Function loader) { - NativeLibrary lib = loader.apply(RawNativeLibraries.newInstance(MethodHandles.lookup())); + private static SymbolLookup lookup(NativeLibrary lib) { return name -> { Objects.requireNonNull(name); if (Utils.containsNullChars(name)) return Optional.empty(); @@ -126,16 +125,17 @@ private static SymbolLookup libLookup(Function loader) { + NativeLibrary lib = loader.apply(RawNativeLibraries.newInstance(MethodHandles.lookup())); + return lookup(lib); } + @SuppressWarnings("restricted") + private static SymbolLookup sysLookup() { + NativeLibraries libs = NativeLibraries.newInstance(null); + NativeLibrary lib = libs.loadLibrary(SymbolLookup.class, "syslookup"); + return lookup(lib); + } public static SystemLookup getInstance() { return INSTANCE; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java index 19b235963a3..401d3e9a9c5 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java @@ -71,7 +71,20 @@ public interface UpcallStubFactory { MemorySegment makeStub(MethodHandle target, Arena arena); } - private record LinkRequest(FunctionDescriptor descriptor, LinkerOptions options) {} + private record LinkRequest(FunctionDescriptor descriptor, LinkerOptions options) { + // Overrides for boot performance + @Override + public boolean equals(Object obj) { + return obj instanceof LinkRequest other && + other.descriptor.equals(descriptor) && + other.options.equals(options); + } + + @Override + public int hashCode() { + return descriptor.hashCode() * 1237 + options.hashCode(); + } + } private final SoftReferenceCache DOWNCALL_CACHE = new SoftReferenceCache<>(); private final SoftReferenceCache UPCALL_CACHE = new SoftReferenceCache<>(); private final Set CANONICAL_LAYOUTS_CACHE = new HashSet<>(canonicalLayouts().values()); @@ -308,22 +321,30 @@ private static MemoryLayout stripNames(MemoryLayout ml) { case StructLayout sl -> MemoryLayout.structLayout(stripNames(sl.memberLayouts())); case UnionLayout ul -> MemoryLayout.unionLayout(stripNames(ul.memberLayouts())); case SequenceLayout sl -> MemoryLayout.sequenceLayout(sl.elementCount(), stripNames(sl.elementLayout())); - case AddressLayout al -> al.targetLayout() - .map(tl -> al.withoutName().withTargetLayout(stripNames(tl))) // restricted - .orElseGet(al::withoutName); + case AddressLayout al -> { + var stripped = al.withoutName(); + var target = al.targetLayout(); + if (target.isPresent()) + stripped = stripped.withTargetLayout(stripNames(target.get())); + yield stripped; + } default -> ml.withoutName(); // ValueLayout and PaddingLayout }; } private static MemoryLayout[] stripNames(List layouts) { - return layouts.stream() - .map(AbstractLinker::stripNames) - .toArray(MemoryLayout[]::new); + var ret = new MemoryLayout[layouts.size()]; + for (int i = 0; i < ret.length; i++) { + ret[i] = stripNames(layouts.get(i)); + } + return ret; } private static FunctionDescriptor stripNames(FunctionDescriptor function) { - return function.returnLayout() - .map(rl -> FunctionDescriptor.of(stripNames(rl), stripNames(function.argumentLayouts()))) - .orElseGet(() -> FunctionDescriptor.ofVoid(stripNames(function.argumentLayouts()))); + var retLayout = function.returnLayout(); + if (retLayout.isEmpty()) { + return FunctionDescriptor.ofVoid(stripNames(function.argumentLayouts())); + } + return FunctionDescriptor.of(stripNames(retLayout.get()), stripNames(function.argumentLayouts())); } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java index 4f7a049fd6d..c2a74eb0965 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java @@ -185,9 +185,7 @@ public boolean hasReturnBindings() { } public int capturedStateMask() { - return linkerOptions.capturedCallState() - .mapToInt(CapturableState::mask) - .reduce(0, (a, b) -> a | b); + return linkerOptions.capturedCallStateMask(); } public boolean needsTransition() { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index 7fb62c56bf1..d22c23b03a1 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,61 +29,68 @@ import java.lang.foreign.MemoryLayout; import java.lang.foreign.StructLayout; -import java.lang.foreign.ValueLayout; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import java.util.ArrayList; +import java.util.Map; import static java.lang.foreign.ValueLayout.JAVA_INT; -public enum CapturableState { - GET_LAST_ERROR ("GetLastError", JAVA_INT, 1 << 0, OperatingSystem.isWindows()), - WSA_GET_LAST_ERROR("WSAGetLastError", JAVA_INT, 1 << 1, OperatingSystem.isWindows()), - ERRNO ("errno", JAVA_INT, 1 << 2, true); - - public static final StructLayout LAYOUT = MemoryLayout.structLayout( - supportedStates().map(CapturableState::layout).toArray(MemoryLayout[]::new)); - - private final String stateName; - private final ValueLayout layout; - private final int mask; - private final boolean isSupported; - - CapturableState(String stateName, ValueLayout layout, int mask, boolean isSupported) { - this.stateName = stateName; - this.layout = layout.withName(stateName); - this.mask = mask; - this.isSupported = isSupported; - } - - private static Stream supportedStates() { - return Stream.of(values()).filter(CapturableState::isSupported); - } +/** + * Utility class for the call states to capture. + */ +public final class CapturableState { - public static CapturableState forName(String name) { - return Stream.of(values()) - .filter(stl -> stl.stateName().equals(name)) - .filter(CapturableState::isSupported) - .findAny() - .orElseThrow(() -> new IllegalArgumentException( - "Unknown name: " + name +", must be one of: " - + supportedStates() - .map(CapturableState::stateName) - .collect(Collectors.joining(", ")))); - } + public static final StructLayout LAYOUT; + // Keep in synch with DowncallLinker::capture_state in downcallLinker.cpp + private static final Map MASKS; - public String stateName() { - return stateName; + static { + if (OperatingSystem.isWindows()) { + LAYOUT = MemoryLayout.structLayout( + JAVA_INT.withName("GetLastError"), + JAVA_INT.withName("WSAGetLastError"), + JAVA_INT.withName("errno")); + MASKS = Map.of( + "GetLastError", 1 << 0, + "WSAGetLastError", 1 << 1, + "errno", 1 << 2 + ); + } else { + LAYOUT = MemoryLayout.structLayout( + JAVA_INT.withName("errno")); + MASKS = Map.of( + "errno", 1 << 2 + ); + } } - public ValueLayout layout() { - return layout; + private CapturableState() { } - public int mask() { - return mask; + /** + * Returns the mask for a supported capturable state, or throw an + * IllegalArgumentException if no supported state with this name exists. + */ + public static int maskFromName(String name) { + var ret = MASKS.get(name); + if (ret == null) { + throw new IllegalArgumentException( + "Unknown name: " + name + ", must be one of: " + + MASKS.keySet()); + } + return ret; } - public boolean isSupported() { - return isSupported; + /** + * Returns a collection-like display string for a captured state mask. + * Enclosed with brackets. + */ + public static String displayString(int mask) { + var displayList = new ArrayList<>(); // unordered + for (var e : MASKS.entrySet()) { + if ((mask & e.getValue()) != 0) { + displayList.add(e.getKey()); + } + } + return displayList.toString(); } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java b/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java index 5ca410f40e2..848d6b22b83 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.Linker; +import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -83,9 +84,9 @@ public boolean hasCapturedCallState() { return getOption(CaptureCallState.class) != null; } - public Stream capturedCallState() { + public int capturedCallStateMask() { CaptureCallState stl = getOption(CaptureCallState.class); - return stl == null ? Stream.empty() : stl.saved().stream(); + return stl == null ? 0 : stl.mask(); } public boolean isVariadicFunction() { @@ -137,18 +138,47 @@ public void validateForDowncall(FunctionDescriptor descriptor) { throw new IllegalArgumentException("Index '" + index + "' not in bounds for descriptor: " + descriptor); } } + + @Override + public int hashCode() { + return index; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof FirstVariadicArg that && index == that.index; + } } - public record CaptureCallState(Set saved) implements LinkerOptionImpl { + public record CaptureCallState(int mask) implements LinkerOptionImpl { @Override public void validateForDowncall(FunctionDescriptor descriptor) { // done during construction } + + @Override + public boolean equals(Object obj) { + return obj instanceof CaptureCallState that && mask == that.mask; + } + + @Override + public int hashCode() { + return mask; + } + + @Override + public String toString() { + return "CaptureCallState" + CapturableState.displayString(mask); + } } - public record Critical(boolean allowHeapAccess) implements LinkerOptionImpl { - public static Critical ALLOW_HEAP = new Critical(true); - public static Critical DONT_ALLOW_HEAP = new Critical(false); + public enum Critical implements LinkerOptionImpl { + ALLOW_HEAP, + DONT_ALLOW_HEAP; + + public boolean allowHeapAccess() { + return ordinal() == 0; // this == ALLOW_HEAP + } @Override public void validateForDowncall(FunctionDescriptor descriptor) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/NativeEntryPoint.java b/src/java.base/share/classes/jdk/internal/foreign/abi/NativeEntryPoint.java index abcc6027919..3940f996e0d 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/NativeEntryPoint.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/NativeEntryPoint.java @@ -48,7 +48,29 @@ public class NativeEntryPoint { private record CacheKey(MethodType methodType, ABIDescriptor abi, List argMoves, List retMoves, boolean needsReturnBuffer, int capturedStateMask, - boolean needsTransition) {} + boolean needsTransition) { + + @Override + public boolean equals(Object o) { + if (!(o instanceof CacheKey other)) return false; + + return methodType == other.methodType && abi == other.abi && capturedStateMask == other.capturedStateMask + && needsTransition == other.needsTransition && needsReturnBuffer == other.needsReturnBuffer + && argMoves.equals(other.argMoves) && retMoves.equals(other.retMoves); + } + + @Override + public int hashCode() { + int result = System.identityHashCode(methodType); + result = 31 * result + abi.hashCode(); + result = 31 * result + argMoves.hashCode(); + result = 31 * result + retMoves.hashCode(); + result = 31 * result + Boolean.hashCode(needsReturnBuffer); + result = 31 * result + capturedStateMask; + result = 31 * result + Boolean.hashCode(needsTransition); + return result; + } + } private NativeEntryPoint(MethodType methodType, long downcallStubAddress) { this.methodType = methodType; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java index 125730560a2..37200598d5b 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java @@ -24,9 +24,9 @@ */ package jdk.internal.foreign.abi; -import jdk.internal.access.JavaLangAccess; import jdk.internal.access.JavaLangInvokeAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.foreign.BufferStack; import jdk.internal.foreign.CABI; import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory; import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker; @@ -390,26 +390,12 @@ static long pickChunkOffset(long chunkOffset, long byteWidth, int chunkWidth) { : chunkOffset; } - public static Arena newBoundedArena(long size) { - return new Arena() { - final Arena arena = Arena.ofConfined(); - final SegmentAllocator slicingAllocator = SegmentAllocator.slicingAllocator(arena.allocate(size)); - - @Override - public Scope scope() { - return arena.scope(); - } + private static final int LINKER_STACK_SIZE = Integer.getInteger("jdk.internal.foreign.LINKER_STACK_SIZE", 256); + private static final BufferStack LINKER_STACK = BufferStack.of(LINKER_STACK_SIZE, 1); - @Override - public void close() { - arena.close(); - } - - @Override - public MemorySegment allocate(long byteSize, long byteAlignment) { - return slicingAllocator.allocate(byteSize, byteAlignment); - } - }; + @ForceInline + public static Arena newBoundedArena(long size) { + return LINKER_STACK.pushFrame(size, 8); } public static Arena newEmptyArena() { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/VMStorage.java b/src/java.base/share/classes/jdk/internal/foreign/abi/VMStorage.java index 1237650e026..0be1675ccd8 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/VMStorage.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/VMStorage.java @@ -24,6 +24,8 @@ */ package jdk.internal.foreign.abi; +import java.util.Objects; + /** * * @param type the type of storage. e.g. stack, or which register type (GP, FP, vector) @@ -32,7 +34,7 @@ * @param indexOrOffset the index is either a register number within a type, or * a stack offset in bytes if type = stack. * (a particular platform might add a bias to this in generate code) - * @param debugName the debug name + * @param debugName the debug name, mostly derived from type */ public record VMStorage(byte type, short segmentMaskOrSize, @@ -43,4 +45,14 @@ public VMStorage(byte type, short segmentMaskOrSize, int indexOrOffset) { this(type, segmentMaskOrSize, indexOrOffset, "Stack@" + indexOrOffset); } + @Override + public int hashCode() { + return Objects.hash(type, segmentMaskOrSize, indexOrOffset); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof VMStorage that && + type == that.type && segmentMaskOrSize == that.segmentMaskOrSize && indexOrOffset == that.indexOrOffset; + } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java index 9be958e7689..7343a23436d 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java @@ -84,9 +84,7 @@ protected MethodHandle arrangeDowncall(MethodType inferredMethodType, FunctionDe assertNotEmpty(function); MemorySegment cif = makeCif(inferredMethodType, function, options, Arena.ofAuto()); - int capturedStateMask = options.capturedCallState() - .mapToInt(CapturableState::mask) - .reduce(0, (a, b) -> a | b); + int capturedStateMask = options.capturedCallStateMask(); DowncallData invData = new DowncallData(cif, function.returnLayout().orElse(null), function.argumentLayouts(), capturedStateMask, options.allowsHeapAccess()); diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java index 08bd840de37..2168a1c4feb 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,8 +40,6 @@ public interface JdkConsole { Reader reader(); JdkConsole println(Object obj); JdkConsole print(Object obj); - String readln(String prompt); - String readln(); JdkConsole format(Locale locale, String format, Object ... args); String readLine(Locale locale, String format, Object ... args); String readLine(); diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java index 3c0afd2005c..ec94d4ec4d6 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,40 +71,6 @@ public JdkConsole print(Object obj) { return this; } - @Override - public String readln(String prompt) { - String line = null; - synchronized (writeLock) { - synchronized(readLock) { - pw.print(prompt); - pw.flush(); // automatic flushing does not cover print - try { - char[] ca = readline(false); - if (ca != null) - line = new String(ca); - } catch (IOException x) { - throw new IOError(x); - } - } - } - return line; - } - - @Override - public String readln() { - String line = null; - synchronized(readLock) { - try { - char[] ca = readline(false); - if (ca != null) - line = new String(ca); - } catch (IOException x) { - throw new IOError(x); - } - } - return line; - } - @Override public JdkConsole format(Locale locale, String format, Object ... args) { formatter.format(locale, format, args).flush(); @@ -225,10 +191,11 @@ public void flush() { @Override public Charset charset() { - return charset; + return outCharset; } - private final Charset charset; + private final Charset inCharset; + private final Charset outCharset; private final Object readLock; private final Object writeLock; // Must not block while holding this. It is used in the shutdown hook. @@ -398,16 +365,18 @@ public int read(char[] cbuf, int offset, int length) } } - public JdkConsoleImpl(Charset charset) { - Objects.requireNonNull(charset); - this.charset = charset; + public JdkConsoleImpl(Charset inCharset, Charset outCharset) { + Objects.requireNonNull(inCharset); + Objects.requireNonNull(outCharset); + this.inCharset = inCharset; + this.outCharset = outCharset; readLock = new Object(); writeLock = new Object(); restoreEchoLock = new Object(); out = StreamEncoder.forOutputStreamWriter( new FileOutputStream(FileDescriptor.out), writeLock, - charset); + outCharset); pw = new PrintWriter(out, true) { public void close() { } @@ -416,7 +385,7 @@ public void close() { reader = new LineReader(StreamDecoder.forInputStreamReader( new FileInputStream(FileDescriptor.in), readLock, - charset)); + inCharset)); rcb = new char[1024]; } } diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleProvider.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleProvider.java index 4ac196d67ff..f3cc67e85a0 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleProvider.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleProvider.java @@ -38,7 +38,8 @@ public interface JdkConsoleProvider { /** * {@return the Console instance, or {@code null} if not available} * @param isTTY indicates if the jvm is attached to a terminal - * @param charset charset of the platform console + * @param inCharset Standard input charset of the platform console + * @param outCharset Standard output charset of the platform console */ - JdkConsole console(boolean isTTY, Charset charset); + JdkConsole console(boolean isTTY, Charset inCharset, Charset outCharset); } diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index deb786b42bd..e6c994a12b1 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,18 +68,18 @@ public enum Feature { // keeping the constant of a feature that has been integrated or dropped, serves the purpose of muting such warnings. //--- - @JEP(number=495, title="Simple Source Files and Instance Main Methods", status="Fourth Preview") - IMPLICIT_CLASSES, - @JEP(number=487, title="Scoped Values", status="Fourth Preview") + IMPLICIT_CLASSES, //to be removed when boot JDK is 25 SCOPED_VALUES, - @JEP(number=499, title="Structured Concurrency", status="Fourth Preview") + @JEP(number=505, title="Structured Concurrency", status="Fifth Preview") STRUCTURED_CONCURRENCY, CLASSFILE_API, STREAM_GATHERERS, - @JEP(number=494, title="Module Import Declarations", status="Second Preview") - MODULE_IMPORTS, - @JEP(number=478, title="Key Derivation Function API", status="Preview") - KEY_DERIVATION, + MODULE_IMPORTS, //remove when the boot JDK is JDK 25 + KEY_DERIVATION, //remove when the boot JDK is JDK 25 + @JEP(number = 502, title = "Stable Values", status = "Preview") + STABLE_VALUES, + @JEP(number=470, title="PEM Encodings of Cryptographic Objects", status="Preview") + PEM_API, LANGUAGE_MODEL, /** * A key for testing. diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableEnumFunction.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableEnumFunction.java new file mode 100644 index 00000000000..d6893438be5 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/stable/StableEnumFunction.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.lang.stable; + +import jdk.internal.util.ImmutableBitSetPredicate; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.IntPredicate; +import java.util.function.Supplier; + +/** + * Optimized implementation of a stable Function with enums as keys. + * + * @implNote This implementation can be used early in the boot sequence as it does not + * rely on reflection, MethodHandles, Streams etc. + * + * @param enumType the class type of the Enum + * @param firstOrdinal the lowest ordinal used + * @param member an int predicate that can be used to test if an enum is a member + * of the valid inputs (as there might be "holes") + * @param delegates a delegate array of inputs to StableValue mappings + * @param original the original Function + * @param the type of the input to the function + * @param the type of the result of the function + */ +public record StableEnumFunction, R>(Class enumType, + int firstOrdinal, + IntPredicate member, + @Stable StableValueImpl[] delegates, + Function original) implements Function { + @ForceInline + @Override + public R apply(E value) { + if (!member.test(value.ordinal())) { // Implicit null-check of value + throw new IllegalArgumentException("Input not allowed: " + value); + } + final int index = value.ordinal() - firstOrdinal; + // Since we did the member.test above, we know the index is in bounds + return delegates[index].orElseSet(new Supplier() { + @Override public R get() { return original.apply(value); }}); + + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object obj) { + return obj == this; + } + + @Override + public String toString() { + final Collection>> entries = new ArrayList<>(delegates.length); + final E[] enumElements = enumType.getEnumConstants(); + int ordinal = firstOrdinal; + for (int i = 0; i < delegates.length; i++, ordinal++) { + if (member.test(ordinal)) { + entries.add(new AbstractMap.SimpleImmutableEntry<>(enumElements[ordinal], delegates[i])); + } + } + return StableUtil.renderMappings(this, "StableFunction", entries, true); + } + + @SuppressWarnings("unchecked") + public static , R> Function of(Set inputs, + Function original) { + // The input set is not empty + final Class enumType = ((E) inputs.iterator().next()).getDeclaringClass(); + final BitSet bitSet = new BitSet(enumType.getEnumConstants().length); + int min = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + for (T t : inputs) { + final int ordinal = ((E) t).ordinal(); + min = Math.min(min, ordinal); + max = Math.max(max, ordinal); + bitSet.set(ordinal); + } + final int size = max - min + 1; + final IntPredicate member = ImmutableBitSetPredicate.of(bitSet); + return (Function) new StableEnumFunction(enumType, min, member, StableUtil.array(size), (Function) original); + } + +} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableFunction.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableFunction.java new file mode 100644 index 00000000000..e36b4e9b25a --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/stable/StableFunction.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.lang.stable; + +import jdk.internal.vm.annotation.ForceInline; + +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; + +// Note: It would be possible to just use `StableMap::get` with some additional logic +// instead of this class but explicitly providing a class like this provides better +// debug capability, exception handling, and may provide better performance. +/** + * Implementation of a stable Function. + * + * @implNote This implementation can be used early in the boot sequence as it does not + * rely on reflection, MethodHandles, Streams etc. + * + * @param values a delegate map of inputs to StableValue mappings + * @param original the original Function + * @param the type of the input to the function + * @param the type of the result of the function + */ +public record StableFunction(Map> values, + Function original) implements Function { + + @ForceInline + @Override + public R apply(T value) { + final StableValueImpl stable = values.get(value); + if (stable == null) { + throw new IllegalArgumentException("Input not allowed: " + value); + } + return stable.orElseSet(new Supplier() { + @Override public R get() { return original.apply(value); }}); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object obj) { + return obj == this; + } + + @Override + public String toString() { + return StableUtil.renderMappings(this, "StableFunction", values.entrySet(), true); + } + + public static StableFunction of(Set inputs, + Function original) { + return new StableFunction<>(StableUtil.map(inputs), original); + } + +} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableIntFunction.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableIntFunction.java new file mode 100644 index 00000000000..a921a4de87b --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/stable/StableIntFunction.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.lang.stable; + +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; + +import java.util.function.IntFunction; +import java.util.function.Supplier; + +/** + * Implementation of a stable IntFunction. + *

              + * For performance reasons (~10%), we are not delegating to a StableList but are using + * the more primitive functions in StableValueUtil that are shared with StableList/StableValueImpl. + * + * @implNote This implementation can be used early in the boot sequence as it does not + * rely on reflection, MethodHandles, Streams etc. + * + * @param the return type + */ +public record StableIntFunction(@Stable StableValueImpl[] delegates, + IntFunction original) implements IntFunction { + + @ForceInline + @Override + public R apply(int index) { + final StableValueImpl delegate; + try { + delegate = delegates[index]; + } catch (ArrayIndexOutOfBoundsException ioob) { + throw new IllegalArgumentException("Input not allowed: " + index, ioob); + } + return delegate.orElseSet(new Supplier() { + @Override public R get() { return original.apply(index); }}); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object obj) { + return obj == this; + } + + @Override + public String toString() { + return StableUtil.renderElements(this, "StableIntFunction", delegates); + } + + public static StableIntFunction of(int size, IntFunction original) { + return new StableIntFunction<>(StableUtil.array(size), original); + } + +} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableSupplier.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableSupplier.java new file mode 100644 index 00000000000..631a41c5710 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/stable/StableSupplier.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.lang.stable; + +import jdk.internal.vm.annotation.ForceInline; + +import java.util.function.Supplier; + +/** + * Implementation of a stable supplier. + *

              + * @implNote This implementation can be used early in the boot sequence as it does not + * rely on reflection, MethodHandles, Streams etc. + * + * @param the return type + */ +public record StableSupplier(StableValueImpl delegate, + Supplier original) implements Supplier { + + @ForceInline + @Override + public T get() { + return delegate.orElseSet(original); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object obj) { + return obj == this; + } + + @Override + public String toString() { + final Object t = delegate.wrappedContentsAcquire(); + return t == this ? "(this StableSupplier)" : StableValueImpl.renderWrapped(t); + } + + public static StableSupplier of(Supplier original) { + return new StableSupplier<>(StableValueImpl.of(), original); + } + +} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableUtil.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableUtil.java new file mode 100644 index 00000000000..74104ddbb49 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/stable/StableUtil.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.lang.stable; + +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.StringJoiner; + +public final class StableUtil { + + private StableUtil() {} + + public static String renderElements(Object self, + String selfName, + StableValueImpl[] delegates) { + return renderElements(self, selfName, delegates, 0, delegates.length); + } + + public static String renderElements(Object self, + String selfName, + StableValueImpl[] delegates, + int offset, + int length) { + final StringJoiner sj = new StringJoiner(", ", "[", "]"); + for (int i = 0; i < length; i++) { + final Object value = delegates[i + offset].wrappedContentsAcquire(); + if (value == self) { + sj.add("(this " + selfName + ")"); + } else { + sj.add(StableValueImpl.renderWrapped(value)); + } + } + return sj.toString(); + } + + public static String renderMappings(Object self, + String selfName, + Iterable>> delegates, + boolean curly) { + final StringJoiner sj = new StringJoiner(", ", curly ? "{" : "[", curly ? "}" : "]"); + for (var e : delegates) { + final Object value = e.getValue().wrappedContentsAcquire(); + final String valueString; + if (value == self) { + valueString = "(this " + selfName + ")"; + } else { + valueString = StableValueImpl.renderWrapped(value); + } + sj.add(e.getKey() + "=" + valueString); + } + return sj.toString(); + } + + public static StableValueImpl[] array(int size) { + assertSizeNonNegative(size); + @SuppressWarnings("unchecked") + final var stableValues = (StableValueImpl[]) new StableValueImpl[size]; + for (int i = 0; i < size; i++) { + stableValues[i] = StableValueImpl.of(); + } + return stableValues; + } + + public static Map> map(Set keys) { + Objects.requireNonNull(keys); + @SuppressWarnings("unchecked") + final var entries = (Map.Entry>[]) new Map.Entry[keys.size()]; + int i = 0; + for (K key : keys) { + entries[i++] = Map.entry(key, StableValueImpl.of()); + } + return Map.ofEntries(entries); + } + + public static void assertSizeNonNegative(int size) { + if (size < 0) { + throw new IllegalArgumentException("size can not be negative: " + size); + } + } + +} diff --git a/src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java b/src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java new file mode 100644 index 00000000000..1413fd7446e --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/lang/stable/StableValueImpl.java @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.lang.stable; + +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; + +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Supplier; + +/** + * The implementation of StableValue. + * + * @implNote This implementation can be used early in the boot sequence as it does not + * rely on reflection, MethodHandles, Streams etc. + * + * @param type of the contents + */ +public final class StableValueImpl implements StableValue { + + static final String UNSET_LABEL = ".unset"; + + // Unsafe allows StableValue to be used early in the boot sequence + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + // Unsafe offsets for direct field access + + private static final long CONTENTS_OFFSET = + UNSAFE.objectFieldOffset(StableValueImpl.class, "contents"); + + // Used to indicate a holder value is `null` (see field `contents` below) + private static final Object NULL_SENTINEL = new Object(); + + // Generally, fields annotated with `@Stable` are accessed by the JVM using special + // memory semantics rules (see `parse.hpp` and `parse(1|2|3).cpp`). + // + // This field is used directly and reflectively via Unsafe using explicit memory semantics. + // + // | Value | Meaning | + // | -------------- | ------------ | + // | null | Unset | + // | NULL_SENTINEL | Set(null) | + // | other | Set(other) | + // + @Stable + private Object contents; + + // Only allow creation via the factory `StableValueImpl::newInstance` + private StableValueImpl() {} + + @ForceInline + @Override + public boolean trySet(T contents) { + if (wrappedContentsAcquire() != null) { + return false; + } + // Prevent reentry via an orElseSet(supplier) + preventReentry(); + // Mutual exclusion is required here as `orElseSet` might also + // attempt to modify `this.contents` + synchronized (this) { + return wrapAndSet(contents); + } + } + + @ForceInline + @Override + public void setOrThrow(T contents) { + if (!trySet(contents)) { + // Neither the set contents nor the provided contents is revealed in the + // exception message as it might be sensitive. + throw new IllegalStateException("The contents is already set"); + } + } + + @ForceInline + @Override + public T orElseThrow() { + final Object t = wrappedContentsAcquire(); + if (t == null) { + throw new NoSuchElementException("No contents set"); + } + return unwrap(t); + } + + @ForceInline + @Override + public T orElse(T other) { + final Object t = wrappedContentsAcquire(); + return (t == null) ? other : unwrap(t); + } + + @ForceInline + @Override + public boolean isSet() { + return wrappedContentsAcquire() != null; + } + + @ForceInline + @Override + public T orElseSet(Supplier supplier) { + Objects.requireNonNull(supplier); + final Object t = wrappedContentsAcquire(); + return (t == null) ? orElseSetSlowPath(supplier) : unwrap(t); + } + + @DontInline + private T orElseSetSlowPath(Supplier supplier) { + preventReentry(); + synchronized (this) { + final Object t = contents; // Plain semantics suffice here + if (t == null) { + final T newValue = supplier.get(); + // The mutex is not reentrant so we know newValue should be returned + wrapAndSet(newValue); + return newValue; + } + return unwrap(t); + } + } + + // The methods equals() and hashCode() should be based on identity (defaults from Object) + + @Override + public String toString() { + final Object t = wrappedContentsAcquire(); + return t == this + ? "(this StableValue)" + : renderWrapped(t); + } + + // Internal methods shared with other internal classes + + @ForceInline + public Object wrappedContentsAcquire() { + return UNSAFE.getReferenceAcquire(this, CONTENTS_OFFSET); + } + + static String renderWrapped(Object t) { + return (t == null) ? UNSET_LABEL : Objects.toString(unwrap(t)); + } + + // Private methods + + // This method is not annotated with @ForceInline as it is always called + // in a slow path. + private void preventReentry() { + if (Thread.holdsLock(this)) { + throw new IllegalStateException("Recursive initialization of a stable value is illegal"); + } + } + + /** + * Wraps the provided {@code newValue} and tries to set the contents. + *

              + * This method ensures the {@link Stable} field is written to at most once. + * + * @param newValue to wrap and set + * @return if the contents was set + */ + @ForceInline + private boolean wrapAndSet(T newValue) { + assert Thread.holdsLock(this); + // We know we hold the monitor here so plain semantic is enough + if (contents == null) { + UNSAFE.putReferenceRelease(this, CONTENTS_OFFSET, wrap(newValue)); + return true; + } + return false; + } + + + // Wraps `null` values into a sentinel value + @ForceInline + private static Object wrap(Object t) { + return (t == null) ? NULL_SENTINEL : t; + } + + // Unwraps null sentinel values into `null` + @SuppressWarnings("unchecked") + @ForceInline + private static T unwrap(Object t) { + return t != NULL_SENTINEL ? (T) t : null; + } + + // Factory + + public static StableValueImpl of() { + return new StableValueImpl<>(); + } + +} diff --git a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java index 0c1732956c9..6f59338d4c8 100644 --- a/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java @@ -25,8 +25,9 @@ package jdk.internal.math; +import jdk.internal.vm.annotation.Stable; + import java.util.Arrays; -import java.util.regex.*; /** * A class for converting between ASCII and decimal representations of a single @@ -48,7 +49,6 @@ public class FloatingDecimal{ static final int MAX_DECIMAL_DIGITS = 15; static final int MAX_DECIMAL_EXPONENT = 308; static final int MIN_DECIMAL_EXPONENT = -324; - static final int BIG_DECIMAL_EXPONENT = 324; // i.e. abs(MIN_DECIMAL_EXPONENT) static final int MAX_NDIGITS = 1100; static final int SINGLE_EXP_SHIFT = FloatConsts.SIGNIFICAND_WIDTH - 1; @@ -107,7 +107,7 @@ public static void appendTo(float f, Appendable buf) { * represent a properly formatted double precision value. */ public static double parseDouble(String s) throws NumberFormatException { - return readJavaFormatString(s).doubleValue(); + return readJavaFormatString(s, BINARY_64_IX).doubleValue(); } /** @@ -119,7 +119,7 @@ public static double parseDouble(String s) throws NumberFormatException { * represent a properly formatted single precision value. */ public static float parseFloat(String s) throws NumberFormatException { - return readJavaFormatString(s).floatValue(); + return readJavaFormatString(s, BINARY_32_IX).floatValue(); } /** @@ -188,7 +188,7 @@ public interface BinaryToASCIIConverter { */ private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter { private final String image; - private boolean isNegative; + private final boolean isNegative; public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) { this.image = image; @@ -243,9 +243,7 @@ public boolean decimalDigitsExact() { } private static final String INFINITY_REP = "Infinity"; - private static final int INFINITY_LENGTH = INFINITY_REP.length(); private static final String NAN_REP = "NaN"; - private static final int NAN_LENGTH = NAN_REP.length(); private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false); private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true); @@ -1826,726 +1824,619 @@ private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) { return buf; } - @SuppressWarnings("fallthrough") - static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException { - boolean isNegative = false; - boolean signSeen = false; - int decExp; - char c; - - parseNumber: - try{ - in = in.trim(); // don't fool around with white space. - // throws NullPointerException if null - int len = in.length(); - if ( len == 0 ) { - throw new NumberFormatException("empty String"); - } - int i = 0; - switch (in.charAt(i)){ - case '-': - isNegative = true; - //FALLTHROUGH - case '+': - i++; - signSeen = true; - } - c = in.charAt(i); - if(c == 'N') { // Check for NaN - if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) { - return A2BC_NOT_A_NUMBER; - } - // something went wrong, throw exception - break parseNumber; - } else if(c == 'I') { // Check for Infinity strings - if((len-i)==INFINITY_LENGTH && in.indexOf(INFINITY_REP,i)==i) { - return isNegative? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY; - } - // something went wrong, throw exception - break parseNumber; - } else if (c == '0') { // check for hexadecimal floating-point number - if (len > i+1 ) { - char ch = in.charAt(i+1); - if (ch == 'x' || ch == 'X' ) { // possible hex string - return parseHexString(in); - } - } - } // look for and process decimal floating-point string - - byte[] digits = new byte[len]; - boolean decSeen = false; - int nDigits = 0; - int decPt = 0; - int nLeadZero = 0; - int nTrailZero = 0; - - skipLeadingZerosLoop: - while (i < len) { - c = in.charAt(i); - if (c == '0') { - nLeadZero++; - } else if (c == '.') { - if (decSeen) { - // already saw one ., this is the 2nd. - throw new NumberFormatException("multiple points"); - } - decPt = i; - if (signSeen) { - decPt -= 1; - } - decSeen = true; - } else { - break skipLeadingZerosLoop; - } - i++; - } - digitLoop: - while (i < len) { - c = in.charAt(i); - if (c >= '1' && c <= '9') { - digits[nDigits++] = (byte) c; - nTrailZero = 0; - } else if (c == '0') { - digits[nDigits++] = (byte) c; - nTrailZero++; - } else if (c == '.') { - if (decSeen) { - // already saw one ., this is the 2nd. - throw new NumberFormatException("multiple points"); - } - decPt = i; - if (signSeen) { - decPt -= 1; - } - decSeen = true; - } else { - break digitLoop; - } - i++; + /** + * The input must match the {@link Double#valueOf(String) rules described here}, + * about leading and trailing whitespaces, and the grammar. + * + * @param in the non-null input + * @param ix one of the {@code BINARY__IX} constants, where {@code } + * is one of 16, 32, 64 + * @return an appropriate binary converter + * @throws NullPointerException if the input is null + * @throws NumberFormatException if the input is malformed + */ + static ASCIIToBinaryConverter readJavaFormatString(String in, int ix) { + /* + * The scanning proper does not allocate any object, + * nor does it perform any costly computation. + * This means that all scanning errors are detected without consuming + * any heap, before actually throwing. + * + * Once scanning is complete, the method determines the length + * of a prefix of the significand that is sufficient for correct + * rounding according to roundTiesToEven. + * The actual value of the prefix length might not be optimal, + * but is always a safe choice. + * + * For hexadecimal input, the prefix is processed by this method directly, + * without allocating objects before creating the returned instance. + * + * For decimal input, the prefix is copied to the returned instance, + * along with the other information needed for the conversion. + * For comparison, the prefix length is at most + * 23 for BINARY_16_IX (Float16, once integrated in java.base) + * 114 for BINARY_32_IX (float) + * 769 for BINARY_64_IX (double) + */ + int len = in.length(); // fail fast on null + + /* Skip leading whitespaces. */ + int i = skipWhitespaces(in, 0); // main running index + if (i == len) { + throw new NumberFormatException("empty String"); + } + + /* Scan opt significand sign. */ + int ch; // running char + int ssign = ' '; // ' ' iff sign is implicit + if ((ch = in.charAt(i)) == '-' || ch == '+') { // i < len + ssign = ch; + ++i; + } + + /* + * In some places the idiom + * (ch | 0b10_0000) == lowercase-letter + * is used as a shortcut for + * ch == lowercase-letter || ch == that-same-letter-as-uppercase + * + * Determine whether we are facing a symbolic value or hex notation. + */ + boolean isDec = true; // decimal input until proven to the contrary + if (i < len) { + ch = in.charAt(i); + if (ch == 'I') { + scanSymbolic(in, i, "Infinity"); + return ssign != '-' ? A2BC_POSITIVE_INFINITY : A2BC_NEGATIVE_INFINITY; } - nDigits -=nTrailZero; - // - // At this point, we've scanned all the digits and decimal - // point we're going to see. Trim off leading and trailing - // zeros, which will just confuse us later, and adjust - // our initial decimal exponent accordingly. - // To review: - // we have seen i total characters. - // nLeadZero of them were zeros before any other digits. - // nTrailZero of them were zeros after any other digits. - // if ( decSeen ), then a . was seen after decPt characters - // ( including leading zeros which have been discarded ) - // nDigits characters were neither lead nor trailing - // zeros, nor point - // - // - // special hack: if we saw no non-zero digits, then the - // answer is zero! - // Unfortunately, we feel honor-bound to keep parsing! - // - boolean isZero = (nDigits == 0); - if ( isZero && nLeadZero == 0 ){ - // we saw NO DIGITS AT ALL, - // not even a crummy 0! - // this is not allowed. - break parseNumber; // go throw exception + if (ch == 'N') { + scanSymbolic(in, i, "NaN"); + return A2BC_NOT_A_NUMBER; // ignore sign } - // - // Our initial exponent is decPt, adjusted by the number of - // discarded zeros. Or, if there was no decPt, - // then its just nDigits adjusted by discarded trailing zeros. - // - if ( decSeen ){ - decExp = decPt - nLeadZero; - } else { - decExp = nDigits + nTrailZero; + if (ch == '0' && i < len - 1 && (in.charAt(i + 1) | 0b10_0000) == 'x') { + isDec = false; + i += 2; } + } - // - // Look for 'e' or 'E' and an optionally signed integer. - // - if ( (i < len) && (((c = in.charAt(i) )=='e') || (c == 'E') ) ){ - int expSign = 1; - int expVal = 0; - int reallyBig = Integer.MAX_VALUE / 10; - boolean expOverflow = false; - switch( in.charAt(++i) ){ - case '-': - expSign = -1; - //FALLTHROUGH - case '+': - i++; - } - int expAt = i; - expLoop: - while ( i < len ){ - if ( expVal >= reallyBig ){ - // the next character will cause integer - // overflow. - expOverflow = true; - } - c = in.charAt(i++); - if(c>='0' && c<='9') { - expVal = expVal*10 + ( (int)c - (int)'0' ); - } else { - i--; // back up. - break expLoop; // stop parsing exponent. - } - } - int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero; - if (expOverflow || (expVal > expLimit)) { - // There is still a chance that the exponent will be safe to - // use: if it would eventually decrease due to a negative - // decExp, and that number is below the limit. We check for - // that here. - if (!expOverflow && (expSign == 1 && decExp < 0) - && (expVal + decExp) < expLimit) { - // Cannot overflow: adding a positive and negative number. - decExp += expVal; - } else { - // - // The intent here is to end up with - // infinity or zero, as appropriate. - // The reason for yielding such a small decExponent, - // rather than something intuitive such as - // expSign*Integer.MAX_VALUE, is that this value - // is subject to further manipulation in - // doubleValue() and floatValue(), and I don't want - // it to be able to cause overflow there! - // (The only way we can get into trouble here is for - // really outrageous nDigits+nTrailZero, such as 2 - // billion.) - // - decExp = expSign * expLimit; - } - } else { - // this should not overflow, since we tested - // for expVal > (MAX+N), where N >= abs(decExp) - decExp = decExp + expSign*expVal; - } + int pt = 0; // index after point, 0 iff absent + int start = i; // index of start of the significand, excluding opt sign - // if we saw something not a digit ( or end of string ) - // after the [Ee][+-], without seeing any digits at all - // this is certainly an error. If we saw some digits, - // but then some trailing garbage, that might be ok. - // so we just fall through in that case. - // HUMBUG - if ( i == expAt ) { - break parseNumber; // certainly bad - } + /* Skip opt leading zeros, including an opt point. */ + while (i < len && ((ch = in.charAt(i)) == '0' || ch == '.')) { + ++i; + if (ch == '.') { + pt = checkMultiplePoints(pt, i); } - // - // We parsed everything we could. - // If there are leftovers, then this is not good input! - // - if ( i < len && - ((i != len - 1) || - (in.charAt(i) != 'f' && - in.charAt(i) != 'F' && - in.charAt(i) != 'd' && - in.charAt(i) != 'D'))) { - break parseNumber; // go throw exception + } + int lz = i; // index after leading group of zeros or point + + /* + * Scan all remaining chars of the significand, including an opt point. + * Also locate the index after the end of the trailing group of non-zeros + * inside this range of the input. + */ + int tnz = 0; // index after trailing group of non-zeros, 0 iff absent + while (i < len && (isDigit(ch = in.charAt(i), isDec) || ch == '.')) { + i++; + if (ch == '.') { + pt = checkMultiplePoints(pt, i); + } else if (ch != '0') { + tnz = i; } - if(isZero) { - return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO; + } + check(in, i - start > (pt != 0 ? 1 : 0)); // must have at least one digit + int stop = i; // index after the significand + + /* Scan exponent part, optional for dec, mandatory for hex. */ + long ep = 0; // exponent, implicitly 0 + boolean hasExp = false; + if (i < len && ((ch = in.charAt(i) | 0b10_0000) == 'e' && isDec + || ch == 'p' && !isDec)) { + ++i; + + /* Scan opt exponent sign. */ + int esign = ' '; // esign == ' ' iff the sign is implicit + if (i < len && ((ch = in.charAt(i)) == '-' || ch == '+')) { + esign = ch; + ++i; } - return new ASCIIToBinaryBuffer(isNegative, decExp, digits, nDigits); - } catch ( StringIndexOutOfBoundsException e ){ } - throw new NumberFormatException("For input string: \"" + in + "\""); - } - private static class HexFloatPattern { - /** - * Grammar is compatible with hexadecimal floating-point constants - * described in section 6.4.4.2 of the C99 specification. + /* Scan the exponent digits. Accumulate in ep, clamping at 10^10. */ + while (i < len && isDigit(ch = in.charAt(i), true)) { // ep is decimal + ++i; + ep = appendDecDigit(ep, ch); + } + check(in, i - stop >= 3 // at least 3 chars after significand + || i - stop == 2 && esign == ' '); // 2 chars, one is digit + if (esign == '-') { + ep = -ep; + } + hasExp = true; + } + /* + * |ep| < 10^10, or |ep| = 10^10 when considered "large". + * A "large" ep either generates a zero or an infinity. */ - private static final Pattern VALUE = Pattern.compile( - //1 234 56 7 8 9 - "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?" - ); - } + check(in, isDec | hasExp); - /** - * Converts string s to a suitable floating decimal; uses the - * double constructor and sets the roundDir variable appropriately - * in case the value is later converted to a float. - * - * @param s The String to parse. - */ - static ASCIIToBinaryConverter parseHexString(String s) { - // Verify string is a member of the hexadecimal floating-point - // string language. - Matcher m = HexFloatPattern.VALUE.matcher(s); - boolean validInput = m.matches(); - if (!validInput) { - // Input does not match pattern - throw new NumberFormatException("For input string: \"" + s + "\""); - } else { // validInput - // - // We must isolate the sign, significand, and exponent - // fields. The sign value is straightforward. Since - // floating-point numbers are stored with a normalized - // representation, the significand and exponent are - // interrelated. - // - // After extracting the sign, we normalized the - // significand as a hexadecimal value, calculating an - // exponent adjust for any shifts made during - // normalization. If the significand is zero, the - // exponent doesn't need to be examined since the output - // will be zero. - // - // Next the exponent in the input string is extracted. - // Afterwards, the significand is normalized as a *binary* - // value and the input value's normalized exponent can be - // computed. The significand bits are copied into a - // double significand; if the string has more logical bits - // than can fit in a double, the extra bits affect the - // round and sticky bits which are used to round the final - // value. - // - // Extract significand sign - String group1 = m.group(1); - boolean isNegative = ((group1 != null) && group1.equals("-")); - - // Extract Significand magnitude - // - // Based on the form of the significand, calculate how the - // binary exponent needs to be adjusted to create a - // normalized//hexadecimal* floating-point number; that - // is, a number where there is one nonzero hex digit to - // the left of the (hexa)decimal point. Since we are - // adjusting a binary, not hexadecimal exponent, the - // exponent is adjusted by a multiple of 4. - // - // There are a number of significand scenarios to consider; - // letters are used in indicate nonzero digits: - // - // 1. 000xxxx => x.xxx normalized - // increase exponent by (number of x's - 1)*4 - // - // 2. 000xxx.yyyy => x.xxyyyy normalized - // increase exponent by (number of x's - 1)*4 - // - // 3. .000yyy => y.yy normalized - // decrease exponent by (number of zeros + 1)*4 - // - // 4. 000.00000yyy => y.yy normalized - // decrease exponent by (number of zeros to right of point + 1)*4 - // - // If the significand is exactly zero, return a properly - // signed zero. - // - - String significandString; - int signifLength; - int exponentAdjust; - { - int leftDigits = 0; // number of meaningful digits to - // left of "decimal" point - // (leading zeros stripped) - int rightDigits = 0; // number of digits to right of - // "decimal" point; leading zeros - // must always be accounted for - // - // The significand is made up of either - // - // 1. group 4 entirely (integer portion only) - // - // OR - // - // 2. the fractional portion from group 7 plus any - // (optional) integer portions from group 6. - // - String group4; - if ((group4 = m.group(4)) != null) { // Integer-only significand - // Leading zeros never matter on the integer portion - significandString = stripLeadingZeros(group4); - leftDigits = significandString.length(); - } else { - // Group 6 is the optional integer; leading zeros - // never matter on the integer portion - String group6 = stripLeadingZeros(m.group(6)); - leftDigits = group6.length(); - - // fraction - String group7 = m.group(7); - rightDigits = group7.length(); - - // Turn "integer.fraction" into "integer"+"fraction" - significandString = - ((group6 == null) ? "" : group6) + // is the null - // check necessary? - group7; - } - - significandString = stripLeadingZeros(significandString); - signifLength = significandString.length(); + /* Skip opt [FfDd]? suffix. */ + if (i < len && (((ch = in.charAt(i) | 0b10_0000)) == 'f' || ch == 'd')) { + ++i; + } - // - // Adjust exponent as described above - // - if (leftDigits >= 1) { // Cases 1 and 2 - exponentAdjust = 4 * (leftDigits - 1); - } else { // Cases 3 and 4 - exponentAdjust = -4 * (rightDigits - signifLength + 1); - } + /* Skip optional trailing whitespaces, then must be at the end of input. */ + check(in, skipWhitespaces(in, i) == len); - // If the significand is zero, the exponent doesn't - // matter; return a properly signed zero. + /* By now, the input is syntactically correct. */ + if (tnz == 0) { // all zero digits, so ignore ep and point + return ssign != '-' ? A2BC_POSITIVE_ZERO : A2BC_NEGATIVE_ZERO; + } - if (signifLength == 0) { // Only zeros in input - return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO; - } - } + /* + * Virtually adjust the point position to be just after + * the last non-zero digit by adjusting the exponent accordingly + * (without modifying the physical pt, as it is used later on). + * + * Determine the count of digits, excluding leading and trailing zeros. + * + * These are the possible situations: + * |lz |tnz |stop + * 00000000123456000000234567000000000 + * + * |pt |lz |tnz |stop + * .00000000123456000000234567000000000 + * + * |pt |lz |tnz |stop + * 00.000000123456000000234567000000000 + * + * |pt=lz |tnz |stop + * 00000000.123456000000234567000000000 + * + * |lz |pt |tnz |stop + * 000000001234.56000000234567000000000 + * + * |lz |pt |tnz |stop + * 0000000012345600.0000234567000000000 + * + * |lz |pt |tnz |stop + * 00000000123456000000.234567000000000 + * + * |lz |pt |tnz |stop + * 0000000012345600000023.4567000000000 + * + * |lz |pt=tnz |stop + * 00000000123456000000234567.000000000 + * + * |lz |tnz |pt |stop + * 0000000012345600000023456700000.0000 + * + * |lz |tnz |pt=stop + * 00000000123456000000234567000000000. + * + * In decimal, moving the point by one position means correcting ep by 1. + * In hexadecimal, it means correcting ep by 4. + */ + long emult = isDec ? 1L : 4L; + int n = tnz - lz; // number of significant digits, 1st approximation + if (pt == 0) { + ep += emult * (stop - tnz); + } else { + ep += emult * (pt - tnz); + if (pt > tnz) { // '.' was counted as a position, adjust ep + ep -= emult; + } else if (lz < pt) { // lz < pt <= tnz + n -= 1; + } + } + /* + * n = number of significant digits (that is, not counting leading nor + * trailing zeros) + * |ep| < 10^11 + * + * The magnitude x of the input meets + * x = f 10^ep (decimal) + * x = f 2^ep (hexadecimal) + * Integer f = consists of the n decimal or hexadecimal + * digits found in part [lz, tnz) of the input, and f_1 != 0, f_n != 0. + */ - // Extract Exponent - // - // Use an int to read in the exponent value; this should - // provide more than sufficient range for non-contrived - // inputs. If reading the exponent in as an int does - // overflow, examine the sign of the exponent and - // significand to determine what to do. - // - String group8 = m.group(8); - boolean positiveExponent = (group8 == null) || group8.equals("+"); - long unsignedRawExponent; - try { - unsignedRawExponent = Integer.parseInt(m.group(9)); + if (!isDec) { // hexadecimal conversion is performed entirely here + /* + * Rounding the leftmost P bits +1 rounding bit +1 sticky bit + * has the same outcome as rounding all bits. + * In terms of hex digits, we need room for HEX_COUNT of them. + */ + int j = 0; + i = lz; + long c = 0; + int le = Math.min(n, HEX_COUNT[ix]); + while (j < le) { + if ((ch = in.charAt(i++)) != '.') { + ++j; + c = c << 4 | digitFor(ch); } - catch (NumberFormatException e) { - // At this point, we know the exponent is - // syntactically well-formed as a sequence of - // digits. Therefore, if an NumberFormatException - // is thrown, it must be due to overflowing int's - // range. Also, at this point, we have already - // checked for a zero significand. Thus the signs - // of the exponent and significand determine the - // final result: - // - // significand - // + - - // exponent + +infinity -infinity - // - +0.0 -0.0 - return isNegative ? - (positiveExponent ? A2BC_NEGATIVE_INFINITY : A2BC_NEGATIVE_ZERO) - : (positiveExponent ? A2BC_POSITIVE_INFINITY : A2BC_POSITIVE_ZERO); + } + if (n > le) { + c |= 0b1; // force a sticky bit + ep += 4L * (n - le); + } + int bl = Long.SIZE - Long.numberOfLeadingZeros(c); // bit length + /* + * Let x = c 2^ep, so 2^(ep+bl-1) <= x < 2^(ep+bl) + * When ep + bl < Q_MIN then x certainly rounds to zero. + * When ep + bl - 1 > E_MAX then x surely rounds to infinity. + */ + if (ep < Q_MIN[ix] - bl) { + return buildZero(ix, ssign); + } + if (ep > E_MAX[ix] - bl + 1) { + return buildInfinity(ix, ssign); + } + int q = (int) ep; // narrowing conversion is safe + int shr; // (sh)ift to (r)ight iff shr > 0 + if (q > E_MIN[ix] - bl) { + shr = bl - P[ix]; + q += shr; + } else { + shr = Q_MIN[ix] - q; + q = Q_MIN[ix]; + } + if (shr > 0) { + long thr = 1L << shr; + long tail = (c & thr - 1) << 1; + c >>>= shr; + if (tail > thr || tail == thr && (c & 0b1) != 0) { + c += 1; + if (c >= 1L << P[ix]) { // but in fact it can't be > + c >>>= 1; + q += 1; + } } + } else { + c <<= -shr; + } - long rawExponent = - (positiveExponent ? 1L : -1L) * // exponent sign - unsignedRawExponent; // exponent magnitude - - // Calculate partially adjusted exponent - long exponent = rawExponent + exponentAdjust; + /* For now throw on BINARY_16_IX, until Float16 is integrated in java.base. */ + return switch (ix) { + case BINARY_32_IX -> + new PreparedASCIIToBinaryBuffer(Double.NaN, buildFloat(ssign, q, c)); + case BINARY_64_IX -> + new PreparedASCIIToBinaryBuffer(buildDouble(ssign, q, c), Float.NaN); + default -> throw new AssertionError("unexpected"); + }; + } - // Starting copying non-zero bits into proper position in - // a long; copy explicit bit too; this will be masked - // later for normal values. + /* + * For decimal inputs, we copy an appropriate prefix of the input and + * rely on another method to do the (sometimes intensive) math conversion. + * + * Define e' = n + ep, which leads to + * x = <0 . f_1 ... f_n> 10^e', 10^(e'-1) <= x < 10^e' + * If e' <= EP_MIN then x rounds to zero. + * Similarly, if e' >= EP_MAX then x rounds to infinity. + * (See the comments on the fields for their semantics.) + * We return immediately in these cases. + * Otherwise, e' fits in an int named e. + */ + int e = Math.clamp(ep + n, EP_MIN[ix], EP_MAX[ix]); + if (e == EP_MIN[ix]) { // e' <= E_MIN + return ssign != '-' ? A2BC_POSITIVE_ZERO : A2BC_NEGATIVE_ZERO; + } + if (e == EP_MAX[ix]) { // e' >= E_MAX + return ssign != '-' ? A2BC_POSITIVE_INFINITY : A2BC_NEGATIVE_INFINITY; + } - boolean round = false; - boolean sticky = false; - int nextShift; - long significand = 0L; - // First iteration is different, since we only copy - // from the leading significand bit; one more exponent - // adjust will be needed... + /* + * For further considerations, x also needs to be seen as + * x = beta 2^q + * with real beta and integer q meeting + * 2^(P-1) <= beta < 2^P and q >= Q_MIN + * 0 < beta < 2^(P-1) and q = Q_MIN + * The (unique) solution is + * q = max(floor(log2(x)) - (P-1), Q_MIN), beta = x 2^(-q) + * It's usually costly to determine q as here. + * However, estimates to q are cheaper and quick to compute. + * + * Indeed, it's a matter of some simple maths to show that, by defining + * ql = max(floor((e-1) log2(10)) - (P-1), Q_MIN) + * qh = max(floor(e log2(10)) - (P-1), Q_MIN) + * then the following hold + * ql <= q <= qh, and qh - ql <= 4 + * Since by now e is relatively small, we can leverage flog2pow10(). + * + * When q >= Q_MIN, consider the interval [ 2^(P-1+q), 2^(P+q) ). + * It contains all floating-point values of the form + * c 2^q, c integer, 2^(P-1) <= c < 2^P (normal values) + * When q = Q_MIN also consider the interval [0, 2^(P-1+q) ) + * which contains all floating-point values of the form + * c 2^q, c integer, 0 <= c < 2^(P-1) (subnormal values and zero) + * For these c values, all numbers of the form + * (c + 1/2) 2^q + * also belong to the intervals. + * These are the boundaries of the rounding intervals and are key for + * correct rounding. + * + * First assume ql > 0, so q > 0. + * All rounding boundaries (c + 1/2) 2^q are integers. + * Hence, to correctly round x, it's enough to retain its integer part, + * +1 non-zero sticky digit iff the fractional part is non-zero. + * (Well, the sticky digit is only needed when the integer part + * coincides with a boundary, but that's hard to detect at this stage. + * Adding the sticky digit is always safe.) + * If n > e we pass the digits (3 is as good as any other + * non-zero sticky digit) and the exponent e to the conversion routine. + * If n <= e we pass all the digits (no sticky digit, + * as the fractional part is empty) and the exponent e to the converter. + * + * Now assume qh <= 0, so q <= 0. + * The boundaries (c + 1/2) 2^q = (2c + 1) 2^(q-1) have a fractional part + * of 1 - q digits: some (or zero) leading zeros, the rightmost is 5. + * A correct rounding needs to retain the integer part of x (if any), + * 1 - q digits of the fractional part, +1 non-zero sticky digit iff + * the rest of the fractional part beyond the 1 - q digits is non-zero. + * (Again, the sticky digit is only needed when the digit in f at the + * same position as the last 5 of the rounding boundary is 5 as well. + * But let's keep it simple for now.) + * However, q is unknown, so use the conservative ql instead. + * More precisely, if n > e + 1 - ql we pass the leftmost e + 1 - ql + * digits of f, sticky 3, and e. + * Otherwise, n <= e + 1 - ql. + * We pass all n digits of f, no sticky digit, and e to the converter. + * + * Otherwise, ql <= 0 < qh, so -4 < q <= 4. + * Again, since q is not known exactly, we proceed as in the previous + * case, with ql as a safe replacement for q. + */ + int ql = Math.max(MathUtils.flog2pow10(e - 1) - (P[ix] - 1), Q_MIN[ix]); + int np = e + Math.max(2 - ql, 1); + byte[] digits = new byte[Math.min(n, np)]; + if (n >= np) { + copyDigits(in, digits, np - 1, lz); + digits[np - 1] = '3'; // append any non-zero sticky digit + } else { + copyDigits(in, digits, n, lz); + } + return new ASCIIToBinaryBuffer(ssign == '-', e, digits, digits.length); + } - // IMPORTANT: make leadingDigit a long to avoid - // surprising shift semantics! - long leadingDigit = getHexDigit(significandString, 0); + private static PreparedASCIIToBinaryBuffer buildZero(int ix, int ssign) { + /* For now throw on BINARY_16_IX, until Float16 is integrated in java.base. */ + return switch (ix) { + case BINARY_32_IX -> + new PreparedASCIIToBinaryBuffer( + Double.NaN, + ssign != '-' ? 0.0f : -0.0f); + case BINARY_64_IX -> + new PreparedASCIIToBinaryBuffer( + ssign != '-' ? 0.0d : -0.0d, + Float.NaN); + default -> throw new AssertionError("unexpected"); + }; + } - // - // Left shift the leading digit (53 - (bit position of - // leading 1 in digit)); this sets the top bit of the - // significand to 1. The nextShift value is adjusted - // to take into account the number of bit positions of - // the leadingDigit actually used. Finally, the - // exponent is adjusted to normalize the significand - // as a binary value, not just a hex value. - // - if (leadingDigit == 1) { - significand |= leadingDigit << 52; - nextShift = 52 - 4; - // exponent += 0 - } else if (leadingDigit <= 3) { // [2, 3] - significand |= leadingDigit << 51; - nextShift = 52 - 5; - exponent += 1; - } else if (leadingDigit <= 7) { // [4, 7] - significand |= leadingDigit << 50; - nextShift = 52 - 6; - exponent += 2; - } else if (leadingDigit <= 15) { // [8, f] - significand |= leadingDigit << 49; - nextShift = 52 - 7; - exponent += 3; - } else { - throw new AssertionError("Result from digit conversion too large!"); - } - // The preceding if-else could be replaced by a single - // code block based on the high-order bit set in - // leadingDigit. Given leadingOnePosition, + private static PreparedASCIIToBinaryBuffer buildInfinity(int ix, int ssign) { + /* For now throw on BINARY_16_IX, until Float16 is integrated in java.base. */ + return switch (ix) { + case BINARY_32_IX -> + new PreparedASCIIToBinaryBuffer( + Double.NaN, + ssign != '-' ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY); + case BINARY_64_IX -> + new PreparedASCIIToBinaryBuffer( + ssign != '-' ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY, + Float.NaN); + default -> throw new AssertionError("unexpected"); + }; + } - // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition); - // nextShift = 52 - (3 + leadingOnePosition); - // exponent += (leadingOnePosition-1); + private static double buildDouble(int ssign, int q, long c) { + long be = c < 1L << P[BINARY_64_IX] - 1 + ? 0 + : q + ((DoubleConsts.EXP_BIAS - 1) + P[BINARY_64_IX]); + long bits = (ssign != '-' ? 0L : 1L << Double.SIZE - 1) + | be << P[BINARY_64_IX] - 1 + | c & DoubleConsts.SIGNIF_BIT_MASK; + return Double.longBitsToDouble(bits); + } - // - // Now the exponent variable is equal to the normalized - // binary exponent. Code below will make representation - // adjustments if the exponent is incremented after - // rounding (includes overflows to infinity) or if the - // result is subnormal. - // + private static float buildFloat(int ssign, int q, long c) { + int be = c < 1L << P[BINARY_32_IX] - 1 + ? 0 + : q + ((FloatConsts.EXP_BIAS - 1) + P[BINARY_32_IX]); + int bits = (ssign != '-' ? 0 : 1 << Float.SIZE - 1) + | be << P[BINARY_32_IX] - 1 + | (int) c & FloatConsts.SIGNIF_BIT_MASK; + return Float.intBitsToFloat(bits); + } - // Copy digit into significand until the significand can't - // hold another full hex digit or there are no more input - // hex digits. - int i = 0; - for (i = 1; - i < signifLength && nextShift >= 0; - i++) { - long currentDigit = getHexDigit(significandString, i); - significand |= (currentDigit << nextShift); - nextShift -= 4; - } + private static void copyDigits(String in, byte[] digits, int len, int i) { + int ch; + int j = 0; + while (j < len) { + if ((ch = in.charAt(i++)) != '.') { + digits[j++] = (byte) ch; + } + } + } - // After the above loop, the bulk of the string is copied. - // Now, we must copy any partial hex digits into the - // significand AND compute the round bit and start computing - // sticky bit. - - if (i < signifLength) { // at least one hex input digit exists - long currentDigit = getHexDigit(significandString, i); - - // from nextShift, figure out how many bits need - // to be copied, if any - switch (nextShift) { // must be negative - case -1: - // three bits need to be copied in; can - // set round bit - significand |= ((currentDigit & 0xEL) >> 1); - round = (currentDigit & 0x1L) != 0L; - break; - - case -2: - // two bits need to be copied in; can - // set round and start sticky - significand |= ((currentDigit & 0xCL) >> 2); - round = (currentDigit & 0x2L) != 0L; - sticky = (currentDigit & 0x1L) != 0; - break; - - case -3: - // one bit needs to be copied in - significand |= ((currentDigit & 0x8L) >> 3); - // Now set round and start sticky, if possible - round = (currentDigit & 0x4L) != 0L; - sticky = (currentDigit & 0x3L) != 0; - break; - - case -4: - // all bits copied into significand; set - // round and start sticky - round = ((currentDigit & 0x8L) != 0); // is top bit set? - // nonzeros in three low order bits? - sticky = (currentDigit & 0x7L) != 0; - break; - - default: - throw new AssertionError("Unexpected shift distance remainder."); - // break; - } + /* Arithmetically "appends the dec digit" ch to v >= 0, clamping at 10^10. */ + private static long appendDecDigit(long v, int ch) { + return v < 10_000_000_000L / 10 ? 10 * v + (ch - '0') : 10_000_000_000L; + } - // Round is set; sticky might be set. + /* Whether ch is a digit char '0-9', 'A-F', or 'a-f', depending on isDec. */ + private static boolean isDigit(int ch, boolean isDec) { + int lch; // lowercase ch + return '0' <= ch && ch <= '9' || + !isDec && 'a' <= (lch = ch | 0b10_0000) && lch <= 'f'; + } - // For the sticky bit, it suffices to check the - // current digit and test for any nonzero digits in - // the remaining unprocessed input. - i++; - while (i < signifLength && !sticky) { - currentDigit = getHexDigit(significandString, i); - sticky = sticky || (currentDigit != 0); - i++; - } + /* Returns the numeric value of ch, assuming it is a hexdigit. */ + private static int digitFor(int ch) { + return ch <= '9' ? ch - '0' : (ch | 0b10_0000) - ('a' - 10); + } - } - // else all of string was seen, round and sticky are - // correct as false. - - // Float calculations - int floatBits = isNegative ? FloatConsts.SIGN_BIT_MASK : 0; - if (exponent >= Float.MIN_EXPONENT) { - if (exponent > Float.MAX_EXPONENT) { - // Float.POSITIVE_INFINITY - floatBits |= FloatConsts.EXP_BIT_MASK; - } else { - int threshShift = DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH - 1; - boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky; - int iValue = (int) (significand >>> threshShift); - if ((iValue & 3) != 1 || floatSticky) { - iValue++; - } - floatBits |= (((((int) exponent) + (FloatConsts.EXP_BIAS - 1))) << SINGLE_EXP_SHIFT) + (iValue >> 1); - } - } else { - if (exponent < FloatConsts.MIN_SUB_EXPONENT - 1) { - // 0 - } else { - // exponent == -127 ==> threshShift = 53 - 2 + (-149) - (-127) = 53 - 24 - int threshShift = (int) ((DoubleConsts.SIGNIFICAND_WIDTH - 2 + FloatConsts.MIN_SUB_EXPONENT) - exponent); - assert threshShift >= DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH; - assert threshShift < DoubleConsts.SIGNIFICAND_WIDTH; - boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky; - int iValue = (int) (significand >>> threshShift); - if ((iValue & 3) != 1 || floatSticky) { - iValue++; - } - floatBits |= iValue >> 1; - } - } - float fValue = Float.intBitsToFloat(floatBits); - - // Check for overflow and update exponent accordingly. - if (exponent > Double.MAX_EXPONENT) { // Infinite result - // overflow to properly signed infinity - return isNegative ? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY; - } else { // Finite return value - if (exponent <= Double.MAX_EXPONENT && // (Usually) normal result - exponent >= Double.MIN_EXPONENT) { - - // The result returned in this block cannot be a - // zero or subnormal; however after the - // significand is adjusted from rounding, we could - // still overflow in infinity. - - // AND exponent bits into significand; if the - // significand is incremented and overflows from - // rounding, this combination will update the - // exponent correctly, even in the case of - // Double.MAX_VALUE overflowing to infinity. - - significand = ((( exponent + - (long) DoubleConsts.EXP_BIAS) << - (DoubleConsts.SIGNIFICAND_WIDTH - 1)) - & DoubleConsts.EXP_BIT_MASK) | - (DoubleConsts.SIGNIF_BIT_MASK & significand); - - } else { // Subnormal or zero - // (exponent < Double.MIN_EXPONENT) - - if (exponent < (DoubleConsts.MIN_SUB_EXPONENT - 1)) { - // No way to round back to nonzero value - // regardless of significand if the exponent is - // less than -1075. - return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO; - } else { // -1075 <= exponent <= MIN_EXPONENT -1 = -1023 - // - // Find bit position to round to; recompute - // round and sticky bits, and shift - // significand right appropriately. - // - - sticky = sticky || round; - round = false; - - // Number of bits of significand to preserve is - // exponent - abs_min_exp +1 - // check: - // -1075 +1074 + 1 = 0 - // -1023 +1074 + 1 = 52 - - int bitsDiscarded = 53 - - ((int) exponent - DoubleConsts.MIN_SUB_EXPONENT + 1); - assert bitsDiscarded >= 1 && bitsDiscarded <= 53; - - // What to do here: - // First, isolate the new round bit - round = (significand & (1L << (bitsDiscarded - 1))) != 0L; - if (bitsDiscarded > 1) { - // create mask to update sticky bits; low - // order bitsDiscarded bits should be 1 - long mask = ~((~0L) << (bitsDiscarded - 1)); - sticky = sticky || ((significand & mask) != 0L); - } - - // Now, discard the bits - significand = significand >> bitsDiscarded; - - significand = ((((long) (Double.MIN_EXPONENT - 1) + // subnorm exp. - (long) DoubleConsts.EXP_BIAS) << - (DoubleConsts.SIGNIFICAND_WIDTH - 1)) - & DoubleConsts.EXP_BIT_MASK) | - (DoubleConsts.SIGNIF_BIT_MASK & significand); - } - } + /* + * Starting at i, skips all chars in ['\0', ' ']. + * Returns the index after the whitespaces. + */ + private static int skipWhitespaces(String in, int i) { + int len = in.length(); + for (; i < len && in.charAt(i) <= ' '; ++i); // empty body + return i; + } - // The significand variable now contains the currently - // appropriate exponent bits too. + /* + * Attempts to scan sub and optional trailing whitespaces, starting at index i. + * The optional whitespaces must be at the end of in. + */ + private static void scanSymbolic(String in, int i, String sub) { + int high = i + sub.length(); // might overflow, checked in next line + check(in, i <= high && high <= in.length() + && in.indexOf(sub, i, high) == i + && skipWhitespaces(in, high) == in.length()); + } - // - // Determine if significand should be incremented; - // making this determination depends on the least - // significant bit and the round and sticky bits. - // - // Round to nearest even rounding table, adapted from - // table 4.7 in "Computer Arithmetic" by IsraelKoren. - // The digit to the left of the "decimal" point is the - // least significant bit, the digits to the right of - // the point are the round and sticky bits - // - // Number Round(x) - // x0.00 x0. - // x0.01 x0. - // x0.10 x0. - // x0.11 x1. = x0. +1 - // x1.00 x1. - // x1.01 x1. - // x1.10 x1. + 1 - // x1.11 x1. + 1 - // - boolean leastZero = ((significand & 1L) == 0L); - if ((leastZero && round && sticky) || - ((!leastZero) && round)) { - significand++; - } + /* + * Returns i if this is the first time the scanner detects a point. + * Throws otherwise. + */ + private static int checkMultiplePoints(int pt, int i) { + if (pt != 0) { + throw new NumberFormatException("multiple points"); + } + return i; + } - double value = isNegative ? - Double.longBitsToDouble(significand | DoubleConsts.SIGN_BIT_MASK) : - Double.longBitsToDouble(significand ); + private static final int MAX_OUT = 1_000; + private static final String OMITTED = " ... "; + private static final int L_HALF = (MAX_OUT - OMITTED.length()) / 2; + private static final int R_HALF = MAX_OUT - (L_HALF + OMITTED.length()); - return new PreparedASCIIToBinaryBuffer(value, fValue); - } + private static void check(String in, boolean expected) { + if (!expected) { + int len = in.length(); + if (len > MAX_OUT) { // discard middle chars to achieve a length of MAX_OUT + in = in.substring(0, L_HALF) + OMITTED + in.substring(len - R_HALF); } + throw new NumberFormatException("For input string: \"" + in + "\""); + } } - /** - * Returns s with any leading zeros removed. + /* + * According to IEEE 754-2019, a finite positive binary floating-point + * of precision P is (uniquely) expressed as + * c 2^q + * where integers c and q meet + * Q_MIN <= q <= Q_MAX + * either 2^(P-1) <= c < 2^P (normal) + * or 0 < c < 2^(P-1) & q = Q_MIN (subnormal) + * c = , d_i in [0, 2) + * + * Equivalently, the fp value can be (uniquely) expressed as + * m 2^ep + * where integer ep and real f meet + * ep = q + P - 1 + * m = c 2^(1-P) + * Hence, + * E_MIN = Q_MIN + P - 1, E_MAX = Q_MAX + P - 1, + * 1 <= m < 2 (normal) + * m < 1 (subnormal) + * m = + * with a (binary) point between d_0 and d_1 */ - static String stripLeadingZeros(String s) { - if(!s.isEmpty() && s.charAt(0)=='0') { - for(int i=1; iposition - * of string s. + /* + * These constants are used to indicate the IEEE binary floating-point format + * as an index (ix) to some methods and static arrays in this class. */ - static int getHexDigit(String s, int position) { - int value = Character.digit(s.charAt(position), 16); - if (value <= -1 || value >= 16) { - throw new AssertionError("Unexpected failure of digit conversion of " + - s.charAt(position)); - } - return value; - } + private static final int BINARY_16_IX = 0; + private static final int BINARY_32_IX = 1; + private static final int BINARY_64_IX = 2; +// private static final int BINARY_128_IX = 3; +// private static final int BINARY_256_IX = 4; + + /* The precision of the format. */ + @Stable + private static final int[] P = { + 11, 24, 53, // 113, 237, + }; + + /* + * EP_MIN = max{e : 10^e <= MIN_VALUE/2}. + * Note that MIN_VALUE/2 is the 0 threshold. + * Less or equal values round to 0 when using roundTiesToEven. + * Equivalently, EP_MIN = floor(log10(2^(Q_MIN-1))). + */ + @Stable + private static final int[] EP_MIN = { + -8, -46, -324, // -4_966, -78_985, + }; + + /* + * EP_MAX = min{e : MAX_VALUE + ulp(MAX_VALUE)/2 <= 10^(e-1)}. + * Note that MAX_VALUE + ulp(MAX_VALUE)/2 is the infinity threshold. + * Greater or equal values round to infinity when using roundTiesToEven. + * Equivalently, EP_MAX = ceil(log10((2^P - 1/2) 2^Q_MAX)) + 1. + */ + @Stable + private static final int[] EP_MAX = { + 6, 40, 310, // 4_934, 78_915, + }; + + /* Exponent width. */ + @Stable + private static final int[] W = { + (1 << 4 + BINARY_16_IX) - P[BINARY_16_IX], + (1 << 4 + BINARY_32_IX) - P[BINARY_32_IX], + (1 << 4 + BINARY_64_IX) - P[BINARY_64_IX], +// (1 << 4 + BINARY_128_IX) - P[BINARY_128_IX], +// (1 << 4 + BINARY_256_IX) - P[BINARY_256_IX], + }; + + /* Maximum exponent in the m 2^e representation. */ + @Stable + private static final int[] E_MAX = { + (1 << W[BINARY_16_IX] - 1) - 1, + (1 << W[BINARY_32_IX] - 1) - 1, + (1 << W[BINARY_64_IX] - 1) - 1, +// (1 << W[BINARY_128_IX] - 1) - 1, +// (1 << W[BINARY_256_IX] - 1) - 1, + }; + + /* Minimum exponent in the m 2^e representation. */ + @Stable + private static final int[] E_MIN = { + 1 - E_MAX[BINARY_16_IX], + 1 - E_MAX[BINARY_32_IX], + 1 - E_MAX[BINARY_64_IX], +// 1 - E_MAX[BINARY_128_IX], +// 1 - E_MAX[BINARY_256_IX], + }; + + /* Minimum exponent in the c 2^q representation. */ + @Stable + private static final int[] Q_MIN = { + E_MIN[BINARY_16_IX] - (P[BINARY_16_IX] - 1), + E_MIN[BINARY_32_IX] - (P[BINARY_32_IX] - 1), + E_MIN[BINARY_64_IX] - (P[BINARY_64_IX] - 1), +// E_MIN[BINARY_128_IX] - (P[BINARY_128_IX] - 1), +// E_MIN[BINARY_256_IX] - (P[BINARY_256_IX] - 1), + }; + + /* + * The most significant P +1 rounding bit +1 sticky bit = P + 2 bits in a + * hexadecimal string need up to HEX_COUNT = floor(P/4) + 2 hex digits. + */ + @Stable + private static final int[] HEX_COUNT = { + P[BINARY_16_IX] / 4 + 2, + P[BINARY_32_IX] / 4 + 2, + P[BINARY_64_IX] / 4 + 2, +// P[BINARY_128_IX] / 4 + 2, +// P[BINARY_256_IX] / 4 + 2, + }; + } diff --git a/src/java.base/share/classes/jdk/internal/math/FormattedFPDecimal.java b/src/java.base/share/classes/jdk/internal/math/FormattedFPDecimal.java index ce9b2fc4eea..7bfe63d0507 100644 --- a/src/java.base/share/classes/jdk/internal/math/FormattedFPDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/FormattedFPDecimal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,8 +57,7 @@ private FormattedFPDecimal() { } public static FormattedFPDecimal valueOf(double v, int prec, char form) { - FormattedFPDecimal fd = new FormattedFPDecimal(); - DoubleToDecimal.split(v, fd); + FormattedFPDecimal fd = split(v); return switch (form) { case SCIENTIFIC -> fd.scientific(prec); case PLAIN -> fd.plain(prec); @@ -69,6 +68,74 @@ public static FormattedFPDecimal valueOf(double v, int prec, char form) { }; } + private static FormattedFPDecimal split(double v) { + FormattedFPDecimal fd = new FormattedFPDecimal(); + DoubleToDecimal.split(v, fd); + return fd; + } + + /** + * Returns a FormattedFPDecimal with the appropriate precision for + * {@link Double#toString(double)}. + * + * @see java.math.BigDecimal#valueOf(double) + */ + public static FormattedFPDecimal valueForDoubleToString(double v) { + final FormattedFPDecimal fd = split(v); + final int expR = fd.getExponentRounded(); + + // Adjust precision, following rules for Double.toString. There is + // always at least one digit and some cases require an extra one to + // force a digit after the decimal. No additional rounding is performed; + // no significant trailing digits are removed. + + final int targetPrec = + // No extra trailing digit needed + (-3 <= expR && expR < 0) ? 1 + + // Keep digits to left of decimal, plus leave a trailing zero + : (0 <= expR && expR < 7) ? expR + 2 : + + // Otherwise, require at least 2 digits, to include trailing + // digit when there is a single digit + 2; + + + long s = fd.f; + int prec = fd.n; + + if (prec < targetPrec) { + // Add zeros needed to reach target precision + final int addZeros = targetPrec - prec; + s *= MathUtils.pow10(addZeros); // addZeros will be at most 8 + prec = targetPrec; + } else { + // Remove trailing zeros to try to reach target precision + while (prec > targetPrec && s % 10 == 0) { + s = s / 10; + prec--; + } + } + + // Calculate new e based on updated precision + final int eNew = expR - prec + 1; // expR is defined as prec + e - 1 + fd.set(s, eNew, prec); + + return fd; + } + + public long getSignificand() { + return f; + } + + public int getPrecision() { + return n; + } + + public int getExp() { + return e; + } + public void set(long f, int e, int n) { /* Initially, n = 0 if f = 0, and 10^{n-1} <= f < 10^n if f != 0 */ this.f = f; diff --git a/src/java.base/share/classes/jdk/internal/math/ToDecimal.java b/src/java.base/share/classes/jdk/internal/math/ToDecimal.java index 45d4da25323..22f9e5a338d 100644 --- a/src/java.base/share/classes/jdk/internal/math/ToDecimal.java +++ b/src/java.base/share/classes/jdk/internal/math/ToDecimal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, Alibaba Group Holding Limited. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -58,7 +58,7 @@ final int putChar(byte[] str, int index, int c) { if (latin1) { str[index] = (byte) c; } else { - JLA.putCharUTF16(str, index, (char) c); + JLA.uncheckedPutCharUTF16(str, index, (char) c); } return index + 1; } @@ -93,7 +93,7 @@ private static void put8DigitsUTF16(byte[] str, int index, int m) { int y = y(m); for (int i = 0; i < 8; ++i) { int t = 10 * y; - JLA.putCharUTF16(str, index + i, '0' + (t >>> 28)); + JLA.uncheckedPutCharUTF16(str, index + i, '0' + (t >>> 28)); y = t & MASK_28; } } @@ -122,11 +122,11 @@ final int removeTrailingZeroes(byte[] str, int index) { ++index; } } else { - while (JLA.getUTF16Char(str, index - 1) == '0') { + while (JLA.uncheckedGetUTF16Char(str, index - 1) == '0') { --index; } /* ... but do not remove the one directly to the right of '.' */ - if (JLA.getUTF16Char(str, index - 1) == '.') { + if (JLA.uncheckedGetUTF16Char(str, index - 1) == '.') { ++index; } } 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 f070738e0c7..72b8479de9a 100644 --- a/src/java.base/share/classes/jdk/internal/misc/CDS.java +++ b/src/java.base/share/classes/jdk/internal/misc/CDS.java @@ -31,15 +31,15 @@ import java.io.InputStream; import java.io.IOException; import java.io.PrintStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.file.InvalidPathException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.jar.JarFile; import java.util.stream.Stream; import jdk.internal.access.SharedSecrets; @@ -82,9 +82,36 @@ public static boolean isDumpingStaticArchive() { return (configStatus & IS_DUMPING_STATIC_ARCHIVE) != 0; } + public static boolean isSingleThreadVM() { + return isDumpingStaticArchive(); + } + private static native int getCDSConfigStatus(); private static native void logLambdaFormInvoker(String line); + + // Used only when dumping static archive to keep weak references alive to + // ensure that Soft/Weak Reference objects can be reliably archived. + private static ArrayList keepAliveList; + + public static void keepAlive(Object s) { + assert isSingleThreadVM(); // no need for synchronization + assert isDumpingStaticArchive(); + if (keepAliveList == null) { + keepAliveList = new ArrayList<>(); + } + keepAliveList.add(s); + } + + // This is called by native JVM code at the very end of Java execution before + // dumping the static archive. + // It collects the objects from keepAliveList so that they can be easily processed + // by the native JVM code to check that any Reference objects that need special + // clean up must have been registed with keepAlive() + private static Object[] getKeepAliveObjects() { + return keepAliveList.toArray(); + } + /** * Initialize archived static fields in the given Class using archived * values from CDS dump time. Also initialize the classes of objects in @@ -372,105 +399,154 @@ public static boolean needsClassInitBarrier(Class c) { * be loaded by custom class loaders during runtime. * See src/hotspot/share/cds/unregisteredClasses.cpp. */ - private static class UnregisteredClassLoader extends URLClassLoader { - private String currentClassName; - private Class currentSuperClass; - private Class[] currentInterfaces; + private static class UnregisteredClassLoader extends ClassLoader { + static { + registerAsParallelCapable(); + } - /** - * Used only by native code. Construct an UnregisteredClassLoader for loading - * unregistered classes from the specified file. If the file doesn't exist, - * the exception will be caughted by native code which will print a warning message and continue. - * - * @param fileName path of the the JAR file to load unregistered classes from. - */ - private UnregisteredClassLoader(String fileName) throws InvalidPathException, IOException { - super(toURLArray(fileName), /*parent*/null); - currentClassName = null; - currentSuperClass = null; - currentInterfaces = null; + static interface Source { + public byte[] readClassFile(String className) throws IOException; } - private static URL[] toURLArray(String fileName) throws InvalidPathException, IOException { - if (!((new File(fileName)).exists())) { - throw new IOException("No such file: " + fileName); + static class JarSource implements Source { + private final JarFile jar; + + JarSource(File file) throws IOException { + jar = new JarFile(file); + } + + @Override + public byte[] readClassFile(String className) throws IOException { + final var entryName = className.replace('.', '/').concat(".class"); + final var entry = jar.getEntry(entryName); + if (entry == null) { + throw new IOException("No such entry: " + entryName + " in " + jar.getName()); + } + try (final var in = jar.getInputStream(entry)) { + return in.readAllBytes(); + } } - return new URL[] { - // Use an intermediate File object to construct a URI/URL without - // authority component as URLClassPath can't handle URLs with a UNC - // server name in the authority component. - Path.of(fileName).toRealPath().toFile().toURI().toURL() - }; } + static class DirSource implements Source { + private final String basePath; + + DirSource(File dir) { + assert dir.isDirectory(); + basePath = dir.toString(); + } + + @Override + public byte[] readClassFile(String className) throws IOException { + final var subPath = className.replace('.', File.separatorChar).concat(".class"); + final var fullPath = Path.of(basePath, subPath); + return Files.readAllBytes(fullPath); + } + } + + private final HashMap sources = new HashMap<>(); + + private Source resolveSource(String path) throws IOException { + Source source = sources.get(path); + if (source != null) { + return source; + } + + final var file = new File(path); + if (!file.exists()) { + throw new IOException("No such file: " + path); + } + if (file.isFile()) { + source = new JarSource(file); + } else if (file.isDirectory()) { + source = new DirSource(file); + } else { + throw new IOException("Not a normal file: " + path); + } + sources.put(path, source); + + return source; + } /** - * Load the class of the given /name from the JAR file that was given to - * the constructor of the current UnregisteredClassLoader instance. This class must be - * a direct subclass of superClass. This class must be declared to implement - * the specified interfaces. + * Load the class of the given name from the given source. + *

              + * All super classes and interfaces of the named class must have already been loaded: + * either defined by this class loader (unregistered ones) or loaded, possibly indirectly, + * by the system class loader (registered ones). *

              - * This method must be called in a single threaded context. It will never be recursed (thus - * the asserts) + * If the named class has a registered super class or interface named N there should be no + * unregistered class or interface named N loaded yet. * * @param name the name of the class to be loaded. - * @param superClass must not be null. The named class must have a super class. - * @param interfaces could be null if the named class does not implement any interfaces. + * @param source path to a directory or a JAR file from which the named class should be + * loaded. */ - private Class load(String name, Class superClass, Class[] interfaces) - throws ClassNotFoundException - { - assert currentClassName == null; - assert currentSuperClass == null; - assert currentInterfaces == null; - - try { - currentClassName = name; - currentSuperClass = superClass; - currentInterfaces = interfaces; - - return findClass(name); - } finally { - currentClassName = null; - currentSuperClass = null; - currentInterfaces = null; - } + private Class load(String name, String source) throws IOException { + final Source resolvedSource = resolveSource(source); + final byte[] bytes = resolvedSource.readClassFile(name); + // 'defineClass()' may cause loading of supertypes of this unregistered class by VM + // calling 'this.loadClass()'. + // + // For any supertype S named SN specified in the classlist the following is ensured by + // the CDS implementation: + // - if S is an unregistered class it must have already been defined by this class + // loader and thus will be found by 'this.findLoadedClass(SN)', + // - if S is not an unregistered class there should be no unregistered class named SN + // loaded yet so either S has previously been (indirectly) loaded by this class loader + // and thus it will be found when calling 'this.findLoadedClass(SN)' or it will be + // found when delegating to the system class loader, which must have already loaded S, + // by calling 'this.getParent().loadClass(SN, false)'. + // See the implementation of 'ClassLoader.loadClass()' for details. + // + // Therefore, we should resolve all supertypes to the expected ones as specified by the + // "super:" and "interfaces:" attributes in the classlist. This invariant is validated + // by the C++ function 'ClassListParser::load_class_from_source()'. + assert getParent() == getSystemClassLoader(); + return defineClass(name, bytes, 0, bytes.length); } + } - /** - * This method must be called from inside the load() method. The /name - * can be only: - *

                - *
              • the name parameter for load() - *
              • the name of the superClass parameter for load() - *
              • the name of one of the interfaces in interfaces parameter for load() - *
                  - * - * For all other cases, a ClassNotFoundException will be thrown. - */ - protected Class findClass(final String name) - throws ClassNotFoundException - { - Objects.requireNonNull(currentClassName); - Objects.requireNonNull(currentSuperClass); - - if (name.equals(currentClassName)) { - // Note: the following call will call back to this.findClass(name) to - // resolve the super types of the named class. - return super.findClass(name); - } - if (name.equals(currentSuperClass.getName())) { - return currentSuperClass; - } - if (currentInterfaces != null) { - for (Class c : currentInterfaces) { - if (name.equals(c.getName())) { - return c; + /** + * This class is used only by native JVM code to spawn a child JVM process to assemble + * the AOT cache. args[] are passed in the JAVA_TOOL_OPTIONS + * environment variable. + */ + private static class ProcessLauncher { + static int execWithJavaToolOptions(String javaLauncher, String args[]) throws IOException, InterruptedException { + ProcessBuilder pb = new ProcessBuilder().inheritIO().command(javaLauncher); + StringBuilder sb = new StringBuilder(); + + // Encode the args as described in + // https://docs.oracle.com/en/java/javase/24/docs/specs/jvmti.html#tooloptions + String prefix = ""; + for (String arg : args) { + sb.append(prefix); + + for (int i = 0; i < arg.length(); i++) { + char c = arg.charAt(i); + if (c == '"' || Character.isWhitespace(c)) { + sb.append('\''); + sb.append(c); + sb.append('\''); + } else if (c == '\'') { + sb.append('"'); + sb.append(c); + sb.append('"'); + } else { + sb.append(c); } } + + prefix = " "; } - throw new ClassNotFoundException(name); + Map env = pb.environment(); + env.put("JAVA_TOOL_OPTIONS", sb.toString()); + env.remove("_JAVA_OPTIONS"); + env.remove("CLASSPATH"); + Process process = pb.start(); + return process.waitFor(); } } } diff --git a/src/java.base/share/classes/jdk/internal/misc/CarrierThreadLocal.java b/src/java.base/share/classes/jdk/internal/misc/CarrierThreadLocal.java index b14ecaffa2e..9396521cad5 100644 --- a/src/java.base/share/classes/jdk/internal/misc/CarrierThreadLocal.java +++ b/src/java.base/share/classes/jdk/internal/misc/CarrierThreadLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,9 +49,5 @@ public void remove() { JLA.removeCarrierThreadLocal(this); } - public boolean isPresent() { - return JLA.isCarrierThreadLocalPresent(this); - } - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); } diff --git a/src/java.base/share/classes/jdk/internal/misc/MethodFinder.java b/src/java.base/share/classes/jdk/internal/misc/MethodFinder.java index 970cebe74ed..60895b8115a 100644 --- a/src/java.base/share/classes/jdk/internal/misc/MethodFinder.java +++ b/src/java.base/share/classes/jdk/internal/misc/MethodFinder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,6 @@ private MethodFinder() { *
                • have a single argument of type {@code String[]}, {@code String...} or no argument
                • *
                • have the return type of void
                • *
                • be public, protected or package private
                • - *
                • not be abstract
                • *
                * * The method returned would be used by a launcher to initiate the execution of an @@ -82,27 +81,28 @@ private MethodFinder() { * @jls 12.1.4 Invoke a main method */ public static Method findMainMethod(Class cls) { - boolean isPreview = PreviewFeatures.isEnabled(); - Method mainMethod = JLA.findMethod(cls, !isPreview, "main", String[].class); - - if (isPreview && mainMethod == null) { - mainMethod = JLA.findMethod(cls, false, "main"); - } + Method mainMethod = JLA.findMethod(cls, true, "main", String[].class); if (mainMethod == null) { - return null; + //if not public method, try to lookup a non-public one + mainMethod = JLA.findMethod(cls, false, "main", String[].class); } - int mods = mainMethod.getModifiers(); + if (mainMethod == null || !isValidMainMethod(mainMethod)) { + mainMethod = JLA.findMethod(cls, false, "main"); + } - if (Modifier.isAbstract(mods) || - mainMethod.getReturnType() != void.class || - (isPreview && Modifier.isPrivate(mods)) || - (!isPreview && !Modifier.isStatic(mods))) { + if (mainMethod == null || !isValidMainMethod(mainMethod)) { return null; } return mainMethod; } + private static boolean isValidMainMethod(Method mainMethodCandidate) { + return mainMethodCandidate.getReturnType() == void.class && + !Modifier.isPrivate(mainMethodCandidate.getModifiers()); + + } + } diff --git a/src/java.base/share/classes/jdk/internal/misc/TerminatingThreadLocal.java b/src/java.base/share/classes/jdk/internal/misc/TerminatingThreadLocal.java index eeb1a77e226..beee5b78d1a 100644 --- a/src/java.base/share/classes/jdk/internal/misc/TerminatingThreadLocal.java +++ b/src/java.base/share/classes/jdk/internal/misc/TerminatingThreadLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,10 +29,9 @@ import java.util.IdentityHashMap; /** - * A per-carrier-thread-local variable that is notified when a thread terminates and - * it has been initialized in the terminating carrier thread or a virtual thread - * that had the terminating carrier thread as its carrier thread (even if it was - * initialized with a null value). + * A platform thread-local variable that is notified when a platform thread terminates, + * and it has been initialized in the terminating thread (or a mounted virtual thread in + * the case of a carrier thread), and even if it was initialized with a null value. */ public class TerminatingThreadLocal extends CarrierThreadLocal { @@ -44,8 +43,8 @@ public void set(T value) { @Override public void remove() { - super.remove(); unregister(this); + super.remove(); } /** @@ -80,7 +79,9 @@ public static void threadTerminated() { * @param tl the ThreadLocal to register */ public static void register(TerminatingThreadLocal tl) { - REGISTRY.get().add(tl); + if (tl != REGISTRY) { + REGISTRY.get().add(tl); + } } /** @@ -93,11 +94,11 @@ private static void unregister(TerminatingThreadLocal tl) { } /** - * a per-carrier-thread registry of TerminatingThreadLocal(s) that have been registered - * but later not unregistered in a particular carrier-thread. + * A per-platform-thread registry of TerminatingThreadLocal(s). The registry is + * itself a TerminatingThreadLocal to keep it reachable until the thread terminates. */ - public static final CarrierThreadLocal>> REGISTRY = - new CarrierThreadLocal<>() { + public static final TerminatingThreadLocal>> REGISTRY = + new TerminatingThreadLocal<>() { @Override protected Collection> initialValue() { return Collections.newSetFromMap(new IdentityHashMap<>(4)); diff --git a/src/java.base/share/classes/jdk/internal/misc/ThreadFlock.java b/src/java.base/share/classes/jdk/internal/misc/ThreadFlock.java index 8bf38b79734..423ffa03d31 100644 --- a/src/java.base/share/classes/jdk/internal/misc/ThreadFlock.java +++ b/src/java.base/share/classes/jdk/internal/misc/ThreadFlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -272,15 +272,8 @@ public Thread start(Thread thread) { * Shutdown this flock so that no new threads can be started, existing threads * in the flock will continue to run. This method is a no-op if the flock is * already shutdown or closed. - * - *

                This method may only be invoked by the flock owner or threads {@linkplain - * #containsThread(Thread) contained} in the flock. - * - * @throws WrongThreadException if the current thread is not the owner or a thread - * contained in the flock */ public void shutdown() { - ensureOwnerOrContainsThread(); if (!shutdown) { shutdown = true; } @@ -370,12 +363,8 @@ public boolean awaitAll(Duration timeout) *

                If the owner is blocked in {@code awaitAll} then it will return immediately. * If the owner is not blocked in {@code awaitAll} then its next call to wait * will return immediately. The method does nothing when the flock is closed. - * - * @throws WrongThreadException if the current thread is not the owner or a thread - * contained in the flock */ public void wakeup() { - ensureOwnerOrContainsThread(); if (!getAndSetPermit(true) && Thread.currentThread() != owner()) { LockSupport.unpark(owner()); } diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index 0a9044178a4..45cddc9fb6f 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -141,9 +141,7 @@ public static ModuleFinder limitedFinder() { private static boolean canUseArchivedBootLayer() { return getProperty("jdk.module.upgrade.path") == null && getProperty("jdk.module.patch.0") == null && // --patch-module - getProperty("jdk.module.limitmods") == null && // --limit-modules - getProperty("jdk.module.addreads.0") == null && // --add-reads - getProperty("jdk.module.addopens.0") == null; // --add-opens + getProperty("jdk.module.limitmods") == null; // --limit-modules } /** @@ -452,7 +450,7 @@ private static ModuleLayer boot2() { // --add-reads, --add-exports/--add-opens addExtraReads(bootLayer); - boolean extraExportsOrOpens = addExtraExportsAndOpens(bootLayer); + addExtraExportsAndOpens(bootLayer); // add enable native access addEnableNativeAccess(bootLayer); @@ -722,15 +720,13 @@ private static void addExtraReads(ModuleLayer bootLayer) { * Process the --add-exports and --add-opens options to export/open * additional packages specified on the command-line. */ - private static boolean addExtraExportsAndOpens(ModuleLayer bootLayer) { - boolean extraExportsOrOpens = false; + private static void addExtraExportsAndOpens(ModuleLayer bootLayer) { // --add-exports String prefix = "jdk.module.addexports."; Map> extraExports = decode(prefix); if (!extraExports.isEmpty()) { addExtraExportsOrOpens(bootLayer, extraExports, false); - extraExportsOrOpens = true; } @@ -739,10 +735,8 @@ private static boolean addExtraExportsAndOpens(ModuleLayer bootLayer) { Map> extraOpens = decode(prefix); if (!extraOpens.isEmpty()) { addExtraExportsOrOpens(bootLayer, extraOpens, true); - extraExportsOrOpens = true; } - return extraExportsOrOpens; } private static void addExtraExportsOrOpens(ModuleLayer bootLayer, diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java b/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java index ff3ffada22a..ed97937e39a 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java @@ -408,24 +408,10 @@ private Builder readModuleAttribute(DataInput in, ConstantPool cpool, int major, throw invalidModuleDescriptor("The requires entry for java.base" + " has ACC_SYNTHETIC set"); } - // requires transitive java.base is illegal unless: - // - the major version is 53 (JDK 9), or: - // - the classfile is a preview classfile, or: - // - the module is deemed to be participating in preview - // (i.e. the module is a java.* module) - // requires static java.base is illegal unless: - // - the major version is 53 (JDK 9), or: - if (major >= 54 - && ((mods.contains(Requires.Modifier.TRANSITIVE) - && !isPreview - && !"java.se".equals(mn)) - || mods.contains(Requires.Modifier.STATIC))) { - String flagName; - if (mods.contains(Requires.Modifier.STATIC)) { - flagName = "ACC_STATIC_PHASE"; - } else { - flagName = "ACC_TRANSITIVE"; - } + // requires static java.base is illegal unless + // the major version is 53 (JDK 9) + if (major >= 54 && mods.contains(Requires.Modifier.STATIC)) { + String flagName = "ACC_STATIC_PHASE"; throw invalidModuleDescriptor("The requires entry for java.base" + " has " + flagName + " set"); } 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 20b390855c9..19be5e53798 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,15 +32,10 @@ import java.io.ObjectStreamField; import java.io.OptionalDataException; import java.io.Serializable; +import java.lang.classfile.ClassFile; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Proxy; +import java.lang.reflect.*; import java.util.Set; import jdk.internal.access.JavaLangReflectAccess; @@ -518,6 +513,31 @@ public final ObjectStreamField[] serialPersistentFields(Class cl) { } } + public final Set parseAccessFlags(int mask, AccessFlag.Location location, Class classFile) { + var cffv = classFileFormatVersion(classFile); + return cffv == null ? + AccessFlag.maskToAccessFlags(mask, location) : + AccessFlag.maskToAccessFlags(mask, location, cffv); + } + + private final ClassFileFormatVersion classFileFormatVersion(Class cl) { + int raw = SharedSecrets.getJavaLangAccess().classFileVersion(cl); + + int major = raw & 0xFFFF; + int minor = raw >>> Character.SIZE; + + assert VM.isSupportedClassFileVersion(major, minor) : major + "." + minor; + + if (major >= ClassFile.JAVA_12_VERSION) { + if (minor == 0) + return ClassFileFormatVersion.fromMajor(raw); + return null; // preview or old preview, fallback to default handling + } else if (major == ClassFile.JAVA_1_VERSION) { + return minor < 3 ? ClassFileFormatVersion.RELEASE_0 : ClassFileFormatVersion.RELEASE_1; + } + return ClassFileFormatVersion.fromMajor(major); + } + //-------------------------------------------------------------------------- // // Internals only below this point diff --git a/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java b/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java index 1a56c3c64fd..de7a5e44b91 100644 --- a/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java +++ b/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java @@ -298,7 +298,7 @@ public static int hashCodeOfUnsigned(byte[] a, int fromIndex, int length, int in public static int hashCodeOfUTF16(byte[] a, int fromIndex, int length, int initialValue) { return switch (length) { case 0 -> initialValue; - case 1 -> 31 * initialValue + JLA.getUTF16Char(a, fromIndex); + case 1 -> 31 * initialValue + JLA.uncheckedGetUTF16Char(a, fromIndex); default -> vectorizedHashCode(a, fromIndex, length, initialValue, T_CHAR); }; } @@ -420,7 +420,7 @@ private static int hashCode(int result, int[] a, int fromIndex, int length) { private static int utf16hashCode(int result, byte[] value, int fromIndex, int length) { int end = fromIndex + length; for (int i = fromIndex; i < end; i++) { - result = 31 * result + JLA.getUTF16Char(value, i); + result = 31 * result + JLA.uncheckedGetUTF16Char(value, i); } return result; } diff --git a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java index d3df46dcd3c..6c0c745651e 100644 --- a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java +++ b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java @@ -143,14 +143,15 @@ public static int stringSize(long x) { * values, to cover the Integer.MIN_VALUE case. Converting otherwise * (negative to positive) will expose -Integer.MIN_VALUE that overflows * integer. + *

                + * WARNING: This method does not perform any bound checks. * * @param i value to convert * @param index next index, after the least significant digit * @param buf target buffer, Latin1-encoded * @return index of the most significant digit or minus sign, if present */ - public static int getCharsLatin1(int i, int index, byte[] buf) { - // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. + public static int uncheckedGetCharsLatin1(int i, int index, byte[] buf) { int q; int charPos = index; @@ -163,20 +164,20 @@ public static int getCharsLatin1(int i, int index, byte[] buf) { while (i <= -100) { q = i / 100; charPos -= 2; - putPairLatin1(buf, charPos, (q * 100) - i); + uncheckedPutPairLatin1(buf, charPos, (q * 100) - i); i = q; } // We know there are at most two digits left at this point. if (i <= -10) { charPos -= 2; - putPairLatin1(buf, charPos, -i); + uncheckedPutPairLatin1(buf, charPos, -i); } else { - putCharLatin1(buf, --charPos, '0' - i); + uncheckedPutCharLatin1(buf, --charPos, '0' - i); } if (negative) { - putCharLatin1(buf, --charPos, '-'); + uncheckedPutCharLatin1(buf, --charPos, '-'); } return charPos; } @@ -193,14 +194,15 @@ public static int getCharsLatin1(int i, int index, byte[] buf) { * values, to cover the Long.MIN_VALUE case. Converting otherwise * (negative to positive) will expose -Long.MIN_VALUE that overflows * long. + *

                + * WARNING: This method does not perform any bound checks. * * @param i value to convert * @param index next index, after the least significant digit * @param buf target buffer, Latin1-encoded * @return index of the most significant digit or minus sign, if present */ - public static int getCharsLatin1(long i, int index, byte[] buf) { - // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. + public static int uncheckedGetCharsLatin1(long i, int index, byte[] buf) { long q; int charPos = index; @@ -213,7 +215,7 @@ public static int getCharsLatin1(long i, int index, byte[] buf) { while (i < Integer.MIN_VALUE) { q = i / 100; charPos -= 2; - putPairLatin1(buf, charPos, (int)((q * 100) - i)); + uncheckedPutPairLatin1(buf, charPos, (int)((q * 100) - i)); i = q; } @@ -223,36 +225,37 @@ public static int getCharsLatin1(long i, int index, byte[] buf) { while (i2 <= -100) { q2 = i2 / 100; charPos -= 2; - putPairLatin1(buf, charPos, (q2 * 100) - i2); + uncheckedPutPairLatin1(buf, charPos, (q2 * 100) - i2); i2 = q2; } // We know there are at most two digits left at this point. if (i2 <= -10) { charPos -= 2; - putPairLatin1(buf, charPos, -i2); + uncheckedPutPairLatin1(buf, charPos, -i2); } else { - putCharLatin1(buf, --charPos, '0' - i2); + uncheckedPutCharLatin1(buf, --charPos, '0' - i2); } if (negative) { - putCharLatin1(buf, --charPos, '-'); + uncheckedPutCharLatin1(buf, --charPos, '-'); } return charPos; } /** - * This is a variant of {@link DecimalDigits#getCharsLatin1(int, int, byte[])}, but for + * This is a variant of {@link DecimalDigits#uncheckedGetCharsLatin1(int, int, byte[])}, but for * UTF-16 coder. + *

                + * WARNING: This method does not perform any bound checks. * * @param i value to convert * @param index next index, after the least significant digit * @param buf target buffer, UTF16-coded. * @return index of the most significant digit or minus sign, if present */ - public static int getCharsUTF16(int i, int index, byte[] buf) { - // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. + public static int uncheckedGetCharsUTF16(int i, int index, byte[] buf) { int q; int charPos = index; @@ -265,36 +268,37 @@ public static int getCharsUTF16(int i, int index, byte[] buf) { while (i <= -100) { q = i / 100; charPos -= 2; - putPairUTF16(buf, charPos, (q * 100) - i); + uncheckedPutPairUTF16(buf, charPos, (q * 100) - i); i = q; } // We know there are at most two digits left at this point. if (i <= -10) { charPos -= 2; - putPairUTF16(buf, charPos, -i); + uncheckedPutPairUTF16(buf, charPos, -i); } else { - putCharUTF16(buf, --charPos, '0' - i); + uncheckedPutCharUTF16(buf, --charPos, '0' - i); } if (negative) { - putCharUTF16(buf, --charPos, '-'); + uncheckedPutCharUTF16(buf, --charPos, '-'); } return charPos; } /** - * This is a variant of {@link DecimalDigits#getCharsLatin1(long, int, byte[])}, but for + * This is a variant of {@link DecimalDigits#uncheckedGetCharsLatin1(long, int, byte[])}, but for * UTF-16 coder. + *

                + * WARNING: This method does not perform any bound checks. * * @param i value to convert * @param index next index, after the least significant digit * @param buf target buffer, UTF16-coded. * @return index of the most significant digit or minus sign, if present */ - public static int getCharsUTF16(long i, int index, byte[] buf) { - // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. + public static int uncheckedGetCharsUTF16(long i, int index, byte[] buf) { long q; int charPos = index; @@ -307,7 +311,7 @@ public static int getCharsUTF16(long i, int index, byte[] buf) { while (i < Integer.MIN_VALUE) { q = i / 100; charPos -= 2; - putPairUTF16(buf, charPos, (int)((q * 100) - i)); + uncheckedPutPairUTF16(buf, charPos, (int)((q * 100) - i)); i = q; } @@ -317,26 +321,26 @@ public static int getCharsUTF16(long i, int index, byte[] buf) { while (i2 <= -100) { q2 = i2 / 100; charPos -= 2; - putPairUTF16(buf, charPos, (q2 * 100) - i2); + uncheckedPutPairUTF16(buf, charPos, (q2 * 100) - i2); i2 = q2; } // We know there are at most two digits left at this point. if (i2 <= -10) { charPos -= 2; - putPairUTF16(buf, charPos, -i2); + uncheckedPutPairUTF16(buf, charPos, -i2); } else { - putCharUTF16(buf, --charPos, '0' - i2); + uncheckedPutCharUTF16(buf, --charPos, '0' - i2); } if (negative) { - putCharUTF16(buf, --charPos, '-'); + uncheckedPutCharUTF16(buf, --charPos, '-'); } return charPos; } /** - * This is a variant of {@link DecimalDigits#getCharsUTF16(long, int, byte[])}, but for + * This is a variant of {@link DecimalDigits#uncheckedGetCharsUTF16(long, int, byte[])}, but for * UTF-16 coder. * * @param i value to convert @@ -345,7 +349,6 @@ public static int getCharsUTF16(long i, int index, byte[] buf) { * @return index of the most significant digit or minus sign, if present */ public static int getChars(long i, int index, char[] buf) { - // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. long q; int charPos = index; @@ -402,34 +405,42 @@ public static void putPair(char[] buf, int charPos, int v) { /** * Insert the 2-bytes integer into the buf as 2 decimal digit ASCII bytes, * only least significant 16 bits of {@code v} are used. + *

                + * WARNING: This method does not perform any bound checks. + * * @param buf byte buffer to copy into * @param charPos insert point * @param v to convert */ - public static void putPairLatin1(byte[] buf, int charPos, int v) { + public static void uncheckedPutPairLatin1(byte[] buf, int charPos, int v) { int packed = DIGITS[v & 0x7f]; - putCharLatin1(buf, charPos, packed & 0xFF); - putCharLatin1(buf, charPos + 1, packed >> 8); + uncheckedPutCharLatin1(buf, charPos, packed & 0xFF); + uncheckedPutCharLatin1(buf, charPos + 1, packed >> 8); } /** * Insert the 2-chars integer into the buf as 2 decimal digit UTF16 bytes, * only least significant 16 bits of {@code v} are used. + *

                + * WARNING: This method does not perform any bound checks. + * * @param buf byte buffer to copy into * @param charPos insert point * @param v to convert */ - public static void putPairUTF16(byte[] buf, int charPos, int v) { + public static void uncheckedPutPairUTF16(byte[] buf, int charPos, int v) { int packed = DIGITS[v & 0x7f]; - putCharUTF16(buf, charPos, packed & 0xFF); - putCharUTF16(buf, charPos + 1, packed >> 8); + uncheckedPutCharUTF16(buf, charPos, packed & 0xFF); + uncheckedPutCharUTF16(buf, charPos + 1, packed >> 8); } - private static void putCharLatin1(byte[] buf, int charPos, int c) { + private static void uncheckedPutCharLatin1(byte[] buf, int charPos, int c) { + assert charPos >= 0 && charPos < buf.length; UNSAFE.putByte(buf, ARRAY_BYTE_BASE_OFFSET + charPos, (byte) c); } - private static void putCharUTF16(byte[] buf, int charPos, int c) { + private static void uncheckedPutCharUTF16(byte[] buf, int charPos, int c) { + assert charPos >= 0 && charPos < (buf.length >> 1); UNSAFE.putCharUnaligned(buf, ARRAY_BYTE_BASE_OFFSET + ((long) charPos << 1), (char) c); } } diff --git a/src/java.base/share/classes/jdk/internal/util/Exceptions.java b/src/java.base/share/classes/jdk/internal/util/Exceptions.java new file mode 100644 index 00000000000..eb4286cd1af --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/util/Exceptions.java @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.util; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import sun.security.util.SecurityProperties; +import jdk.internal.misc.VM; + +/** + * Contains static utility methods which can filter exception + * message strings for sensitive information. + * + * Code using this mechanism should use formatMsg() + * to generate a formatted (enhanced or restricted) string for exception + * messages. + * + * The methods above take variable numbers of SensitiveInfo objects + * as parameters which contain the text that may have to be filtered. + * + * The SensitiveInfo objects should be generated with one of the following: + * public static SensitiveInfo filterSocketInfo(String s) + * public static SensitiveInfo filterNonSocketInfo(String s) + * public static SensitiveInfo filterJarName(String name) + * public static SensitiveInfo filterUserName(String name) + */ +public final class Exceptions { + private Exceptions() {} + + private static volatile boolean enhancedSocketExceptionText; + private static volatile boolean enhancedNonSocketExceptionText; + private static volatile boolean enhancedUserExceptionText; + private static volatile boolean enhancedJarExceptionText; + private static volatile boolean initialized = false; + + /** + * Base class for generating exception messages that may + * contain sensitive information which in certain contexts + * needs to be filtered out, in case it gets revealed in + * unexpected places. Exception messages are either enhanced + * or restricted. Enhanced messages include sensitive information. + * Restricted messages don't. + * + * Sub-class for any new category that needs to be independently + * controlled. Consider using a unique value for the + * SecurityProperties.includedInExceptions(String value) mechanism + * Current values defined are "jar", "userInfo" + * "hostInfo", "hostInfoExclSocket". + * + * New code can also piggy back on existing categories + * + * A SensitiveInfo contains the following components + * all of which default to empty strings. + * + * prefix, the sensitive info itself, a suffix + * and a replacement string. + * + * The composeFilteredText(boolean enhance) method generates + * an enhanced string when enhance is true. + * This comprises (enhance == true) + * prefix + info + suffix + * When (enhance == false), then by default the output is: + * "" empty string + * However, if a replacement is set, then when enhance == false + * the output is the replacement string. + */ + public abstract static class SensitiveInfo { + String info, suffix, prefix, replacement; + boolean enhanced; + + SensitiveInfo(String info) { + this.info = info; + prefix = suffix = replacement = ""; + } + public SensitiveInfo prefixWith(String prefix) { + this.prefix = prefix; + return this; + } + public SensitiveInfo suffixWith(String suffix) { + this.suffix = suffix; + return this; + } + public SensitiveInfo replaceWith(String replacement) { + this.replacement = replacement; + return this; + } + + public boolean enhanced() { + return enhanced; + } + + /** + * Implementation should call composeFilteredText(boolean flag) + * where flag contains the boolean value of whether + * the category is enabled or not. + */ + public abstract String output(); + + protected String composeFilteredText(boolean enhance) { + if (enhance) { + this.enhanced = true; + return prefix + info + suffix; + } else { + return replacement; + } + } + } + + static final class SocketInfo extends SensitiveInfo { + public SocketInfo(String host) { + super(host); + } + @Override + public String output() { + setup(); + return super.composeFilteredText(enhancedSocketExceptionText); + } + } + + static final class NonSocketInfo extends SensitiveInfo { + public NonSocketInfo(String host) { + super(host); + } + @Override + public String output() { + setup(); + return super.composeFilteredText(enhancedNonSocketExceptionText); + } + } + + static final class JarInfo extends SensitiveInfo { + public JarInfo(String name) { + super(name); + } + @Override + public String output() { + setup(); + return super.composeFilteredText(enhancedJarExceptionText); + } + } + + static final class UserInfo extends SensitiveInfo { + public UserInfo(String host) { + super(host); + } + @Override + public String output() { + setup(); + return super.composeFilteredText(enhancedUserExceptionText); + } + } + + // remove leading, trailing and duplicated space characters + static String trim(String s) { + int len = s.length(); + if (len == 0) return s; + + StringBuilder sb = new StringBuilder(); + + // initial value deals with leading spaces + boolean inSpace = true; + for (int i=0; i 0 && sb.charAt(sblen - 1) == ' ') + sb.deleteCharAt(sblen - 1); + return sb.toString(); + } + + public static SensitiveInfo filterSocketInfo(String host) { + return new SocketInfo(host); + } + + public static SensitiveInfo filterNonSocketInfo(String host) { + return new NonSocketInfo(host); + } + + public static SensitiveInfo filterJarName(String name) { + return new JarInfo(name); + } + + public static SensitiveInfo filterUserName(String name) { + return new UserInfo(name); + } + + /** + * Transform each SensitiveInfo into a String argument which is passed + * to String.format(). This string is then trimmed. + */ + public static String formatMsg(String format, SensitiveInfo... infos) { + String[] args = new String[infos.length]; + + int i = 0; + + for (SensitiveInfo info : infos) { + args[i++] = info.output(); + } + return trim(String.format(format, (Object[])args)); + } + + /** + * Simplification of above. Equivalent to: + * formatMsg("%s", SensitiveInfo[1]); // ie with one arg + */ + public static String formatMsg(SensitiveInfo info) { + return trim(info.output()); + } + + public static void setup() { + if (initialized || !VM.isBooted()) + return; + enhancedSocketExceptionText = SecurityProperties.includedInExceptions("hostInfo"); + enhancedNonSocketExceptionText = SecurityProperties.includedInExceptions("hostInfoExclSocket") + | enhancedSocketExceptionText; + + enhancedUserExceptionText = SecurityProperties.includedInExceptions("userInfo"); + enhancedJarExceptionText = SecurityProperties.INCLUDE_JAR_NAME_IN_EXCEPTIONS; + initialized = true; + } + + public static boolean enhancedNonSocketExceptions() { + setup(); + return enhancedNonSocketExceptionText; + } + + public static boolean enhancedSocketExceptions() { + setup(); + return enhancedSocketExceptionText; + } + + /** + * The enhanced message text is the socket address appended to + * the original IOException message + */ + public static IOException ioException(IOException e, SocketAddress addr) { + setup(); + if (addr == null) { + return e; + } + if (!enhancedSocketExceptionText) { + return create(e, e.getMessage()); + } + if (addr instanceof UnixDomainSocketAddress) { + return ofUnixDomain(e, (UnixDomainSocketAddress)addr); + } else if (addr instanceof InetSocketAddress) { + return ofInet(e, (InetSocketAddress)addr); + } else { + return e; + } + } + + private static IOException ofInet(IOException e, InetSocketAddress addr) { + return create(e, String.join(": ", e.getMessage(), addr.toString())); + } + + private static IOException ofUnixDomain(IOException e, UnixDomainSocketAddress addr) { + String path = addr.getPath().toString(); + StringBuilder sb = new StringBuilder(); + sb.append(e.getMessage()); + sb.append(": "); + sb.append(path); + String enhancedMsg = sb.toString(); + return create(e, enhancedMsg); + } + + // return a new instance of the same type with the given detail + // msg, or if the type doesn't support detail msgs, return given + // instance. + private static T create(T e, String msg) { + try { + Class clazz = e.getClass(); + @SuppressWarnings("unchecked") + Constructor ctor = (Constructor)clazz.getConstructor(String.class); + T e1 = (ctor.newInstance(msg)); + e1.setStackTrace(e.getStackTrace()); + return e1; + } catch (Exception e0) { + // Some eg AsynchronousCloseException have no detail msg + return e; + } + } +} diff --git a/src/java.base/share/classes/jdk/internal/util/HexDigits.java b/src/java.base/share/classes/jdk/internal/util/HexDigits.java index c08db4f5b48..45b39704059 100644 --- a/src/java.base/share/classes/jdk/internal/util/HexDigits.java +++ b/src/java.base/share/classes/jdk/internal/util/HexDigits.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package jdk.internal.util; -import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.vm.annotation.Stable; @@ -36,8 +35,6 @@ * @since 21 */ public final class HexDigits { - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - /** * Each element of the array represents the ascii encoded * hex relative to its index, for example:

                @@ -112,86 +109,4 @@ public static short digitPair(int i, boolean ucase) { ? (short) (v - ((v & 0b0100_0000_0100_0000) >> 1)) : v; } - - /** - * Insert the unsigned 2-byte integer into the buffer as 4 hexadecimal digit ASCII bytes, - * only least significant 16 bits of {@code value} are used. - * @param buffer byte buffer to copy into - * @param index insert point - * @param value to convert - */ - public static void put4(byte[] buffer, int index, int value) { - // Prepare an int value so C2 generates a 4-byte write instead of two 2-byte writes - int v = (DIGITS[value & 0xff] << 16) | DIGITS[(value >> 8) & 0xff]; - buffer[index] = (byte) v; - buffer[index + 1] = (byte) (v >> 8); - buffer[index + 2] = (byte) (v >> 16); - buffer[index + 3] = (byte) (v >> 24); - } - - /** - * Insert digits for long value in buffer from high index to low index. - * - * @param value value to convert - * @param index insert point + 1 - * @param buffer byte buffer to copy into - * - * @return the last index used - */ - public static int getCharsLatin1(long value, int index, byte[] buffer) { - while ((value & ~0xFF) != 0) { - short pair = DIGITS[((int) value) & 0xFF]; - buffer[--index] = (byte)(pair >> 8); - buffer[--index] = (byte)(pair); - value >>>= 8; - } - - int digits = DIGITS[(int) (value & 0xFF)]; - buffer[--index] = (byte) (digits >> 8); - - if (0xF < value) { - buffer[--index] = (byte) (digits & 0xFF); - } - - return index; - } - - /** - * Insert digits for long value in buffer from high index to low index. - * - * @param value value to convert - * @param index insert point + 1 - * @param buffer byte buffer to copy into - * - * @return the last index used - */ - public static int getCharsUTF16(long value, int index, byte[] buffer) { - while ((value & ~0xFF) != 0) { - int pair = (int) DIGITS[((int) value) & 0xFF]; - JLA.putCharUTF16(buffer, --index, pair >> 8); - JLA.putCharUTF16(buffer, --index, pair & 0xFF); - value >>>= 8; - } - - int digits = DIGITS[(int) (value & 0xFF)]; - JLA.putCharUTF16(buffer, --index, (byte) (digits >> 8)); - - if (0xF < value) { - JLA.putCharUTF16(buffer, --index, (byte) (digits & 0xFF)); - } - - return index; - } - - /** - * Calculate the number of digits required to represent the long. - * - * @param value value to convert - * - * @return number of digits - */ - public static int stringSize(long value) { - return value == 0 ? 1 : - 67 - Long.numberOfLeadingZeros(value) >> 2; - } } diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java index 766aca20b21..150b9d752bb 100644 --- a/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java +++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeyMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ import java.util.stream.Stream; import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.CDS; /** * This class provides management of {@link Map maps} where it is desirable to @@ -336,6 +337,40 @@ public void removeStaleReferences() { } } + @SuppressWarnings("unchecked") + public void prepareForAOTCache() { + // We are running the AOT assembly phase. The JVM has a single Java thread, so + // we don't have any concurrent threads that may modify the map while we are + // iterating its keys. + // + // Also, the java.lang.ref.Reference$ReferenceHandler thread is not running, + // so even if the GC has put some of the keys on the pending ReferencePendingList, + // none of the keys would have been added to the stale queue yet. + assert CDS.isSingleThreadVM(); + + for (ReferenceKey key : map.keySet()) { + Object referent = key.get(); + if (referent == null) { + // We don't need this key anymore. Add to stale queue + ((Reference)key).enqueue(); + } else { + // Make sure the referent cannot be collected. Otherwise, when + // the referent is collected, the GC may push the key onto + // Universe::reference_pending_list() at an unpredictable time, + // making it difficult to correctly serialize the key's + // state into the CDS archive. + // + // See aotReferenceObjSupport.cpp for more info. + CDS.keepAlive(referent); + } + Reference.reachabilityFence(referent); + } + + // Remove all keys enqueued above + removeStaleReferences(); + } + + /** * Puts an entry where the key and the value are the same. Used for * interning values in a set. diff --git a/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java b/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java index 355af10aa7c..960b63b12d3 100644 --- a/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java +++ b/src/java.base/share/classes/jdk/internal/util/ReferencedKeySet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -193,4 +193,8 @@ public T intern(T e) { public T intern(T e, UnaryOperator interner) { return ReferencedKeyMap.intern(map, e, interner); } + + public void prepareForAOTCache() { + map.prepareForAOTCache(); + } } diff --git a/src/java.base/share/classes/jdk/internal/util/SystemProps.java b/src/java.base/share/classes/jdk/internal/util/SystemProps.java index 26110a1dab3..5760f04831e 100644 --- a/src/java.base/share/classes/jdk/internal/util/SystemProps.java +++ b/src/java.base/share/classes/jdk/internal/util/SystemProps.java @@ -88,9 +88,12 @@ public static Map initProperties() { put(props, "file.encoding", nativeEncoding); } - // "stdout/err.encoding", prepared for System.out/err. For compatibility - // purposes, substitute them with "sun.*" if they don't exist. If "sun.*" aren't - // available either, fall back to "native.encoding". + // Encoding properties for stdin, stdout, and stderr. For stdout and stderr, + // check "sun.stdout.encoding" and "sun.stderr.encoding" properties for backward + // compatibility reasons before falling back to the "native.encoding" property. + putIfAbsent(props, "stdin.encoding", + raw.propDefault(Raw._stdin_encoding_NDX)); + putIfAbsent(props, "stdin.encoding", nativeEncoding); putIfAbsent(props, "stdout.encoding", props.getOrDefault("sun.stdout.encoding", raw.propDefault(Raw._stdout_encoding_NDX))); putIfAbsent(props, "stdout.encoding", nativeEncoding); @@ -241,7 +244,8 @@ public static class Raw { @Native private static final int _socksProxyHost_NDX = 1 + _socksNonProxyHosts_NDX; @Native private static final int _socksProxyPort_NDX = 1 + _socksProxyHost_NDX; @Native private static final int _stderr_encoding_NDX = 1 + _socksProxyPort_NDX; - @Native private static final int _stdout_encoding_NDX = 1 + _stderr_encoding_NDX; + @Native private static final int _stdin_encoding_NDX = 1 + _stderr_encoding_NDX; + @Native private static final int _stdout_encoding_NDX = 1 + _stdin_encoding_NDX; @Native private static final int _sun_arch_abi_NDX = 1 + _stdout_encoding_NDX; @Native private static final int _sun_arch_data_model_NDX = 1 + _sun_arch_abi_NDX; @Native private static final int _sun_cpu_endian_NDX = 1 + _sun_arch_data_model_NDX; diff --git a/src/java.base/share/classes/jdk/internal/vm/ContinuationSupport.java b/src/java.base/share/classes/jdk/internal/vm/ContinuationSupport.java index 92d26b93d53..0a01987abcc 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ContinuationSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/ContinuationSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,5 +50,23 @@ public static void ensureSupported() { } } + /** + * Pins the current continuation if the VM has continuations support. + */ + public static void pinIfSupported() { + if (isSupported()) { + Continuation.pin(); + } + } + + /** + * Unpins the current continuation if the VM has continuations support. + */ + public static void unpinIfSupported() { + if (isSupported()) { + Continuation.unpin(); + } + } + private static native boolean isSupported0(); } diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadContainer.java b/src/java.base/share/classes/jdk/internal/vm/ThreadContainer.java index 98a6c28496a..e2e91d50ec1 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadContainer.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,24 +76,49 @@ public long threadCount() { public abstract Stream threads(); /** - * Invoked by Thread::start before the given Thread is started. + * Invoked by {@code add} to add a thread to this container before it starts. */ - public void onStart(Thread thread) { - // do nothing + protected void onStart(Thread thread) { } /** - * Invoked when a Thread terminates or starting it fails. - * - * For a platform thread, this method is invoked by the thread itself when it - * terminates. For a virtual thread, this method is invoked on its carrier - * after the virtual thread has terminated. - * - * If starting the Thread failed then this method is invoked on the thread - * that invoked onStart. + * Invoked by {@code remove} to remove a thread from this container when it + * terminates (or failed to start). */ - public void onExit(Thread thread) { - // do nothing + protected void onExit(Thread thread) { + } + + /** + * Adds a thread to this container. This method should be invoked before the + * thread executes. + */ + public final void add(Thread thread) { + // Prevent a virtual thread from being preempted as this could potentially + // deadlock when scheduled to continue and all carriers are blocked adding + // or removing virtual threads. + ContinuationSupport.pinIfSupported(); + try { + onStart(thread); + } finally { + ContinuationSupport.unpinIfSupported(); + } + } + + /** + * Remove a thread from this container. This method can be invoked by the thread + * itself as it terminates, or it can be invoked by another thread after the given + * thread has terminated (or failed to start). + */ + public final void remove(Thread thread) { + // Prevent a virtual thread from being preempted as this could potentially + // deadlock when scheduled to continue and all carriers are blocked adding + // or removing virtual threads. + ContinuationSupport.pinIfSupported(); + try { + onExit(thread); + } finally { + ContinuationSupport.unpinIfSupported(); + } } /** diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java index d0705bc2457..58729774f24 100644 --- a/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,11 +24,13 @@ */ package jdk.internal.vm; -import java.io.BufferedOutputStream; +import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.io.PrintStream; +import java.io.OutputStreamWriter; +import java.io.UncheckedIOException; +import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; @@ -36,15 +38,19 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.time.Instant; -import java.util.ArrayList; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Deque; import java.util.Iterator; import java.util.List; +import java.util.Objects; /** * Thread dump support. * - * This class defines methods to dump threads to an output stream or file in plain - * text or JSON format. + * This class defines static methods to support the Thread.dump_to_file diagnostic command + * and the HotSpotDiagnosticMXBean.dumpThreads API. It defines methods to generate a + * thread dump to a file or byte array in plain text or JSON format. */ public class ThreadDumper { private ThreadDumper() { } @@ -53,13 +59,12 @@ private ThreadDumper() { } private static final int MAX_BYTE_ARRAY_SIZE = 16_000; /** - * Generate a thread dump in plain text format to a byte array or file, UTF-8 encoded. - * + * Generate a thread dump in plain text format to a file or byte array, UTF-8 encoded. * This method is invoked by the VM for the Thread.dump_to_file diagnostic command. * * @param file the file path to the file, null or "-" to return a byte array * @param okayToOverwrite true to overwrite an existing file - * @return the UTF-8 encoded thread dump or message to return to the user + * @return the UTF-8 encoded thread dump or message to return to the tool user */ public static byte[] dumpThreads(String file, boolean okayToOverwrite) { if (file == null || file.equals("-")) { @@ -70,13 +75,12 @@ public static byte[] dumpThreads(String file, boolean okayToOverwrite) { } /** - * Generate a thread dump in JSON format to a byte array or file, UTF-8 encoded. - * + * Generate a thread dump in JSON format to a file or byte array, UTF-8 encoded. * This method is invoked by the VM for the Thread.dump_to_file diagnostic command. * * @param file the file path to the file, null or "-" to return a byte array * @param okayToOverwrite true to overwrite an existing file - * @return the UTF-8 encoded thread dump or message to return to the user + * @return the UTF-8 encoded thread dump or message to return to the tool user */ public static byte[] dumpThreadsToJson(String file, boolean okayToOverwrite) { if (file == null || file.equals("-")) { @@ -88,21 +92,32 @@ public static byte[] dumpThreadsToJson(String file, boolean okayToOverwrite) { /** * Generate a thread dump in plain text or JSON format to a byte array, UTF-8 encoded. + * This method is the implementation of the Thread.dump_to_file diagnostic command + * when a file path is not specified. It returns the thread dump and/or message to + * send to the tool user. */ private static byte[] dumpThreadsToByteArray(boolean json, int maxSize) { - try (var out = new BoundedByteArrayOutputStream(maxSize); - PrintStream ps = new PrintStream(out, true, StandardCharsets.UTF_8)) { + var out = new BoundedByteArrayOutputStream(maxSize); + try (out; var writer = new TextWriter(out)) { if (json) { - dumpThreadsToJson(ps); + dumpThreadsToJson(writer); } else { - dumpThreads(ps); + dumpThreads(writer); } - return out.toByteArray(); + } catch (Exception ex) { + if (ex instanceof UncheckedIOException ioe) { + ex = ioe.getCause(); + } + String reply = String.format("Failed: %s%n", ex); + return reply.getBytes(StandardCharsets.UTF_8); } + return out.toByteArray(); } /** * Generate a thread dump in plain text or JSON format to the given file, UTF-8 encoded. + * This method is the implementation of the Thread.dump_to_file diagnostic command. + * It returns the thread dump and/or message to send to the tool user. */ private static byte[] dumpThreadsToFile(String file, boolean okayToOverwrite, boolean json) { Path path = Path.of(file).toAbsolutePath(); @@ -110,224 +125,412 @@ private static byte[] dumpThreadsToFile(String file, boolean okayToOverwrite, bo ? new OpenOption[0] : new OpenOption[] { StandardOpenOption.CREATE_NEW }; String reply; - try (OutputStream out = Files.newOutputStream(path, options); - BufferedOutputStream bos = new BufferedOutputStream(out); - PrintStream ps = new PrintStream(bos, false, StandardCharsets.UTF_8)) { - if (json) { - dumpThreadsToJson(ps); - } else { - dumpThreads(ps); + try (OutputStream out = Files.newOutputStream(path, options)) { + try (var writer = new TextWriter(out)) { + if (json) { + dumpThreadsToJson(writer); + } else { + dumpThreads(writer); + } + reply = String.format("Created %s%n", path); + } catch (UncheckedIOException e) { + reply = String.format("Failed: %s%n", e.getCause()); } - reply = String.format("Created %s%n", path); - } catch (FileAlreadyExistsException e) { + } catch (FileAlreadyExistsException _) { reply = String.format("%s exists, use -overwrite to overwrite%n", path); - } catch (IOException ioe) { - reply = String.format("Failed: %s%n", ioe); + } catch (Exception ex) { + reply = String.format("Failed: %s%n", ex); } return reply.getBytes(StandardCharsets.UTF_8); } /** - * Generate a thread dump in plain text format to the given output stream, - * UTF-8 encoded. - * - * This method is invoked by HotSpotDiagnosticMXBean.dumpThreads. + * Generate a thread dump in plain text format to the given output stream, UTF-8 + * encoded. This method is invoked by HotSpotDiagnosticMXBean.dumpThreads. + * @throws IOException if an I/O error occurs */ - public static void dumpThreads(OutputStream out) { - BufferedOutputStream bos = new BufferedOutputStream(out); - PrintStream ps = new PrintStream(bos, false, StandardCharsets.UTF_8); + public static void dumpThreads(OutputStream out) throws IOException { + var writer = new TextWriter(out); try { - dumpThreads(ps); - } finally { - ps.flush(); // flushes underlying stream + dumpThreads(writer); + writer.flush(); + } catch (UncheckedIOException e) { + IOException ioe = e.getCause(); + throw ioe; } } /** - * Generate a thread dump in plain text format to the given print stream. + * Generate a thread dump in plain text format to the given text stream. + * @throws UncheckedIOException if an I/O error occurs */ - private static void dumpThreads(PrintStream ps) { - ps.println(processId()); - ps.println(Instant.now()); - ps.println(Runtime.version()); - ps.println(); - dumpThreads(ThreadContainers.root(), ps); + private static void dumpThreads(TextWriter writer) { + writer.println(processId()); + writer.println(Instant.now()); + writer.println(Runtime.version()); + writer.println(); + dumpThreads(ThreadContainers.root(), writer); } - private static void dumpThreads(ThreadContainer container, PrintStream ps) { - container.threads().forEach(t -> dumpThread(t, ps)); - container.children().forEach(c -> dumpThreads(c, ps)); + private static void dumpThreads(ThreadContainer container, TextWriter writer) { + container.threads().forEach(t -> dumpThread(t, writer)); + container.children().forEach(c -> dumpThreads(c, writer)); } - private static void dumpThread(Thread thread, PrintStream ps) { - String suffix = thread.isVirtual() ? " virtual" : ""; - ps.println("#" + thread.threadId() + " \"" + thread.getName() + "\"" + suffix); - for (StackTraceElement ste : thread.getStackTrace()) { - ps.print(" "); - ps.println(ste); + private static void dumpThread(Thread thread, TextWriter writer) { + ThreadSnapshot snapshot = ThreadSnapshot.of(thread); + Instant now = Instant.now(); + Thread.State state = snapshot.threadState(); + writer.println("#" + thread.threadId() + " \"" + snapshot.threadName() + + "\" " + (thread.isVirtual() ? "virtual " : "") + state + " " + now); + + StackTraceElement[] stackTrace = snapshot.stackTrace(); + int depth = 0; + while (depth < stackTrace.length) { + writer.print(" at "); + writer.println(stackTrace[depth]); + snapshot.ownedMonitorsAt(depth).forEach(o -> { + if (o != null) { + writer.println(" - locked " + decorateObject(o)); + } else { + writer.println(" - lock is eliminated"); + } + }); + + // if parkBlocker set, or blocked/waiting on monitor, then print after top frame + if (depth == 0) { + // park blocker + Object parkBlocker = snapshot.parkBlocker(); + if (parkBlocker != null) { + writer.println(" - parking to wait for " + decorateObject(parkBlocker)); + } + + // blocked on monitor enter or Object.wait + if (state == Thread.State.BLOCKED && snapshot.blockedOn() instanceof Object obj) { + writer.println(" - waiting to lock " + decorateObject(obj)); + } else if ((state == Thread.State.WAITING || state == Thread.State.TIMED_WAITING) + && snapshot.waitingOn() instanceof Object obj) { + writer.println(" - waiting on " + decorateObject(obj)); + } + } + + depth++; } - ps.println(); + writer.println(); + } + + /** + * Returns the identity string for the given object in a form suitable for the plain + * text format thread dump. + */ + private static String decorateObject(Object obj) { + return "<" + Objects.toIdentityString(obj) + ">"; } /** * Generate a thread dump in JSON format to the given output stream, UTF-8 encoded. - * * This method is invoked by HotSpotDiagnosticMXBean.dumpThreads. + * @throws IOException if an I/O error occurs */ - public static void dumpThreadsToJson(OutputStream out) { - BufferedOutputStream bos = new BufferedOutputStream(out); - PrintStream ps = new PrintStream(bos, false, StandardCharsets.UTF_8); + public static void dumpThreadsToJson(OutputStream out) throws IOException { + var writer = new TextWriter(out); try { - dumpThreadsToJson(ps); - } finally { - ps.flush(); // flushes underlying stream + dumpThreadsToJson(writer); + writer.flush(); + } catch (UncheckedIOException e) { + IOException ioe = e.getCause(); + throw ioe; } } /** - * Generate a thread dump to the given print stream in JSON format. + * Generate a thread dump to the given text stream in JSON format. + * @throws UncheckedIOException if an I/O error occurs */ - private static void dumpThreadsToJson(PrintStream out) { - out.println("{"); - out.println(" \"threadDump\": {"); - - String now = Instant.now().toString(); - String runtimeVersion = Runtime.version().toString(); - out.format(" \"processId\": \"%d\",%n", processId()); - out.format(" \"time\": \"%s\",%n", escape(now)); - out.format(" \"runtimeVersion\": \"%s\",%n", escape(runtimeVersion)); - - out.println(" \"threadContainers\": ["); - List containers = allContainers(); - Iterator iterator = containers.iterator(); - while (iterator.hasNext()) { - ThreadContainer container = iterator.next(); - boolean more = iterator.hasNext(); - dumpThreadsToJson(container, out, more); - } - out.println(" ]"); // end of threadContainers - - out.println(" }"); // end threadDump - out.println("}"); // end object + private static void dumpThreadsToJson(TextWriter textWriter) { + var jsonWriter = new JsonWriter(textWriter); + + jsonWriter.startObject(); // top-level object + + jsonWriter.startObject("threadDump"); + + jsonWriter.writeProperty("processId", processId()); + jsonWriter.writeProperty("time", Instant.now()); + jsonWriter.writeProperty("runtimeVersion", Runtime.version()); + + jsonWriter.startArray("threadContainers"); + dumpThreads(ThreadContainers.root(), jsonWriter); + jsonWriter.endArray(); + + jsonWriter.endObject(); // threadDump + + jsonWriter.endObject(); // end of top-level object } /** - * Dump the given thread container to the print stream in JSON format. + * Write a thread container to the given JSON writer. + * @throws UncheckedIOException if an I/O error occurs */ - private static void dumpThreadsToJson(ThreadContainer container, - PrintStream out, - boolean more) { - out.println(" {"); - out.format(" \"container\": \"%s\",%n", escape(container.toString())); - - ThreadContainer parent = container.parent(); - if (parent == null) { - out.format(" \"parent\": null,%n"); - } else { - out.format(" \"parent\": \"%s\",%n", escape(parent.toString())); - } + private static void dumpThreads(ThreadContainer container, JsonWriter jsonWriter) { + jsonWriter.startObject(); + jsonWriter.writeProperty("container", container); + jsonWriter.writeProperty("parent", container.parent()); Thread owner = container.owner(); - if (owner == null) { - out.format(" \"owner\": null,%n"); - } else { - out.format(" \"owner\": \"%d\",%n", owner.threadId()); - } + jsonWriter.writeProperty("owner", (owner != null) ? owner.threadId() : null); long threadCount = 0; - out.println(" \"threads\": ["); + jsonWriter.startArray("threads"); Iterator threads = container.threads().iterator(); while (threads.hasNext()) { Thread thread = threads.next(); - dumpThreadToJson(thread, out, threads.hasNext()); + dumpThread(thread, jsonWriter); threadCount++; } - out.println(" ],"); // end of threads + jsonWriter.endArray(); // threads // thread count if (!ThreadContainers.trackAllThreads()) { threadCount = Long.max(threadCount, container.threadCount()); } - out.format(" \"threadCount\": \"%d\"%n", threadCount); + jsonWriter.writeProperty("threadCount", threadCount); - if (more) { - out.println(" },"); - } else { - out.println(" }"); // last container, no trailing comma - } + jsonWriter.endObject(); + + // the children of the thread container follow + container.children().forEach(c -> dumpThreads(c, jsonWriter)); } /** - * Dump the given thread and its stack trace to the print stream in JSON format. + * Write a thread to the given JSON writer. + * @throws UncheckedIOException if an I/O error occurs */ - private static void dumpThreadToJson(Thread thread, PrintStream out, boolean more) { - out.println(" {"); - out.println(" \"tid\": \"" + thread.threadId() + "\","); - out.println(" \"name\": \"" + escape(thread.getName()) + "\","); - out.println(" \"stack\": ["); - - int i = 0; - StackTraceElement[] stackTrace = thread.getStackTrace(); - while (i < stackTrace.length) { - out.print(" \""); - out.print(escape(stackTrace[i].toString())); - out.print("\""); - i++; - if (i < stackTrace.length) { - out.println(","); - } else { - out.println(); // last element, no trailing comma + private static void dumpThread(Thread thread, JsonWriter jsonWriter) { + Instant now = Instant.now(); + ThreadSnapshot snapshot = ThreadSnapshot.of(thread); + Thread.State state = snapshot.threadState(); + StackTraceElement[] stackTrace = snapshot.stackTrace(); + + jsonWriter.startObject(); + jsonWriter.writeProperty("tid", thread.threadId()); + jsonWriter.writeProperty("time", now); + if (thread.isVirtual()) { + jsonWriter.writeProperty("virtual", Boolean.TRUE); + } + jsonWriter.writeProperty("name", snapshot.threadName()); + jsonWriter.writeProperty("state", state); + + // park blocker + Object parkBlocker = snapshot.parkBlocker(); + if (parkBlocker != null) { + // parkBlocker is an object to allow for exclusiveOwnerThread in the future + jsonWriter.startObject("parkBlocker"); + jsonWriter.writeProperty("object", Objects.toIdentityString(parkBlocker)); + jsonWriter.endObject(); + } + + // blocked on monitor enter or Object.wait + if (state == Thread.State.BLOCKED && snapshot.blockedOn() instanceof Object obj) { + jsonWriter.writeProperty("blockedOn", Objects.toIdentityString(obj)); + } else if ((state == Thread.State.WAITING || state == Thread.State.TIMED_WAITING) + && snapshot.waitingOn() instanceof Object obj) { + jsonWriter.writeProperty("waitingOn", Objects.toIdentityString(obj)); + } + + // stack trace + jsonWriter.startArray("stack"); + Arrays.stream(stackTrace).forEach(jsonWriter::writeProperty); + jsonWriter.endArray(); + + // monitors owned, skip if none + if (snapshot.ownsMonitors()) { + jsonWriter.startArray("monitorsOwned"); + int depth = 0; + while (depth < stackTrace.length) { + List objs = snapshot.ownedMonitorsAt(depth).toList(); + if (!objs.isEmpty()) { + jsonWriter.startObject(); + jsonWriter.writeProperty("depth", depth); + jsonWriter.startArray("locks"); + snapshot.ownedMonitorsAt(depth) + .map(o -> (o != null) ? Objects.toIdentityString(o) : null) + .forEach(jsonWriter::writeProperty); + jsonWriter.endArray(); + jsonWriter.endObject(); + } + depth++; } + jsonWriter.endArray(); } - out.println(" ]"); - if (more) { - out.println(" },"); - } else { - out.println(" }"); // last thread, no trailing comma + + // thread identifier of carrier, when mounted + if (thread.isVirtual() && snapshot.carrierThread() instanceof Thread carrier) { + jsonWriter.writeProperty("carrier", carrier.threadId()); } + + jsonWriter.endObject(); } /** - * Returns a list of all thread containers that are "reachable" from - * the root container. + * Simple JSON writer to stream objects/arrays to a TextWriter with formatting. + * This class is not intended to be a fully featured JSON writer. */ - private static List allContainers() { - List containers = new ArrayList<>(); - collect(ThreadContainers.root(), containers); - return containers; - } + private static class JsonWriter { + private static class Node { + final boolean isArray; + int propertyCount; + Node(boolean isArray) { + this.isArray = isArray; + } + boolean isArray() { + return isArray; + } + int propertyCount() { + return propertyCount; + } + int getAndIncrementPropertyCount() { + int old = propertyCount; + propertyCount++; + return old; + } + } + private final Deque stack = new ArrayDeque<>(); + private final TextWriter writer; - private static void collect(ThreadContainer container, List containers) { - containers.add(container); - container.children().forEach(c -> collect(c, containers)); - } + JsonWriter(TextWriter writer) { + this.writer = writer; + } - /** - * Escape any characters that need to be escape in the JSON output. - */ - private static String escape(String value) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < value.length(); i++) { - char c = value.charAt(i); - switch (c) { - case '"' -> sb.append("\\\""); - case '\\' -> sb.append("\\\\"); - case '/' -> sb.append("\\/"); - case '\b' -> sb.append("\\b"); - case '\f' -> sb.append("\\f"); - case '\n' -> sb.append("\\n"); - case '\r' -> sb.append("\\r"); - case '\t' -> sb.append("\\t"); - default -> { - if (c <= 0x1f) { - sb.append(String.format("\\u%04x", c)); - } else { - sb.append(c); + private void indent() { + int indent = stack.size() * 2; + writer.print(" ".repeat(indent)); + } + + /** + * Start of object or array. + */ + private void startObject(String name, boolean isArray) { + if (!stack.isEmpty()) { + Node node = stack.peek(); + if (node.getAndIncrementPropertyCount() > 0) { + writer.println(","); + } + } + indent(); + if (name != null) { + writer.print("\"" + name + "\": "); + } + writer.println(isArray ? "[" : "{"); + stack.push(new Node(isArray)); + } + + /** + * End of object or array. + */ + private void endObject(boolean isArray) { + Node node = stack.pop(); + if (node.isArray() != isArray) + throw new IllegalStateException(); + if (node.propertyCount() > 0) { + writer.println(); + } + indent(); + writer.print(isArray ? "]" : "}"); + } + + /** + * Write a property. + * @param name the property name, null for an unnamed property + * @param obj the value or null + */ + void writeProperty(String name, Object obj) { + Node node = stack.peek(); + if (node.getAndIncrementPropertyCount() > 0) { + writer.println(","); + } + indent(); + if (name != null) { + writer.print("\"" + name + "\": "); + } + switch (obj) { + // Long may be larger than safe range of JSON integer value + case Long _ -> writer.print("\"" + obj + "\""); + case Number _ -> writer.print(obj); + case Boolean _ -> writer.print(obj); + case null -> writer.print("null"); + default -> writer.print("\"" + escape(obj.toString()) + "\""); + } + } + + /** + * Write an unnamed property. + */ + void writeProperty(Object obj) { + writeProperty(null, obj); + } + + /** + * Start named object. + */ + void startObject(String name) { + startObject(name, false); + } + + /** + * Start unnamed object. + */ + void startObject() { + startObject(null); + } + + /** + * End of object. + */ + void endObject() { + endObject(false); + } + + /** + * Start named array. + */ + void startArray(String name) { + startObject(name, true); + } + + /** + * End of array. + */ + void endArray() { + endObject(true); + } + + /** + * Escape any characters that need to be escape in the JSON output. + */ + private static String escape(String value) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + switch (c) { + case '"' -> sb.append("\\\""); + case '\\' -> sb.append("\\\\"); + case '/' -> sb.append("\\/"); + case '\b' -> sb.append("\\b"); + case '\f' -> sb.append("\\f"); + case '\n' -> sb.append("\\n"); + case '\r' -> sb.append("\\r"); + case '\t' -> sb.append("\\t"); + default -> { + if (c <= 0x1f) { + sb.append(String.format("\\u%04x", c)); + } else { + sb.append(c); + } } } } + return sb.toString(); } - return sb.toString(); } /** @@ -357,6 +560,56 @@ public void close() { } } + /** + * Simple Writer implementation for printing text. The print/println methods + * throw UncheckedIOException if an I/O error occurs. + */ + private static class TextWriter extends Writer { + private final Writer delegate; + + TextWriter(OutputStream out) { + delegate = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8)); + } + + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + delegate.write(cbuf, off, len); + } + + void print(Object obj) { + String s = String.valueOf(obj); + try { + write(s, 0, s.length()); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + void println() { + print(System.lineSeparator()); + } + + void println(String s) { + print(s); + println(); + } + + void println(Object obj) { + print(obj); + println(); + } + + @Override + public void flush() throws IOException { + delegate.flush(); + } + + @Override + public void close() throws IOException { + delegate.close(); + } + } + /** * Returns the process ID or -1 if not supported. */ diff --git a/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java b/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java new file mode 100644 index 00000000000..e0dd4bbc508 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/vm/ThreadSnapshot.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.vm; + +import java.util.Arrays; +import java.util.stream.Stream; + +/** + * Represents a snapshot of information about a Thread. + */ +class ThreadSnapshot { + private static final StackTraceElement[] EMPTY_STACK = new StackTraceElement[0]; + private static final ThreadLock[] EMPTY_LOCKS = new ThreadLock[0]; + + // filled by VM + private String name; + private int threadStatus; + private Thread carrierThread; + private StackTraceElement[] stackTrace; + // owned monitors + private ThreadLock[] locks; + // an object the thread is blocked/waiting on, converted to ThreadBlocker by ThreadSnapshot.of() + private int blockerTypeOrdinal; + private Object blockerObject; + + // set by ThreadSnapshot.of() + private ThreadBlocker blocker; + + private ThreadSnapshot() {} + + /** + * Take a snapshot of a Thread to get all information about the thread. + * @throws UnsupportedOperationException if not supported by VM + */ + static ThreadSnapshot of(Thread thread) { + ThreadSnapshot snapshot = create(thread); + if (snapshot == null) { + throw new UnsupportedOperationException(); + } + if (snapshot.stackTrace == null) { + snapshot.stackTrace = EMPTY_STACK; + } + if (snapshot.locks != null) { + Arrays.stream(snapshot.locks).forEach(ThreadLock::finishInit); + } else { + snapshot.locks = EMPTY_LOCKS; + } + if (snapshot.blockerObject != null) { + snapshot.blocker = new ThreadBlocker(snapshot.blockerTypeOrdinal, snapshot.blockerObject); + snapshot.blockerObject = null; // release + } + return snapshot; + } + + /** + * Returns the thread name. + */ + String threadName() { + return name; + } + + /** + * Returns the thread state. + */ + Thread.State threadState() { + return jdk.internal.misc.VM.toThreadState(threadStatus); + } + + /** + * Returns the thread stack trace. + */ + StackTraceElement[] stackTrace() { + return stackTrace; + } + + /** + * Returns the thread's parkBlocker. + */ + Object parkBlocker() { + return getBlocker(BlockerLockType.PARK_BLOCKER); + } + + /** + * Returns the object that the thread is blocked on. + * @throws IllegalStateException if not in the blocked state + */ + Object blockedOn() { + if (threadState() != Thread.State.BLOCKED) { + throw new IllegalStateException(); + } + return getBlocker(BlockerLockType.WAITING_TO_LOCK); + } + + /** + * Returns the object that the thread is waiting on. + * @throws IllegalStateException if not in the waiting state + */ + Object waitingOn() { + if (threadState() != Thread.State.WAITING + && threadState() != Thread.State.TIMED_WAITING) { + throw new IllegalStateException(); + } + return getBlocker(BlockerLockType.WAITING_ON); + } + + private Object getBlocker(BlockerLockType type) { + return (blocker != null && blocker.type == type) ? blocker.obj : null; + } + + /** + * Returns true if the thread owns any object monitors. + */ + boolean ownsMonitors() { + return locks.length > 0; + } + + /** + * Returns the objects that the thread locked at the given depth. The stream + * will contain a null element for a monitor that has been eliminated. + */ + Stream ownedMonitorsAt(int depth) { + return Arrays.stream(locks) + .filter(lock -> lock.depth() == depth) + .map(lock -> (lock.type == OwnedLockType.LOCKED) + ? lock.lockObject() + : /*eliminated*/ null); + } + + /** + * If the thread is a mounted virtual thread then return its carrier. + */ + Thread carrierThread() { + return carrierThread; + } + + /** + * Represents information about a locking operation. + */ + private enum OwnedLockType { + LOCKED, + // Lock object is a class of the eliminated monitor + ELIMINATED, + } + + private enum BlockerLockType { + // Park blocker + PARK_BLOCKER, + WAITING_TO_LOCK, + // Object.wait() + WAITING_ON, + } + + /** + * Represents a locking operation of a thread at a specific stack depth. + */ + private static class ThreadLock { + private static final OwnedLockType[] lockTypeValues = OwnedLockType.values(); // cache + + // set by the VM + private int depth; + private int typeOrdinal; + private Object obj; + + // set by ThreadLock.of() + private OwnedLockType type; + + private ThreadLock() {} + + void finishInit() { + type = lockTypeValues[typeOrdinal]; + } + + int depth() { + return depth; + } + + OwnedLockType type() { + return type; + } + + Object lockObject() { + if (type == OwnedLockType.ELIMINATED) { + // we have no lock object, lock contains lock class + return null; + } + return obj; + } + } + + private record ThreadBlocker(BlockerLockType type, Object obj) { + private static final BlockerLockType[] lockTypeValues = BlockerLockType.values(); // cache + + ThreadBlocker(int typeOrdinal, Object obj) { + this(lockTypeValues[typeOrdinal], obj); + } + } + + private static native ThreadSnapshot create(Thread thread); +} diff --git a/src/java.xml/share/classes/jdk/xml/internal/JdkCatalog.java b/src/java.base/share/classes/jdk/internal/vm/vector/Utils.java similarity index 58% rename from src/java.xml/share/classes/jdk/xml/internal/JdkCatalog.java rename to src/java.base/share/classes/jdk/internal/vm/vector/Utils.java index 51890307399..de0bb83d39d 100644 --- a/src/java.xml/share/classes/jdk/xml/internal/JdkCatalog.java +++ b/src/java.base/share/classes/jdk/internal/vm/vector/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,25 +22,28 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.xml.internal; +package jdk.internal.vm.vector; -import java.net.URI; -import javax.xml.catalog.Catalog; -import javax.xml.catalog.CatalogFeatures; -import javax.xml.catalog.CatalogManager; +import jdk.internal.reflect.CallerSensitive; +import jdk.internal.reflect.Reflection; /** - * Represents the built-in Catalog that hosts the DTDs for the Java platform. + * Miscellaneous utility methods. */ -public class JdkCatalog { - public static final String JDKCATALOG = "/jdk/xml/internal/jdkcatalog/JDKCatalog.xml"; - private static final String JDKCATALOG_URL = SecuritySupport.getResource(JDKCATALOG).toExternalForm(); - public static Catalog catalog; +public class Utils { + public static final boolean DEBUG = Boolean.getBoolean("jdk.incubator.vector.DEBUG"); - public static void init(String resolve) { - if (catalog == null) { - CatalogFeatures cf = JdkXmlUtils.getCatalogFeatures(null, JDKCATALOG_URL, null, resolve); - catalog = CatalogManager.catalog(cf, URI.create(JDKCATALOG_URL)); + public static boolean isNonCapturingLambda(Object o) { + return o.getClass().getDeclaredFields().length == 0; + } + + @CallerSensitive + public static void debug(String format, Object... args) { + if (DEBUG) { + Class caller = Reflection.getCallerClass(); + System.out.printf("DEBUG: %s: ", caller.getSimpleName()); + System.out.printf(format, args); + System.out.println(); } } } 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 cbf30da2289..4a8ad79b50c 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 @@ -30,6 +30,8 @@ import java.util.function.*; +import static jdk.internal.vm.vector.Utils.isNonCapturingLambda; + public class VectorSupport { static { registerNatives(); @@ -114,6 +116,9 @@ public class VectorSupport { public static final int VECTOR_OP_EXPM1 = 117; public static final int VECTOR_OP_HYPOT = 118; + public static final int VECTOR_OP_MATHLIB_FIRST = VECTOR_OP_TAN; + public static final int VECTOR_OP_MATHLIB_LAST = VECTOR_OP_HYPOT; + public static final int VECTOR_OP_SADD = 119; public static final int VECTOR_OP_SSUB = 120; public static final int VECTOR_OP_SUADD = 121; @@ -323,6 +328,23 @@ V unaryOp(int oprId, /* ============================================================================ */ +// public interface LibraryUnaryOperation, +// M extends VectorMask> { +// V apply(MemorySegment entry, V v, M m); +// } + + @IntrinsicCandidate + public static + , E> + V libraryUnaryOp(long addr, Class vClass, Class eClass, int length, String debugName, + V v, + UnaryOperation defaultImpl) { + assert isNonCapturingLambda(defaultImpl) : defaultImpl; + return defaultImpl.apply(v, null); + } + + /* ============================================================================ */ + public interface BinaryOperation> { VM apply(VM v1, VM v2, M m); @@ -341,6 +363,24 @@ VM binaryOp(int oprId, assert isNonCapturingLambda(defaultImpl) : defaultImpl; return defaultImpl.apply(v1, v2, m); } + + /* ============================================================================ */ + +// public interface LibraryBinaryOperation> { +// V apply(MemorySegment entry, V v1, V v2, M m); +// } + + @IntrinsicCandidate + public static + + V libraryBinaryOp(long addr, Class vClass, Class eClass, int length, String debugName, + V v1, V v2, + BinaryOperation defaultImpl) { + assert isNonCapturingLambda(defaultImpl) : defaultImpl; + return defaultImpl.apply(v1, v2, null); + } + /* ============================================================================ */ public interface SelectFromTwoVector> { @@ -718,13 +758,19 @@ long maskReductionCoerced(int oper, /* ============================================================================ */ + // Returns a string containing a list of CPU features VM detected. + public static native String getCPUFeatures(); + + /* ============================================================================ */ + // query the JVM's supported vector sizes and types public static native int getMaxLaneCount(Class etype); /* ============================================================================ */ - public static boolean isNonCapturingLambda(Object o) { - return o.getClass().getDeclaredFields().length == 0; + @SuppressWarnings({"restricted"}) + public static void loadNativeLibrary(String name) { + System.loadLibrary(name); } /* ============================================================================ */ diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 22f40d9cead..07de3f2c57f 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -156,7 +156,6 @@ java.compiler, java.desktop, // for ScopedValue jdk.compiler, - jdk.crypto.cryptoki, // participates in preview features jdk.incubator.vector, // participates in preview features jdk.jartool, // participates in preview features jdk.jdeps, // participates in preview features @@ -271,8 +270,13 @@ java.prefs, java.security.jgss, java.smartcardio, + java.naming, + java.rmi, + java.net.http, jdk.charsets, + jdk.incubator.vector, jdk.internal.vm.ci, + jdk.httpserver, jdk.jlink, jdk.jpackage, jdk.net; diff --git a/src/java.base/share/classes/sun/launcher/LauncherHelper.java b/src/java.base/share/classes/sun/launcher/LauncherHelper.java index 8fbf76851cc..81a4fe32110 100644 --- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -73,7 +73,6 @@ import java.util.stream.Stream; import jdk.internal.misc.MethodFinder; -import jdk.internal.misc.PreviewFeatures; import jdk.internal.misc.VM; import jdk.internal.module.ModuleBootstrap; import jdk.internal.module.Modules; @@ -945,19 +944,13 @@ private static void validateMainMethod(Class mainClass) { int mods = mainMethod.getModifiers(); isStaticMain = Modifier.isStatic(mods); - boolean isPublic = Modifier.isPublic(mods); noArgMain = mainMethod.getParameterCount() == 0; - if (!PreviewFeatures.isEnabled()) { - if (!isStaticMain || !isPublic || noArgMain) { - abort(null, "java.launcher.cls.error2", mainClass.getName(), - JAVAFX_APPLICATION_CLASS_NAME); - } - return; - } - if (!isStaticMain) { String className = mainMethod.getDeclaringClass().getName(); + if (Modifier.isAbstract(mainClass.getModifiers())) { + abort(null, "java.launcher.cls.error8", className); + } if (mainClass.isMemberClass() && !Modifier.isStatic(mainClass.getModifiers())) { abort(null, "java.launcher.cls.error7", className); } 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 e8dc89161fd..83e08a3e11c 100644 --- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties +++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -154,7 +154,7 @@ java.launcher.X.usage=\n\ \ -Xmixed mixed mode execution (default)\n\ \ -Xmn sets the initial and maximum size (in bytes) of the heap\n\ \ for the young generation (nursery)\n\ -\ -Xms set initial Java heap size\n\ +\ -Xms set minimum and initial Java heap size\n\ \ -Xmx set maximum Java heap size\n\ \ -Xnoclassgc disable class garbage collection\n\ \ -Xrs reduce use of OS signals by Java/VM (see documentation)\n\ @@ -279,6 +279,9 @@ java.launcher.cls.error6=\ java.launcher.cls.error7=\ Error: non-static inner class {0} constructor can not be invoked \n\ make inner class static or move inner class out to separate source file +java.launcher.cls.error8=\ + Error: abstract class {0} can not be instantiated\n\ + please use a concrete class java.launcher.jar.error1=\ Error: An unexpected error occurred while trying to open file {0} java.launcher.jar.error2=manifest not found in {0} diff --git a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java b/src/java.base/share/classes/sun/net/util/IPAddressUtil.java index b3da295c4a7..21bbc5ac455 100644 --- a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java +++ b/src/java.base/share/classes/sun/net/util/IPAddressUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,9 @@ import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import static jdk.internal.util.Exceptions.formatMsg; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; + public class IPAddressUtil { private static final int INADDR4SZ = 4; private static final int INADDR16SZ = 16; @@ -161,7 +164,8 @@ public static byte[] validateNumericFormatV4(String src, boolean throwIAE) { * @return an {@code IllegalArgumentException} instance */ public static IllegalArgumentException invalidIpAddressLiteral(String src) { - return new IllegalArgumentException("Invalid IP address literal: " + src); + return new IllegalArgumentException( + formatMsg("Invalid IP address literal%s", filterNonSocketInfo(src).prefixWith(": "))); } /* diff --git a/src/java.base/share/classes/sun/net/util/SocketExceptions.java b/src/java.base/share/classes/sun/net/util/SocketExceptions.java deleted file mode 100644 index 1198898edcb..00000000000 --- a/src/java.base/share/classes/sun/net/util/SocketExceptions.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.net.util; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.net.InetSocketAddress; -import java.net.UnixDomainSocketAddress; -import java.net.SocketAddress; - -import sun.security.util.SecurityProperties; - -public final class SocketExceptions { - private SocketExceptions() {} - - private static final boolean enhancedExceptionText = - SecurityProperties.includedInExceptions("hostInfo"); - - /** - * Utility which takes an exception and returns either the same exception - * or a new exception of the same type with the same stack trace - * and detail message enhanced with addressing information from the - * given InetSocketAddress. - * - * If the system/security property "jdk.includeInExceptions" is not - * set or does not contain the category hostInfo, - * then the original exception is returned. - * - * Only specific IOException subtypes are supported. - */ - public static IOException of(IOException e, SocketAddress addr) { - if (!enhancedExceptionText || addr == null) { - return e; - } - if (addr instanceof UnixDomainSocketAddress) { - return ofUnixDomain(e, (UnixDomainSocketAddress)addr); - } else if (addr instanceof InetSocketAddress) { - return ofInet(e, (InetSocketAddress)addr); - } else { - return e; - } - } - - private static IOException ofInet(IOException e, InetSocketAddress addr) { - return create(e, String.join(": ", e.getMessage(), addr.toString())); - } - - private static IOException ofUnixDomain(IOException e, UnixDomainSocketAddress addr) { - String path = addr.getPath().toString(); - StringBuilder sb = new StringBuilder(); - sb.append(e.getMessage()); - sb.append(": "); - sb.append(path); - String enhancedMsg = sb.toString(); - return create(e, enhancedMsg); - } - - // return a new instance of the same type with the given detail - // msg, or if the type doesn't support detail msgs, return given - // instance. - private static IOException create(final IOException e, final String msg) { - try { - Class clazz = e.getClass(); - Constructor ctor = clazz.getConstructor(String.class); - IOException e1 = (IOException)(ctor.newInstance(msg)); - e1.setStackTrace(e.getStackTrace()); - return e1; - } catch (Exception e0) { - // Some eg AsynchronousCloseException have no detail msg - return e; - } - } -} diff --git a/src/java.base/share/classes/sun/net/www/ParseUtil.java b/src/java.base/share/classes/sun/net/www/ParseUtil.java index 51d1b8398b6..cac32e53288 100644 --- a/src/java.base/share/classes/sun/net/www/ParseUtil.java +++ b/src/java.base/share/classes/sun/net/www/ParseUtil.java @@ -40,6 +40,8 @@ import java.util.HexFormat; import sun.nio.cs.UTF_8; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * A class that contains useful routines common to sun.net.www @@ -502,7 +504,7 @@ private static void checkPath(String s, String scheme, String path) { if (scheme != null) { if (path != null && !path.isEmpty() && path.charAt(0) != '/') - throw new URISyntaxException(s, + throw new URISyntaxException(formatMsg("%s", filterNonSocketInfo(s)), "Relative path in absolute URI"); } } diff --git a/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java index 97e797040a0..fc947f8977f 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/file/FileURLConnection.java @@ -25,6 +25,7 @@ package sun.net.www.protocol.file; +import java.net.MalformedURLException; import java.net.URL; import java.net.FileNameMap; import java.io.*; @@ -46,6 +47,11 @@ public class FileURLConnection extends URLConnection { private static final String TEXT_PLAIN = "text/plain"; private static final String LAST_MODIFIED = "last-modified"; + // The feature of falling back to FTP for non-local file URLs is disabled + // by default and can be re-enabled by setting a system property + private static final boolean FTP_FALLBACK_ENABLED = + Boolean.getBoolean("jdk.net.file.ftpfallback"); + private final File file; private InputStream is; private List directoryListing; @@ -204,6 +210,8 @@ public synchronized InputStream getInputStream() /* since getOutputStream isn't supported, only read permission is * relevant */ + @Override + @Deprecated(since = "25", forRemoval = true) @SuppressWarnings("removal") public Permission getPermission() throws IOException { if (permission == null) { @@ -222,4 +230,17 @@ public Permission getPermission() throws IOException { } return permission; } + + /** + * Throw {@link MalformedURLException} if the FTP fallback feature for non-local + * file URLs is not explicitly enabled via system property. + * + * @see #FTP_FALLBACK_ENABLED + * @throws MalformedURLException if FTP fallback is not enabled + */ + static void requireFtpFallbackEnabled() throws MalformedURLException { + if (!FTP_FALLBACK_ENABLED) { + throw new MalformedURLException("Unsupported non-local file URL"); + } + } } diff --git a/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java index 493fda1c1b3..be24f1133f2 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -569,6 +569,8 @@ String guessContentTypeFromFilename(String fname) { * @return The {@code Permission} object. */ @Override + @Deprecated(since = "25", forRemoval = true) + @SuppressWarnings("removal") public Permission getPermission() { if (permission == null) { int urlport = url.getPort(); 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 fb2dfe6fff3..2f011f5805b 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 @@ -53,7 +53,8 @@ import sun.util.logging.PlatformLogger; import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*; - +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * This class provides HTTPS client URL support, building on the standard @@ -559,8 +560,10 @@ private void checkURLSpoofing(HostnameVerifier hostnameVerifier) serverSocket.close(); session.invalidate(); - throw new IOException("HTTPS hostname wrong: should be <" - + url.getHost() + ">"); + throw new IOException(formatMsg("Wrong HTTPS hostname%s", + filterNonSocketInfo(url.getHost()) + .prefixWith(": should be <") + .suffixWith(">"))); } @Override diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java index 2096957d289..26c9e0188d1 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -355,6 +355,9 @@ public long getHeaderFieldDate(String name, long defaultValue) { return delegate.getHeaderFieldDate(name, defaultValue); } + @Override + @Deprecated(since = "25", forRemoval = true) + @SuppressWarnings("removal") public Permission getPermission() throws IOException { return delegate.getPermission(); } diff --git a/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java b/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java index 2884f825b84..381d4244238 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,8 @@ import java.io.IOException; import java.net.*; +import static jdk.internal.util.Exceptions.filterJarName; +import static jdk.internal.util.Exceptions.formatMsg; /* * Jar URL Handler @@ -181,8 +183,11 @@ private String parseAbsoluteSpec(String spec) { String innerSpec = spec.substring(0, index - 1); newURL(innerSpec); } catch (MalformedURLException e) { - throw new NullPointerException("invalid url: " + - spec + " (" + e + ")"); + throw new NullPointerException( + formatMsg("invalid url: %s %s", filterJarName(spec), + filterJarName(e.getMessage()) + .prefixWith("(") + .suffixWith(")"))); } return spec; } @@ -193,19 +198,18 @@ private String parseContextSpec(URL url, String spec) { if (spec.startsWith("/")) { int bangSlash = indexOfBangSlash(ctxFile); if (bangSlash == -1) { - throw new NullPointerException("malformed " + - "context url:" + - url + - ": no !/"); + throw new NullPointerException( + formatMsg("malformed context url%s : no !/", + filterJarName(String.valueOf(url)).prefixWith(": "))); } ctxFile = ctxFile.substring(0, bangSlash); } else { // chop up the last component int lastSlash = ctxFile.lastIndexOf('/'); if (lastSlash == -1) { - throw new NullPointerException("malformed " + - "context url:" + - url); + throw new NullPointerException( + formatMsg("malformed context url%s", + filterJarName(String.valueOf(url)).prefixWith(": "))); } else if (lastSlash < ctxFile.length() - 1) { ctxFile = ctxFile.substring(0, lastSlash + 1); } diff --git a/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java index 4d695c8d4e8..741854349d7 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jar/JarFileFactory.java @@ -35,6 +35,8 @@ import jdk.internal.util.OperatingSystem; import sun.net.util.URLUtil; import sun.net.www.ParseUtil; +import static jdk.internal.util.Exceptions.filterJarName; +import static jdk.internal.util.Exceptions.formatMsg; /* A factory for cached JAR file. This class is used to both retrieve * and cache Jar files. @@ -108,7 +110,7 @@ JarFile getOrCreate(URL url, boolean useCaches) throws IOException { result = URLJarFile.getJarFile(patched, this); } if (result == null) - throw new FileNotFoundException(url.toString()); + throw new FileNotFoundException(formatMsg("%s", filterJarName(url.toString()))); return result; } @@ -200,7 +202,7 @@ JarFile get(URL url, boolean useCaches) throws IOException { result = URLJarFile.getJarFile(url, this); } if (result == null) - throw new FileNotFoundException(url.toString()); + throw new FileNotFoundException(formatMsg("%s", filterJarName(url.toString()))); return result; } 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 85d36fe2320..96c04132551 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,9 @@ import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import static jdk.internal.util.Exceptions.filterJarName; +import static jdk.internal.util.Exceptions.formatMsg; + /** * @author Benjamin Renaud @@ -77,6 +80,9 @@ public JarEntry getJarEntry() throws IOException { return jarEntry; } + @Override + @Deprecated(since = "25", forRemoval = true) + @SuppressWarnings("removal") public Permission getPermission() throws IOException { return jarFileURLConnection.getPermission(); } @@ -126,9 +132,10 @@ public void connect() throws IOException { factory.closeIfNotCached(url, jarFile); } catch (Exception e) { } - throw new FileNotFoundException("JAR entry " + entryName + - " not found in " + - jarFile.getName()); + throw new FileNotFoundException( + formatMsg("JAR entry %s not found in jar file %s", + filterJarName(entryName), + filterJarName(jarFile.getName()))); } } @@ -166,9 +173,10 @@ public InputStream getInputStream() throws IOException { throw new IOException("no entry name specified"); } else { if (jarEntry == null) { - throw new FileNotFoundException("JAR entry " + entryName + - " not found in " + - jarFile.getName()); + throw new FileNotFoundException( + formatMsg("JAR entry %s not found in jar file %s", + filterJarName(entryName), + filterJarName(jarFile.getName()))); } result = new JarURLInputStream (jarFile.getInputStream(jarEntry)); } diff --git a/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java b/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java index 95bc2179a31..51a88cb229d 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java +++ b/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java index 0e6ca6c3dcd..565c393c2a0 100644 --- a/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ abstract class AsynchronousServerSocketChannelImpl AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) { super(group.provider()); - this.fd = Net.serverSocket(true); + this.fd = Net.serverSocket(); } @Override diff --git a/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java index e08a873d73d..c53aca8b1c7 100644 --- a/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java @@ -88,7 +88,7 @@ abstract class AsynchronousSocketChannelImpl throws IOException { super(group.provider()); - this.fd = Net.socket(true); + this.fd = Net.socket(); this.state = ST_UNCONNECTED; } 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 4930e1447a3..44b05f97472 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,8 @@ import java.util.concurrent.locks.ReentrantLock; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static jdk.internal.util.Exceptions.formatMsg; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; /** * A multicast datagram socket based on a datagram channel. @@ -490,7 +492,8 @@ public void setInterface(InetAddress inf) throws SocketException { NetworkInterface ni = NetworkInterface.getByInetAddress(inf); if (ni == null) { String address = inf.getHostAddress(); - throw new SocketException("No network interface with address " + address); + throw new SocketException(formatMsg("No network interface found with address %s", + filterNonSocketInfo(address))); } synchronized (outgoingInterfaceLock) { // set interface and update cached values 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 72de217a83c..240405c2f7c 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -264,19 +264,11 @@ private int implRead(ByteBuffer dst) throws IOException { private int traceImplRead(ByteBuffer dst) throws IOException { int bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); bytesRead = implRead(dst); } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { - if (bytesRead < 0) { - FileReadEvent.commit(start, duration, path, 0L, true); - } else { - FileReadEvent.commit(start, duration, path, bytesRead, false); - } - } + FileReadEvent.offer(start, path, bytesRead); } return bytesRead; } @@ -326,19 +318,11 @@ private long implRead(ByteBuffer[] dsts, int offset, int length) private long traceImplRead(ByteBuffer[] dsts, int offset, int length) throws IOException { long bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); bytesRead = implRead(dsts, offset, length); } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { - if (bytesRead < 0) { - FileReadEvent.commit(start, duration, path, 0L, true); - } else { - FileReadEvent.commit(start, duration, path, bytesRead, false); - } - } + FileReadEvent.offer(start, path, bytesRead); } return bytesRead; } @@ -385,16 +369,11 @@ private int implWrite(ByteBuffer src) throws IOException { private int traceImplWrite(ByteBuffer src) throws IOException { int bytesWritten = 0; - long start = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); bytesWritten = implWrite(src); } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { - long bytes = bytesWritten > 0 ? bytesWritten : 0; - FileWriteEvent.commit(start, duration, path, bytes); - } + FileWriteEvent.offer(start, path, bytesWritten); } return bytesWritten; } @@ -441,16 +420,11 @@ private long implWrite(ByteBuffer[] srcs, int offset, int length) throws IOExcep private long traceImplWrite(ByteBuffer[] srcs, int offset, int length) throws IOException { long bytesWritten = 0; - long start = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); bytesWritten = implWrite(srcs, offset, length); } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { - long bytes = bytesWritten > 0 ? bytesWritten : 0; - FileWriteEvent.commit(start, duration, path, bytes); - } + FileWriteEvent.offer(start, path, bytesWritten); } return bytesWritten; } @@ -1199,19 +1173,11 @@ private int implRead(ByteBuffer dst, long position) throws IOException { private int traceImplRead(ByteBuffer dst, long position) throws IOException { int bytesRead = 0; - long start = 0; + long start = FileReadEvent.timestamp(); try { - start = FileReadEvent.timestamp(); bytesRead = implRead(dst, position); } finally { - long duration = FileReadEvent.timestamp() - start; - if (FileReadEvent.shouldCommit(duration)) { - if (bytesRead < 0) { - FileReadEvent.commit(start, duration, path, 0L, true); - } else { - FileReadEvent.commit(start, duration, path, bytesRead, false); - } - } + FileReadEvent.offer(start, path, bytesRead); } return bytesRead; } @@ -1271,16 +1237,11 @@ private int implWrite(ByteBuffer src, long position) throws IOException { private int traceImplWrite(ByteBuffer src, long position) throws IOException { int bytesWritten = 0; - long start = 0; + long start = FileWriteEvent.timestamp(); try { - start = FileWriteEvent.timestamp(); bytesWritten = implWrite(src, position); } finally { - long duration = FileWriteEvent.timestamp() - start; - if (FileWriteEvent.shouldCommit(duration)) { - long bytes = bytesWritten > 0 ? bytesWritten : 0; - FileWriteEvent.commit(start, duration, path, bytes); - } + FileWriteEvent.offer(start, path, bytesWritten); } return bytesWritten; } 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 d86d6decb14..ad1aedc2668 100644 --- a/src/java.base/share/classes/sun/nio/ch/IOUtil.java +++ b/src/java.base/share/classes/sun/nio/ch/IOUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -484,7 +484,7 @@ static void acquireScope(ByteBuffer bb, boolean async) { NIO_ACCESS.acquireSession(bb); } - private static void releaseScope(ByteBuffer bb) { + static void releaseScope(ByteBuffer bb) { try { NIO_ACCESS.releaseSession(bb); } catch (Exception e) { diff --git a/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java b/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java index 1c78e45a2d8..6d551462ce8 100644 --- a/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java +++ b/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -79,6 +79,7 @@ protected IOVecWrapper[] initialValue() { protected void threadTerminated(IOVecWrapper[] cache) { IOVecWrapper wrapper = cache[0]; if (wrapper != null) { + cache[0] = null; wrapper.vecArray.free(); } } diff --git a/src/java.base/share/classes/sun/nio/ch/Net.java b/src/java.base/share/classes/sun/nio/ch/Net.java index 5c922aff676..5cd14a8b301 100644 --- a/src/java.base/share/classes/sun/nio/ch/Net.java +++ b/src/java.base/share/classes/sun/nio/ch/Net.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -470,8 +470,8 @@ private static boolean isFastTcpLoopbackRequested() { private static native boolean canUseIPv6OptionsWithIPv4LocalAddress0(); - static FileDescriptor socket(boolean stream) throws IOException { - return socket(UNSPEC, stream); + static FileDescriptor socket() throws IOException { + return socket(UNSPEC, true); } static FileDescriptor socket(ProtocolFamily family, boolean stream) throws IOException { @@ -480,14 +480,14 @@ static FileDescriptor socket(ProtocolFamily family, boolean stream) throws IOExc return IOUtil.newFD(socket0(preferIPv6, stream, false, FAST_LOOPBACK)); } - static FileDescriptor serverSocket(boolean stream) { - return serverSocket(UNSPEC, stream); + static FileDescriptor serverSocket() { + return serverSocket(UNSPEC); } - static FileDescriptor serverSocket(ProtocolFamily family, boolean stream) { + static FileDescriptor serverSocket(ProtocolFamily family) { boolean preferIPv6 = isIPv6Available() && (family != StandardProtocolFamily.INET); - return IOUtil.newFD(socket0(preferIPv6, stream, true, FAST_LOOPBACK)); + return IOUtil.newFD(socket0(preferIPv6, true, true, FAST_LOOPBACK)); } // Due to oddities SO_REUSEADDR on Windows reuse is ignored diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java index 96d6e1e1db7..dd81b356738 100644 --- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java @@ -58,10 +58,12 @@ import sun.net.NetHooks; import sun.net.PlatformSocketImpl; import sun.net.ext.ExtendedSocketOptions; -import sun.net.util.SocketExceptions; +import jdk.internal.util.Exceptions; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.NANOSECONDS; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; /** * NIO based SocketImpl. @@ -100,8 +102,6 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp private static final int ST_CLOSED = 5; private volatile int state; // need stateLock to change - // set by SocketImpl.create, protected by stateLock - private boolean stream; private Cleanable cleaner; // set to true when the socket is in non-blocking mode @@ -288,7 +288,7 @@ private int timedRead(FileDescriptor fd, byte[] b, int off, int len, long nanos) * @throws SocketException if the socket is closed or a socket I/O error occurs * @throws SocketTimeoutException if the read timeout elapses */ - private int implRead(byte[] b, int off, int len) throws IOException { + private int implRead(byte[] b, int off, int len, long remainingNanos) throws IOException { int n = 0; FileDescriptor fd = beginRead(); try { @@ -296,11 +296,10 @@ private int implRead(byte[] b, int off, int len) throws IOException { throw new SocketException("Connection reset"); if (isInputClosed) return -1; - int timeout = this.timeout; - configureNonBlockingIfNeeded(fd, timeout > 0); - if (timeout > 0) { + configureNonBlockingIfNeeded(fd, remainingNanos > 0); + if (remainingNanos > 0) { // read with timeout - n = timedRead(fd, b, off, len, MILLISECONDS.toNanos(timeout)); + n = timedRead(fd, b, off, len, remainingNanos); } else { // read, no timeout n = tryRead(fd, b, off, len); @@ -335,14 +334,24 @@ private int read(byte[] b, int off, int len) throws IOException { if (len == 0) { return 0; } else { - readLock.lock(); + long remainingNanos = 0; + int timeout = this.timeout; + if (timeout > 0) { + remainingNanos = tryLock(readLock, timeout, MILLISECONDS); + if (remainingNanos <= 0) { + assert !readLock.isHeldByCurrentThread(); + throw new SocketTimeoutException("Read timed out"); + } + } else { + readLock.lock(); + } try { // emulate legacy behavior to return -1, even if socket is closed if (readEOF) return -1; // read up to MAX_BUFFER_SIZE bytes int size = Math.min(len, MAX_BUFFER_SIZE); - int n = implRead(b, off, size); + int n = implRead(b, off, size, remainingNanos); if (n == -1) readEOF = true; return n; @@ -451,19 +460,20 @@ private void write(byte[] b, int off, int len) throws IOException { */ @Override protected void create(boolean stream) throws IOException { + if (!stream) { + throw new IOException("Datagram socket creation not supported"); + } synchronized (stateLock) { if (state != ST_NEW) throw new IOException("Already created"); FileDescriptor fd; if (server) { - assert stream; - fd = Net.serverSocket(true); + fd = Net.serverSocket(); } else { - fd = Net.socket(stream); + fd = Net.socket(); } - Runnable closer = closerFor(fd, stream); + Runnable closer = closerFor(fd); this.fd = fd; - this.stream = stream; this.cleaner = CleanerFactory.cleaner().register(this, closer); this.state = ST_UNCONNECTED; } @@ -555,7 +565,8 @@ protected void connect(SocketAddress remote, int millis) throws IOException { throw new IOException("Unsupported address type"); InetSocketAddress isa = (InetSocketAddress) remote; if (isa.isUnresolved()) { - throw new UnknownHostException(isa.getHostName()); + throw new UnknownHostException( + formatMsg(filterNonSocketInfo(isa.getHostName()))); } InetAddress address = isa.getAddress(); @@ -605,7 +616,7 @@ protected void connect(SocketAddress remote, int millis) throws IOException { assert Thread.currentThread().isVirtual(); throw new SocketException("Closed by interrupt"); } else { - throw SocketExceptions.of(ioe, isa); + throw Exceptions.ioException(ioe, isa); } } } @@ -653,8 +664,6 @@ protected void listen(int backlog) throws IOException { private FileDescriptor beginAccept() throws SocketException { synchronized (stateLock) { ensureOpen(); - if (!stream) - throw new SocketException("Not a stream socket"); if (localport == 0) throw new SocketException("Not bound"); readerThread = NativeThread.current(); @@ -764,10 +773,9 @@ protected void accept(SocketImpl si) throws IOException { } // set the fields - Runnable closer = closerFor(newfd, true); + Runnable closer = closerFor(newfd); synchronized (nsi.stateLock) { nsi.fd = newfd; - nsi.stream = true; nsi.cleaner = CleanerFactory.cleaner().register(nsi, closer); nsi.localport = localAddress.getPort(); nsi.address = isaa[0].getAddress(); @@ -1187,24 +1195,14 @@ protected void sendUrgentData(int data) throws IOException { /** * Returns an action to close the given file descriptor. */ - private static Runnable closerFor(FileDescriptor fd, boolean stream) { - if (stream) { - return () -> { - try { - nd.close(fd); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - }; - } else { - return () -> { - try { - nd.close(fd); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - }; - } + private static Runnable closerFor(FileDescriptor fd) { + return () -> { + try { + nd.close(fd); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + }; } /** diff --git a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index 62a4b9a7cf8..b8e25b23b69 100644 --- a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -132,7 +132,7 @@ class ServerSocketChannelImpl if (family == UNIX) { this.fd = UnixDomainSockets.socket(); } else { - this.fd = Net.serverSocket(family, true); + this.fd = Net.serverSocket(family); } this.fdVal = IOUtil.fdVal(fd); } 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 d8ed1cfb675..bf777ed23e4 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java @@ -40,6 +40,9 @@ import java.util.Set; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static jdk.internal.util.Exceptions.filterNonSocketInfo; +import static jdk.internal.util.Exceptions.formatMsg; + // Make a socket channel look like a socket. // @@ -92,7 +95,8 @@ public void connect(SocketAddress remote, int timeout) throws IOException { if (sc.isConnected()) throw new SocketException("Already connected"); close(); - throw new UnknownHostException(remote.toString()); + throw new UnknownHostException( + formatMsg(filterNonSocketInfo(remote.toString()))); } if (timeout < 0) throw new IllegalArgumentException("connect: timeout can't be negative"); 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 0980592abab..c1241a51f85 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -64,7 +64,7 @@ import sun.net.ConnectionResetException; import sun.net.NetHooks; import sun.net.ext.ExtendedSocketOptions; -import sun.net.util.SocketExceptions; +import jdk.internal.util.Exceptions; /** * An implementation of SocketChannels @@ -975,7 +975,7 @@ public boolean connect(SocketAddress remote) throws IOException { } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, sa); + throw Exceptions.ioException(ioe, sa); } } @@ -1065,7 +1065,7 @@ public boolean finishConnect() throws IOException { } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, remoteAddress); + throw Exceptions.ioException(ioe, remoteAddress); } } @@ -1313,7 +1313,7 @@ void blockingConnect(SocketAddress remote, long nanos) throws IOException { } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, sa); + throw Exceptions.ioException(ioe, sa); } } 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 128694cb52d..66c9fa40f2e 100644 --- a/src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java +++ b/src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import java.io.FileDescriptor; import java.io.IOException; import java.net.BindException; -import java.net.NetPermission; import java.net.SocketAddress; import java.net.UnixDomainSocketAddress; import java.nio.channels.UnsupportedAddressTypeException; @@ -52,9 +51,6 @@ private static class UnnamedHolder { private static final String tempDir = UnixDomainSocketsUtil.getTempDir(); - private static final NetPermission accessUnixDomainSocket = - new NetPermission("accessUnixDomainSocket"); - static boolean isSupported() { return supported; } diff --git a/src/java.base/share/classes/sun/nio/cs/CESU_8.java b/src/java.base/share/classes/sun/nio/cs/CESU_8.java index f1fc69703c2..a9a25e151ad 100644 --- a/src/java.base/share/classes/sun/nio/cs/CESU_8.java +++ b/src/java.base/share/classes/sun/nio/cs/CESU_8.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -446,7 +446,7 @@ private CoderResult encodeArrayLoop(CharBuffer src, int dl = dst.arrayOffset() + dst.limit(); // Handle ASCII-only prefix - int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); + int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); sp += n; dp += n; @@ -551,7 +551,7 @@ public int encode(char[] sa, int sp, int len, byte[] da) { int dp = 0; // Handle ASCII-only prefix - int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(len, da.length)); + int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(len, da.length)); sp += n; dp += n; diff --git a/src/java.base/share/classes/sun/nio/cs/DoubleByte.java b/src/java.base/share/classes/sun/nio/cs/DoubleByte.java index 2978a6f5dec..4738f51515b 100644 --- a/src/java.base/share/classes/sun/nio/cs/DoubleByte.java +++ b/src/java.base/share/classes/sun/nio/cs/DoubleByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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,7 @@ import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; -import sun.nio.cs.Surrogate; -import sun.nio.cs.ArrayDecoder; -import sun.nio.cs.ArrayEncoder; + import static sun.nio.cs.CharsetMapping.*; /* @@ -602,7 +600,7 @@ protected CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { try { if (isASCIICompatible) { - int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(dl - dp, sl - sp)); + int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(dl - dp, sl - sp)); sp += n; dp += n; } @@ -688,7 +686,7 @@ public int encode(char[] src, int sp, int len, byte[] dst) { int dp = 0; int sl = sp + len; if (isASCIICompatible) { - int n = JLA.encodeASCII(src, sp, dst, dp, len); + int n = JLA.uncheckedEncodeASCII(src, sp, dst, dp, len); sp += n; dp += n; } diff --git a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java index 3e86f104fac..39215bfa93d 100644 --- a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java +++ b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.base/share/classes/sun/nio/cs/SingleByte.java b/src/java.base/share/classes/sun/nio/cs/SingleByte.java index 748659b323f..d802cc85aa8 100644 --- a/src/java.base/share/classes/sun/nio/cs/SingleByte.java +++ b/src/java.base/share/classes/sun/nio/cs/SingleByte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; -import java.util.Arrays; + import static sun.nio.cs.CharsetMapping.*; public class SingleByte @@ -217,7 +217,7 @@ private CoderResult encodeArrayLoop(CharBuffer src, ByteBuffer dst) { int len = Math.min(dl - dp, sl - sp); if (isASCIICompatible) { - int n = JLA.encodeASCII(sa, sp, da, dp, len); + int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, len); sp += n; dp += n; len -= n; diff --git a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java index 8ff79d497fb..bb84ab1bd4b 100644 --- a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java +++ b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -159,7 +159,7 @@ private CoderResult encodeArrayLoop(CharBuffer src, assert (dp <= dl); dp = (dp <= dl ? dp : dl); - int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); + int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); sp += n; dp += n; diff --git a/src/java.base/share/classes/sun/nio/cs/UTF_8.java b/src/java.base/share/classes/sun/nio/cs/UTF_8.java index a27b4690f59..54e479f838a 100644 --- a/src/java.base/share/classes/sun/nio/cs/UTF_8.java +++ b/src/java.base/share/classes/sun/nio/cs/UTF_8.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; /* Legal UTF-8 Byte Sequences * @@ -453,7 +452,7 @@ private CoderResult encodeArrayLoop(CharBuffer src, int dl = dst.arrayOffset() + dst.limit(); // Handle ASCII-only prefix - int n = JLA.encodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); + int n = JLA.uncheckedEncodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp)); sp += n; dp += n; diff --git a/src/java.base/share/classes/sun/security/ec/ECKeyFactory.java b/src/java.base/share/classes/sun/security/ec/ECKeyFactory.java index 85d4d0bf263..2530425fbd4 100644 --- a/src/java.base/share/classes/sun/security/ec/ECKeyFactory.java +++ b/src/java.base/share/classes/sun/security/ec/ECKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.security.ec; +import sun.security.pkcs.PKCS8Key; + import java.security.*; import java.security.interfaces.*; import java.security.spec.*; @@ -84,8 +86,7 @@ public ECKeyFactory() { * To be used by future Java ECDSA and ECDH implementations. */ public static ECKey toECKey(Key key) throws InvalidKeyException { - if (key instanceof ECKey) { - ECKey ecKey = (ECKey)key; + if (key instanceof ECKey ecKey) { checkKey(ecKey); return ecKey; } else { @@ -147,7 +148,7 @@ protected Key engineTranslateKey(Key key) throws InvalidKeyException { // see JCA doc protected PublicKey engineGeneratePublic(KeySpec keySpec) - throws InvalidKeySpecException { + throws InvalidKeySpecException { try { return implGeneratePublic(keySpec); } catch (InvalidKeySpecException e) { @@ -159,7 +160,7 @@ protected PublicKey engineGeneratePublic(KeySpec keySpec) // see JCA doc protected PrivateKey engineGeneratePrivate(KeySpec keySpec) - throws InvalidKeySpecException { + throws InvalidKeySpecException { try { return implGeneratePrivate(keySpec); } catch (InvalidKeySpecException e) { @@ -171,19 +172,13 @@ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) // internal implementation of translateKey() for public keys. See JCA doc private PublicKey implTranslatePublicKey(PublicKey key) - throws InvalidKeyException { - if (key instanceof ECPublicKey) { - if (key instanceof ECPublicKeyImpl) { - return key; - } - ECPublicKey ecKey = (ECPublicKey)key; - return new ECPublicKeyImpl( - ecKey.getW(), - ecKey.getParams() - ); + throws InvalidKeyException { + if (key instanceof ECPublicKeyImpl) { + return key; + } else if (key instanceof ECPublicKey ecKey) { + return new ECPublicKeyImpl(ecKey.getW(), ecKey.getParams()); } else if ("X.509".equals(key.getFormat())) { - byte[] encoded = key.getEncoded(); - return new ECPublicKeyImpl(encoded); + return new ECPublicKeyImpl(key.getEncoded()); } else { throw new InvalidKeyException("Public keys must be instance " + "of ECPublicKey or have X.509 encoding"); @@ -192,16 +187,11 @@ private PublicKey implTranslatePublicKey(PublicKey key) // internal implementation of translateKey() for private keys. See JCA doc private PrivateKey implTranslatePrivateKey(PrivateKey key) - throws InvalidKeyException { - if (key instanceof ECPrivateKey) { - if (key instanceof ECPrivateKeyImpl) { - return key; - } - ECPrivateKey ecKey = (ECPrivateKey)key; - return new ECPrivateKeyImpl( - ecKey.getS(), - ecKey.getParams() - ); + throws InvalidKeyException { + if (key instanceof ECPrivateKeyImpl) { + return key; + } else if (key instanceof ECPrivateKey ecKey) { + return new ECPrivateKeyImpl(ecKey.getS(), ecKey.getParams()); } else if ("PKCS#8".equals(key.getFormat())) { byte[] encoded = key.getEncoded(); try { @@ -209,52 +199,58 @@ private PrivateKey implTranslatePrivateKey(PrivateKey key) } finally { Arrays.fill(encoded, (byte)0); } - } else { - throw new InvalidKeyException("Private keys must be instance " - + "of ECPrivateKey or have PKCS#8 encoding"); } + + throw new InvalidKeyException("Private keys must be instance " + + "of ECPrivateKey or have PKCS#8 encoding"); } // internal implementation of generatePublic. See JCA doc private PublicKey implGeneratePublic(KeySpec keySpec) - throws GeneralSecurityException { - if (keySpec instanceof X509EncodedKeySpec) { - X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec; - return new ECPublicKeyImpl(x509Spec.getEncoded()); - } else if (keySpec instanceof ECPublicKeySpec) { - ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec; - return new ECPublicKeyImpl( - ecSpec.getW(), - ecSpec.getParams() - ); - } else { - throw new InvalidKeySpecException("Only ECPublicKeySpec " - + "and X509EncodedKeySpec supported for EC public keys"); - } + throws GeneralSecurityException { + return switch (keySpec) { + case X509EncodedKeySpec x -> new ECPublicKeyImpl(x.getEncoded()); + case ECPublicKeySpec e -> + new ECPublicKeyImpl(e.getW(), e.getParams()); + case PKCS8EncodedKeySpec p8 -> { + PKCS8Key p8key = new ECPrivateKeyImpl(p8.getEncoded()); + if (!p8key.hasPublicKey()) { + throw new InvalidKeySpecException("No public key found."); + } + yield new ECPublicKeyImpl(p8key.getPubKeyEncoded()); + } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; } // internal implementation of generatePrivate. See JCA doc private PrivateKey implGeneratePrivate(KeySpec keySpec) - throws GeneralSecurityException { - if (keySpec instanceof PKCS8EncodedKeySpec) { - PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec; - byte[] encoded = pkcsSpec.getEncoded(); - try { - return new ECPrivateKeyImpl(encoded); - } finally { - Arrays.fill(encoded, (byte) 0); + throws GeneralSecurityException { + return switch (keySpec) { + case PKCS8EncodedKeySpec p8 -> { + byte[] encoded = p8.getEncoded(); + try { + yield new ECPrivateKeyImpl(encoded); + } finally { + Arrays.fill(encoded, (byte) 0); + } } - } else if (keySpec instanceof ECPrivateKeySpec) { - ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec; - return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams()); - } else { - throw new InvalidKeySpecException("Only ECPrivateKeySpec " - + "and PKCS8EncodedKeySpec supported for EC private keys"); - } + case ECPrivateKeySpec e -> + new ECPrivateKeyImpl(e.getS(), e.getParams()); + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; } protected T engineGetKeySpec(Key key, Class keySpec) - throws InvalidKeySpecException { + throws InvalidKeySpecException { try { // convert key to one of our keys // this also verifies that the key is a valid EC key and ensures @@ -263,8 +259,7 @@ protected T engineGetKeySpec(Key key, Class keySpec) } catch (InvalidKeyException e) { throw new InvalidKeySpecException(e); } - if (key instanceof ECPublicKey) { - ECPublicKey ecKey = (ECPublicKey)key; + if (key instanceof ECPublicKey ecKey) { if (keySpec.isAssignableFrom(ECPublicKeySpec.class)) { return keySpec.cast(new ECPublicKeySpec( ecKey.getW(), diff --git a/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java b/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java index b1b8b2d188f..65c4f093f27 100644 --- a/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java +++ b/src/java.base/share/classes/sun/security/ec/ECPrivateKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,7 @@ import sun.security.util.*; import sun.security.x509.AlgorithmId; import sun.security.pkcs.PKCS8Key; +import sun.security.x509.X509Key; /** * Key implementation for EC private keys. @@ -73,6 +74,7 @@ public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey { private byte[] arrayS; // private value as a little-endian array @SuppressWarnings("serial") // Type of field is not Serializable private ECParameterSpec params; + private byte[] domainParams; //Currently unsupported /** * Construct a key from its encoding. Called by the ECKeyFactory. @@ -111,7 +113,7 @@ private void makeEncoding(byte[] s) throws InvalidKeyException { out.putOctetString(privBytes); Arrays.fill(privBytes, (byte) 0); DerValue val = DerValue.wrap(DerValue.tag_Sequence, out); - key = val.toByteArray(); + privKeyMaterial = val.toByteArray(); val.clear(); } @@ -133,7 +135,7 @@ private void makeEncoding(BigInteger s) throws InvalidKeyException { out.putOctetString(sOctets); Arrays.fill(sOctets, (byte) 0); DerValue val = DerValue.wrap(DerValue.tag_Sequence, out); - key = val.toByteArray(); + privKeyMaterial = val.toByteArray(); val.clear(); } @@ -153,64 +155,78 @@ public BigInteger getS() { return s; } - private byte[] getArrayS0() { + // Return the internal arrayS byte[], if arrayS is null generate it. + public byte[] getArrayS() { if (arrayS == null) { arrayS = ECUtil.sArray(getS(), params); } return arrayS; } - public byte[] getArrayS() { - return getArrayS0().clone(); - } - // see JCA doc public ECParameterSpec getParams() { return params; } + /** + * Parse the ASN.1 of the privateKey Octet + */ private void parseKeyBits() throws InvalidKeyException { + // Parse private key material from PKCS8Key.decode() try { - DerInputStream in = new DerInputStream(key); + DerInputStream in = new DerInputStream(privKeyMaterial); DerValue derValue = in.getDerValue(); if (derValue.tag != DerValue.tag_Sequence) { throw new IOException("Not a SEQUENCE"); } DerInputStream data = derValue.data; int version = data.getInteger(); - if (version != 1) { + if (version != V2) { throw new IOException("Version must be 1"); } byte[] privData = data.getOctetString(); ArrayUtil.reverse(privData); arrayS = privData; - while (data.available() != 0) { - DerValue value = data.getDerValue(); - if (value.isContextSpecific((byte) 0)) { - // ignore for now - } else if (value.isContextSpecific((byte) 1)) { - // ignore for now - } else { - throw new InvalidKeyException("Unexpected value: " + value); - } - } + + // Validate parameters stored from PKCS8Key.decode() AlgorithmParameters algParams = this.algid.getParameters(); if (algParams == null) { throw new InvalidKeyException("EC domain parameters must be " + "encoded in the algorithm identifier"); } params = algParams.getParameterSpec(ECParameterSpec.class); + + if (data.available() == 0) { + return; + } + + DerValue value = data.getDerValue(); + if (value.isContextSpecific((byte) 0)) { + domainParams = value.getDataBytes(); // Save DER sequence + if (data.available() == 0) { + return; + } + value = data.getDerValue(); + } + + if (value.isContextSpecific((byte) 1)) { + DerValue bits = value.withTag(DerValue.tag_BitString); + pubKeyEncoded = new X509Key(algid, + bits.data.getUnalignedBitString()).getEncoded(); + } else { + throw new InvalidKeyException("Unexpected value: " + value); + } + } catch (IOException | InvalidParameterSpecException e) { throw new InvalidKeyException("Invalid EC private key", e); } } - @Override public PublicKey calculatePublicKey() { ECParameterSpec ecParams = getParams(); ECOperations ops = ECOperations.forParameters(ecParams) .orElseThrow(ProviderException::new); - MutablePoint pub = ops.multiply(ecParams.getGenerator(), getArrayS0()); + MutablePoint pub = ops.multiply(ecParams.getGenerator(), getArrayS()); AffinePoint affPub = pub.asAffine(); ECPoint w = new ECPoint(affPub.getX().asBigInteger(), affPub.getY().asBigInteger()); diff --git a/src/java.base/share/classes/sun/security/ec/XDHKeyFactory.java b/src/java.base/share/classes/sun/security/ec/XDHKeyFactory.java index 3e2ced41236..c8fb6c0c11b 100644 --- a/src/java.base/share/classes/sun/security/ec/XDHKeyFactory.java +++ b/src/java.base/share/classes/sun/security/ec/XDHKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,9 @@ package sun.security.ec; -import java.security.KeyFactorySpi; -import java.security.Key; -import java.security.PublicKey; -import java.security.PrivateKey; -import java.security.InvalidKeyException; -import java.security.ProviderException; +import sun.security.pkcs.PKCS8Key; + +import java.security.*; import java.security.interfaces.XECKey; import java.security.interfaces.XECPrivateKey; import java.security.interfaces.XECPublicKey; @@ -147,54 +144,72 @@ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) private PublicKey generatePublicImpl(KeySpec keySpec) throws InvalidKeyException, InvalidKeySpecException { - if (keySpec instanceof X509EncodedKeySpec) { - X509EncodedKeySpec x509Spec = (X509EncodedKeySpec) keySpec; - XDHPublicKeyImpl result = - new XDHPublicKeyImpl(x509Spec.getEncoded()); - checkLockedParams(InvalidKeySpecException::new, - result.getParams()); - return result; - } else if (keySpec instanceof XECPublicKeySpec) { - XECPublicKeySpec publicKeySpec = (XECPublicKeySpec) keySpec; - XECParameters params = XECParameters.get( - InvalidKeySpecException::new, publicKeySpec.getParams()); - checkLockedParams(InvalidKeySpecException::new, params); - return new XDHPublicKeyImpl(params, publicKeySpec.getU()); - } else { - throw new InvalidKeySpecException( - "Only X509EncodedKeySpec and XECPublicKeySpec are supported"); - } + return switch (keySpec) { + case X509EncodedKeySpec x509Spec -> { + XDHPublicKeyImpl result = + new XDHPublicKeyImpl(x509Spec.getEncoded()); + checkLockedParams(InvalidKeySpecException::new, + result.getParams()); + yield result; + } + case XECPublicKeySpec publicKeySpec -> { + XECParameters params = XECParameters.get( + InvalidKeySpecException::new, publicKeySpec.getParams()); + checkLockedParams(InvalidKeySpecException::new, params); + yield new XDHPublicKeyImpl(params, publicKeySpec.getU()); + } + case PKCS8EncodedKeySpec p8 -> { + PKCS8Key p8key = new XDHPrivateKeyImpl(p8.getEncoded()); + if (!p8key.hasPublicKey()) { + throw new InvalidKeySpecException("No public key found."); + } + XDHPublicKeyImpl result = + new XDHPublicKeyImpl(p8key.getPubKeyEncoded()); + checkLockedParams(InvalidKeySpecException::new, + result.getParams()); + yield result; + } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; } private PrivateKey generatePrivateImpl(KeySpec keySpec) throws InvalidKeyException, InvalidKeySpecException { - if (keySpec instanceof PKCS8EncodedKeySpec) { - PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec) keySpec; - byte[] encoded = pkcsSpec.getEncoded(); - try { - XDHPrivateKeyImpl result = new XDHPrivateKeyImpl(encoded); - checkLockedParams(InvalidKeySpecException::new, + return switch (keySpec) { + case PKCS8EncodedKeySpec pkcsSpec -> { + byte[] encoded = pkcsSpec.getEncoded(); + try { + XDHPrivateKeyImpl result = new XDHPrivateKeyImpl(encoded); + checkLockedParams(InvalidKeySpecException::new, result.getParams()); - return result; - } finally { - Arrays.fill(encoded, (byte) 0); + yield result; + } finally { + Arrays.fill(encoded, (byte) 0); + } } - } else if (keySpec instanceof XECPrivateKeySpec) { - XECPrivateKeySpec privateKeySpec = (XECPrivateKeySpec) keySpec; - XECParameters params = XECParameters.get( - InvalidKeySpecException::new, privateKeySpec.getParams()); - checkLockedParams(InvalidKeySpecException::new, params); - byte[] scalar = privateKeySpec.getScalar(); - try { - return new XDHPrivateKeyImpl(params, scalar); - } finally { - Arrays.fill(scalar, (byte)0); + case XECPrivateKeySpec privateKeySpec -> { + XECParameters params = XECParameters.get( + InvalidKeySpecException::new, privateKeySpec.getParams()); + checkLockedParams(InvalidKeySpecException::new, params); + + byte[] scalar = privateKeySpec.getScalar(); + try { + yield new XDHPrivateKeyImpl(params, scalar); + } finally { + Arrays.fill(scalar, (byte) 0); + } } - } else { - throw new InvalidKeySpecException( - "Only PKCS8EncodedKeySpec and XECPrivateKeySpec supported"); - } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; } protected T engineGetKeySpec(Key key, Class keySpec) diff --git a/src/java.base/share/classes/sun/security/ec/XDHPrivateKeyImpl.java b/src/java.base/share/classes/sun/security/ec/XDHPrivateKeyImpl.java index dfc0d0f6cd3..416a3e10af4 100644 --- a/src/java.base/share/classes/sun/security/ec/XDHPrivateKeyImpl.java +++ b/src/java.base/share/classes/sun/security/ec/XDHPrivateKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ public final class XDHPrivateKeyImpl extends PKCS8Key implements XECPrivateKey { DerValue val = new DerValue(DerValue.tag_OctetString, k); try { - this.key = val.toByteArray(); + this.privKeyMaterial = val.toByteArray(); } finally { val.clear(); } @@ -67,7 +67,7 @@ public final class XDHPrivateKeyImpl extends PKCS8Key implements XECPrivateKey { InvalidKeyException::new, algid); paramSpec = new NamedParameterSpec(params.getName()); try { - DerInputStream derStream = new DerInputStream(key); + DerInputStream derStream = new DerInputStream(privKeyMaterial); k = derStream.getOctetString(); } catch (IOException ex) { throw new InvalidKeyException(ex); @@ -102,7 +102,6 @@ public Optional getScalar() { return Optional.of(getK()); } - @Override public PublicKey calculatePublicKey() { XECParameters params = paramSpec.getName().equalsIgnoreCase("X25519") ? XECParameters.X25519 diff --git a/src/java.base/share/classes/sun/security/ec/ed/EdDSAKeyFactory.java b/src/java.base/share/classes/sun/security/ec/ed/EdDSAKeyFactory.java index c282a34ef84..71ec14ba06f 100644 --- a/src/java.base/share/classes/sun/security/ec/ed/EdDSAKeyFactory.java +++ b/src/java.base/share/classes/sun/security/ec/ed/EdDSAKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,12 +25,9 @@ package sun.security.ec.ed; -import java.security.KeyFactorySpi; -import java.security.Key; -import java.security.PublicKey; -import java.security.PrivateKey; -import java.security.InvalidKeyException; -import java.security.ProviderException; +import sun.security.pkcs.PKCS8Key; + +import java.security.*; import java.security.interfaces.*; import java.security.spec.*; import java.util.Arrays; @@ -140,55 +137,68 @@ protected PrivateKey engineGeneratePrivate(KeySpec keySpec) private PublicKey generatePublicImpl(KeySpec keySpec) throws InvalidKeyException, InvalidKeySpecException { - if (keySpec instanceof X509EncodedKeySpec) { - X509EncodedKeySpec x509Spec = (X509EncodedKeySpec) keySpec; - EdDSAPublicKeyImpl result = - new EdDSAPublicKeyImpl(x509Spec.getEncoded()); - checkLockedParams(InvalidKeySpecException::new, - result.getParams()); - return result; - } else if (keySpec instanceof EdECPublicKeySpec) { - EdECPublicKeySpec publicKeySpec = (EdECPublicKeySpec) keySpec; - EdDSAParameters params = EdDSAParameters.get( - InvalidKeySpecException::new, publicKeySpec.getParams()); - checkLockedParams(InvalidKeySpecException::new, params); - return new EdDSAPublicKeyImpl(params, publicKeySpec.getPoint()); - } else { - throw new InvalidKeySpecException( - "Only X509EncodedKeySpec and EdECPublicKeySpec are supported"); - } + return switch (keySpec) { + case X509EncodedKeySpec x509Spec -> { + EdDSAPublicKeyImpl result = + new EdDSAPublicKeyImpl(x509Spec.getEncoded()); + checkLockedParams(InvalidKeySpecException::new, + result.getParams()); + yield result; + } + case EdECPublicKeySpec publicKeySpec -> { + EdDSAParameters params = EdDSAParameters.get( + InvalidKeySpecException::new, publicKeySpec.getParams()); + checkLockedParams(InvalidKeySpecException::new, params); + yield new EdDSAPublicKeyImpl(params, publicKeySpec.getPoint()); + } + case PKCS8EncodedKeySpec p8 -> { + PKCS8Key p8key = new EdDSAPrivateKeyImpl(p8.getEncoded()); + if (!p8key.hasPublicKey()) { + throw new InvalidKeySpecException("No public key found."); + } + yield new EdDSAPublicKeyImpl(p8key.getPubKeyEncoded()); + } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; } private PrivateKey generatePrivateImpl(KeySpec keySpec) throws InvalidKeyException, InvalidKeySpecException { - if (keySpec instanceof PKCS8EncodedKeySpec) { - PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec) keySpec; - byte[] encoded = pkcsSpec.getEncoded(); - try { - EdDSAPrivateKeyImpl result = + return switch (keySpec) { + case PKCS8EncodedKeySpec pkcsSpec -> { + byte[] encoded = pkcsSpec.getEncoded(); + try { + EdDSAPrivateKeyImpl result = new EdDSAPrivateKeyImpl(encoded); - checkLockedParams(InvalidKeySpecException::new, + checkLockedParams(InvalidKeySpecException::new, result.getParams()); - return result; - } finally { - Arrays.fill(encoded, (byte) 0); + yield result; + } finally { + Arrays.fill(encoded, (byte) 0); + } } - } else if (keySpec instanceof EdECPrivateKeySpec) { - EdECPrivateKeySpec privateKeySpec = (EdECPrivateKeySpec) keySpec; - EdDSAParameters params = EdDSAParameters.get( - InvalidKeySpecException::new, privateKeySpec.getParams()); - checkLockedParams(InvalidKeySpecException::new, params); - byte[] bytes = privateKeySpec.getBytes(); - try { - return new EdDSAPrivateKeyImpl(params, bytes); - } finally { - Arrays.fill(bytes, (byte)0); + case EdECPrivateKeySpec privateKeySpec -> { + EdDSAParameters params = EdDSAParameters.get( + InvalidKeySpecException::new, privateKeySpec.getParams()); + checkLockedParams(InvalidKeySpecException::new, params); + byte[] bytes = privateKeySpec.getBytes(); + try { + yield new EdDSAPrivateKeyImpl(params, bytes); + } finally { + Arrays.fill(bytes, (byte) 0); + } } - } else { - throw new InvalidKeySpecException( - "Only PKCS8EncodedKeySpec and EdECPrivateKeySpec supported"); - } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; } protected T engineGetKeySpec(Key key, Class keySpec) diff --git a/src/java.base/share/classes/sun/security/ec/ed/EdDSAPrivateKeyImpl.java b/src/java.base/share/classes/sun/security/ec/ed/EdDSAPrivateKeyImpl.java index 661ec9ed1b7..10b19c1ce53 100644 --- a/src/java.base/share/classes/sun/security/ec/ed/EdDSAPrivateKeyImpl.java +++ b/src/java.base/share/classes/sun/security/ec/ed/EdDSAPrivateKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ public final class EdDSAPrivateKeyImpl DerValue val = new DerValue(DerValue.tag_OctetString, h); try { - this.key = val.toByteArray(); + privKeyMaterial = val.toByteArray(); } finally { val.clear(); } @@ -71,7 +71,7 @@ public final class EdDSAPrivateKeyImpl paramSpec = new NamedParameterSpec(params.getName()); try { - DerInputStream derStream = new DerInputStream(key); + DerInputStream derStream = new DerInputStream(privKeyMaterial); h = derStream.getOctetString(); } catch (IOException ex) { throw new InvalidKeyException(ex); @@ -81,8 +81,8 @@ public final class EdDSAPrivateKeyImpl void checkLength(EdDSAParameters params) throws InvalidKeyException { - if (params.getKeyLength() != this.h.length) { - throw new InvalidKeyException("key length is " + this.h.length + + if (params.getKeyLength() != h.length) { + throw new InvalidKeyException("key length is " + h.length + ", key length must be " + params.getKeyLength()); } } diff --git a/src/java.base/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java b/src/java.base/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java index f87579ebb70..14abf9f30dc 100644 --- a/src/java.base/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java +++ b/src/java.base/share/classes/sun/security/internal/spec/TlsPrfParameterSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,7 @@ public class TlsPrfParameterSpec implements AlgorithmParameterSpec { private final SecretKey secret; + private final String keyAlg; private final String label; private final byte[] seed; private final int outputLength; @@ -72,13 +73,45 @@ public class TlsPrfParameterSpec implements AlgorithmParameterSpec { public TlsPrfParameterSpec(SecretKey secret, String label, byte[] seed, int outputLength, String prfHashAlg, int prfHashLength, int prfBlockSize) { - if ((label == null) || (seed == null)) { - throw new NullPointerException("label and seed must not be null"); + this(secret, "TlsPrf", label, seed, outputLength, prfHashAlg, + prfHashLength, prfBlockSize); + } + + /** + * Constructs a new TlsPrfParameterSpec. + * + * @param secret the secret to use in the calculation (or null) + * @param keyAlg the algorithm name for the generated {@code SecretKey} + * @param label the label to use in the calculation + * @param seed the random seed to use in the calculation + * @param outputLength the length in bytes of the output key to be produced + * @param prfHashAlg the name of the TLS PRF hash algorithm to use. + * Used only for TLS 1.2+. TLS1.1 and earlier use a fixed PRF. + * @param prfHashLength the output length of the TLS PRF hash algorithm. + * Used only for TLS 1.2+. + * @param prfBlockSize the input block size of the TLS PRF hash algorithm. + * Used only for TLS 1.2+. + * + * @throws NullPointerException if keyAlg, label or seed is null + * @throws IllegalArgumentException if outputLength is negative or + * keyAlg is empty + */ + public TlsPrfParameterSpec(SecretKey secret, String keyAlg, + String label, byte[] seed, int outputLength, + String prfHashAlg, int prfHashLength, int prfBlockSize) { + + if ((keyAlg == null) || (label == null) || (seed == null)) { + throw new NullPointerException( + "keyAlg, label or seed must not be null"); + } + if (keyAlg.isEmpty()) { + throw new IllegalArgumentException("keyAlg can not be empty"); } if (outputLength <= 0) { throw new IllegalArgumentException("outputLength must be positive"); } this.secret = secret; + this.keyAlg = keyAlg; this.label = label; this.seed = seed.clone(); this.outputLength = outputLength; @@ -87,6 +120,15 @@ public TlsPrfParameterSpec(SecretKey secret, String label, this.prfBlockSize = prfBlockSize; } + /** + * Returns the key algorithm name to use when generating the SecretKey. + * + * @return the key algorithm name + */ + public String getKeyAlg() { + return keyAlg; + } + /** * Returns the secret to use in the PRF calculation, or null if there is no * secret. diff --git a/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java b/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java index 88a2909cfac..a748433da87 100644 --- a/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java +++ b/src/java.base/share/classes/sun/security/pkcs/NamedPKCS8Key.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,7 @@ public NamedPKCS8Key(String fname, String pname, byte[] rawBytes) { DerValue val = new DerValue(DerValue.tag_OctetString, rawBytes); try { - this.key = val.toByteArray(); + this.privKeyMaterial = val.toByteArray(); } finally { val.clear(); } @@ -90,7 +90,7 @@ public NamedPKCS8Key(String fname, byte[] encoded) throws InvalidKeyException { if (algid.getEncodedParams() != null) { throw new InvalidKeyException("algorithm identifier has params"); } - rawBytes = new DerInputStream(key).getOctetString(); + rawBytes = new DerInputStream(privKeyMaterial).getOctetString(); } catch (IOException e) { throw new InvalidKeyException("Cannot parse input", e); } @@ -129,7 +129,7 @@ private void readObject(ObjectInputStream stream) @Override public void destroy() throws DestroyFailedException { Arrays.fill(rawBytes, (byte)0); - Arrays.fill(key, (byte)0); + Arrays.fill(privKeyMaterial, (byte)0); if (encodedKey != null) { Arrays.fill(encodedKey, (byte)0); } diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java b/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java index 4cb277b43a8..b7cc5e7057f 100644 --- a/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java +++ b/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * 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,22 +25,18 @@ package sun.security.pkcs; -import java.io.*; -import java.security.Key; -import java.security.KeyRep; -import java.security.PrivateKey; -import java.security.KeyFactory; -import java.security.MessageDigest; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; +import jdk.internal.access.SharedSecrets; +import sun.security.util.*; +import sun.security.x509.AlgorithmId; +import sun.security.x509.X509Key; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Arrays; -import jdk.internal.access.SharedSecrets; -import sun.security.x509.*; -import sun.security.util.*; - /** * Holds a PKCS#8 key, for example a private key * @@ -56,7 +52,7 @@ * ... * } * - * We support this format but do not parse attributes and publicKey now. + * We support this format but do not parse attributes. */ public class PKCS8Key implements PrivateKey, InternalPrivateKey { @@ -67,20 +63,29 @@ public class PKCS8Key implements PrivateKey, InternalPrivateKey { /* The algorithm information (name, parameters, etc). */ protected AlgorithmId algid; - /* The key bytes, without the algorithm information */ - protected byte[] key; + /* The private key OctetString for the algorithm subclasses to decode */ + protected byte[] privKeyMaterial; - /* The encoded for the key. Created on demand by encode(). */ + /* The pkcs8 encoding of this key(s). Created on demand. */ protected byte[] encodedKey; + /* The encoded x509 public key for v2 */ + protected byte[] pubKeyEncoded = null; + + /* ASN.1 Attributes */ + private byte[] attributes; + + /* PKCS8 version of the PEM */ + private int version; + /* The version for this key */ - private static final int V1 = 0; - private static final int V2 = 1; + public static final int V1 = 0; + public static final int V2 = 1; /** * Default constructor. Constructors in subclasses that create a new key * from its components require this. These constructors must initialize - * {@link #algid} and {@link #key}. + * {@link #algid} and {@link #privKeyMaterial}. */ protected PKCS8Key() { } @@ -91,7 +96,7 @@ protected PKCS8Key() { } * * This method is also used by {@link #parseKey} to create a raw key. */ - protected PKCS8Key(byte[] input) throws InvalidKeyException { + public PKCS8Key(byte[] input) throws InvalidKeyException { try { decode(new DerValue(input)); } catch (IOException e) { @@ -99,39 +104,70 @@ protected PKCS8Key(byte[] input) throws InvalidKeyException { } } + private PKCS8Key(byte[] privEncoding, byte[] pubEncoding) + throws InvalidKeyException { + this(privEncoding); + pubKeyEncoded = pubEncoding; + version = V2; + } + + public int getVersion() { + return version; + } + + /** + * Method for decoding PKCS8 v1 and v2 formats. Decoded values are stored + * in this class, key material remains in DER format for algorithm + * subclasses to decode. + */ private void decode(DerValue val) throws InvalidKeyException { try { if (val.tag != DerValue.tag_Sequence) { throw new InvalidKeyException("invalid key format"); } - int version = val.data.getInteger(); + // Support check for V1, aka 0, and V2, aka 1. + version = val.data.getInteger(); if (version != V1 && version != V2) { throw new InvalidKeyException("unknown version: " + version); } - algid = AlgorithmId.parse (val.data.getDerValue ()); - key = val.data.getOctetString(); + // Parse and store AlgorithmID + algid = AlgorithmId.parse(val.data.getDerValue()); + + // Store key material for subclasses to parse + privKeyMaterial = val.data.getOctetString(); - DerValue next; + // PKCS8 v1 typically ends here if (val.data.available() == 0) { return; } - next = val.data.getDerValue(); - if (next.isContextSpecific((byte)0)) { + + // OPTIONAL Context tag 0 for Attributes for PKCS8 v1 & v2 + // Uses 0xA0 context-specific/constructed or 0x80 + // context-specific/primitive. + DerValue v = val.data.getDerValue(); + if (v.isContextSpecific((byte)0)) { + attributes = v.getDataBytes(); // Save DER sequence if (val.data.available() == 0) { return; } - next = val.data.getDerValue(); + v = val.data.getDerValue(); } - if (next.isContextSpecific((byte)1)) { - if (version == V1) { - throw new InvalidKeyException("publicKey seen in v1"); + // OPTIONAL context tag 1 for Public Key for PKCS8 v2 only + if (version == V2) { + if (v.isContextSpecific((byte)1)) { + DerValue bits = v.withTag(DerValue.tag_BitString); + pubKeyEncoded = new X509Key(algid, + bits.getUnalignedBitString()).getEncoded(); + } else { + throw new InvalidKeyException("Invalid context tag"); } if (val.data.available() == 0) { return; } } + throw new InvalidKeyException("Extra bytes"); } catch (IOException e) { throw new InvalidKeyException("Unable to decode key", e); @@ -154,17 +190,29 @@ private void decode(DerValue val) throws InvalidKeyException { * handling, that specific need can be accommodated. * * @param encoded the DER-encoded SubjectPublicKeyInfo value - * @exception IOException on data format errors + * @exception InvalidKeyException on data format errors */ - public static PrivateKey parseKey(byte[] encoded) throws IOException { + public static PrivateKey parseKey(byte[] encoded) + throws InvalidKeyException { + return parseKey(encoded, null); + } + + public static PrivateKey parseKey(byte[] encoded, Provider provider) + throws InvalidKeyException { try { PKCS8Key rawKey = new PKCS8Key(encoded); - byte[] internal = rawKey.getEncodedInternal(); - PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(internal); + + PKCS8EncodedKeySpec pkcs8KeySpec = + new PKCS8EncodedKeySpec(rawKey.generateEncoding()); PrivateKey result = null; try { - result = KeyFactory.getInstance(rawKey.algid.getName()) + if (provider == null) { + result = KeyFactory.getInstance(rawKey.algid.getName()) .generatePrivate(pkcs8KeySpec); + } else { + result = KeyFactory.getInstance(rawKey.algid.getName(), + provider).generatePrivate(pkcs8KeySpec); + } } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { // Ignore and return raw key result = rawKey; @@ -176,8 +224,8 @@ public static PrivateKey parseKey(byte[] encoded) throws IOException { .clearEncodedKeySpec(pkcs8KeySpec); } return result; - } catch (InvalidKeyException e) { - throw new IOException("corrupt private key", e); + } catch (IOException e) { + throw new InvalidKeyException(e); } } @@ -188,10 +236,18 @@ public String getAlgorithm() { return algid.getName(); } + public byte[] getPubKeyEncoded() { + return pubKeyEncoded; + } + + public boolean hasPublicKey() { + return (pubKeyEncoded != null); + } + /** * Returns the algorithm ID to be used with this key. */ - public AlgorithmId getAlgorithmId () { + public AlgorithmId getAlgorithmId () { return algid; } @@ -200,7 +256,8 @@ public AlgorithmId getAlgorithmId () { * or {@code null} if an encoding error occurs. */ public byte[] getEncoded() { - return getEncodedInternal().clone(); + byte[] b = getEncodedInternal(); + return (b != null) ? b.clone() : null; } /** @@ -210,6 +267,25 @@ public String getFormat() { return "PKCS#8"; } + /** + * With a given encoded Public and Private key, generate and return a + * PKCS8v2 DER-encoded byte[]. + * + * @param pubKeyEncoded DER-encoded PublicKey + * @param privKeyEncoded DER-encoded PrivateKey + * @return DER-encoded byte array + * @throws IOException thrown on encoding failure + */ + public static byte[] getEncoded(byte[] pubKeyEncoded, byte[] privKeyEncoded) + throws IOException { + try { + return new PKCS8Key(privKeyEncoded, pubKeyEncoded). + generateEncoding(); + } catch (InvalidKeyException e) { + throw new IOException(e); + } + } + /** * DER-encodes this key as a byte array stored inside this object * and return it. @@ -218,17 +294,53 @@ public String getFormat() { */ private synchronized byte[] getEncodedInternal() { if (encodedKey == null) { - DerOutputStream tmp = new DerOutputStream(); - tmp.putInteger(V1); - algid.encode(tmp); - tmp.putOctetString(key); - DerValue out = DerValue.wrap(DerValue.tag_Sequence, tmp); - encodedKey = out.toByteArray(); - out.clear(); + try { + encodedKey = generateEncoding(); + } catch (IOException e) { + return null; + } } return encodedKey; } + private byte[] generateEncoding() throws IOException { + DerOutputStream out = new DerOutputStream(); + out.putInteger(version); + algid.encode(out); + out.putOctetString(privKeyMaterial); + + if (version == V2) { + if (attributes != null) { + out.writeImplicit( + DerValue.createTag((byte) (DerValue.TAG_CONTEXT | + DerValue.TAG_CONSTRUCT), false, (byte) 0), + new DerOutputStream().putOctetString(attributes)); + + } + + if (pubKeyEncoded != null) { + X509Key x = new X509Key(); + try { + x.decode(pubKeyEncoded); + } catch (InvalidKeyException e) { + throw new IOException(e); + } + + // X509Key x = X509Key.parse(pubKeyEncoded); + DerOutputStream pubOut = new DerOutputStream(); + pubOut.putUnalignedBitString(x.getKey()); + out.writeImplicit( + DerValue.createTag(DerValue.TAG_CONTEXT, false, + (byte) 1), pubOut); + } + } + + DerValue val = DerValue.wrap(DerValue.tag_Sequence, out); + encodedKey = val.toByteArray(); + val.clear(); + return encodedKey; + } + @java.io.Serial protected Object writeReplace() throws java.io.ObjectStreamException { return new KeyRep(KeyRep.Type.PRIVATE, @@ -298,6 +410,6 @@ public void clear() { if (encodedKey != null) { Arrays.fill(encodedKey, (byte)0); } - Arrays.fill(key, (byte)0); + Arrays.fill(privKeyMaterial, (byte)0); } } diff --git a/src/java.base/share/classes/sun/security/provider/DSAPrivateKey.java b/src/java.base/share/classes/sun/security/provider/DSAPrivateKey.java index e34fd3a6af1..a3357b1879c 100644 --- a/src/java.base/share/classes/sun/security/provider/DSAPrivateKey.java +++ b/src/java.base/share/classes/sun/security/provider/DSAPrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ public DSAPrivateKey(BigInteger x, BigInteger p, byte[] xbytes = x.toByteArray(); DerValue val = new DerValue(DerValue.tag_Integer, xbytes); - key = val.toByteArray(); + privKeyMaterial = val.toByteArray(); val.clear(); Arrays.fill(xbytes, (byte)0); } @@ -81,7 +81,7 @@ public DSAPrivateKey(BigInteger x, BigInteger p, public DSAPrivateKey(byte[] encoded) throws InvalidKeyException { super(encoded); try { - DerInputStream in = new DerInputStream(key); + DerInputStream in = new DerInputStream(privKeyMaterial); x = in.getBigInteger(); } catch (IOException e) { throw new InvalidKeyException(e.getMessage(), e); diff --git a/src/java.base/share/classes/sun/security/provider/KeyProtector.java b/src/java.base/share/classes/sun/security/provider/KeyProtector.java index 0faed9db737..384c28e2bf8 100644 --- a/src/java.base/share/classes/sun/security/provider/KeyProtector.java +++ b/src/java.base/share/classes/sun/security/provider/KeyProtector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package sun.security.provider; -import java.io.IOException; import java.security.SecureRandom; import java.security.*; import java.util.Arrays; @@ -300,8 +299,8 @@ public Key recover(EncryptedPrivateKeyInfo encrInfo) // which in turn parses the key material. try { return PKCS8Key.parseKey(plainKey); - } catch (IOException ioe) { - throw new UnrecoverableKeyException(ioe.getMessage()); + } catch (InvalidKeyException e) { + throw new UnrecoverableKeyException(e.getMessage()); } finally { Arrays.fill(plainKey, (byte)0); } diff --git a/src/java.base/share/classes/sun/security/provider/ML_DSA.java b/src/java.base/share/classes/sun/security/provider/ML_DSA.java index ff25eb527ef..af64ef399a8 100644 --- a/src/java.base/share/classes/sun/security/provider/ML_DSA.java +++ b/src/java.base/share/classes/sun/security/provider/ML_DSA.java @@ -541,21 +541,21 @@ public ML_DSA_KeyPair generateKeyPairInternal(byte[] randomBytes) { int[][][] keygenA = generateA(rho); //A is in NTT domain //Sample S1 and S2 - int[][] s1 = new int[mlDsa_l][ML_DSA_N]; - int[][] s2 = new int[mlDsa_k][ML_DSA_N]; + int[][] s1 = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + int[][] s2 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); //hash is reset before being used in sampleS1S2 sampleS1S2(s1, s2, hash, rhoPrime); //Compute t and tr mlDsaVectorNtt(s1); //s1 now in NTT domain - int[][] As1 = new int[mlDsa_k][ML_DSA_N]; + int[][] As1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); matrixVectorPointwiseMultiply(As1, keygenA, s1); mlDsaVectorInverseNtt(s1); //take s1 out of NTT domain mlDsaVectorInverseNtt(As1); int[][] t = vectorAddPos(As1, s2); - int[][] t0 = new int[mlDsa_k][ML_DSA_N]; - int[][] t1 = new int[mlDsa_k][ML_DSA_N]; + int[][] t0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] t1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); power2Round(t, t0, t1); //Encode PK and SK @@ -593,19 +593,19 @@ public ML_DSA_Signature signInternal(byte[] message, byte[] rnd, byte[] skBytes) hash.reset(); //Initialize vectors used in loop - int[][] z = new int[mlDsa_l][ML_DSA_N]; - boolean[][] h = new boolean[mlDsa_k][ML_DSA_N]; + int[][] z = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + boolean[][] h = booleanMatrixAlloc(mlDsa_k, ML_DSA_N); byte[] commitmentHash = new byte[lambda/4]; - int[][] y = new int[mlDsa_l][ML_DSA_N]; - int[][] yy = new int[mlDsa_l][ML_DSA_N]; - int[][] w = new int[mlDsa_k][ML_DSA_N]; - int[][] w0 = new int[mlDsa_k][ML_DSA_N]; - int[][] w1 = new int[mlDsa_k][ML_DSA_N]; - int[][] w_ct0 = new int[mlDsa_k][ML_DSA_N]; + int[][] y = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + int[][] yy = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + int[][] w = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] w0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] w1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] w_ct0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); int[] c = new int[ML_DSA_N]; - int[][] cs1 = new int[mlDsa_l][ML_DSA_N]; - int[][] cs2 = new int[mlDsa_k][ML_DSA_N]; - int[][] ct0 = new int[mlDsa_k][ML_DSA_N]; + int[][] cs1 = integerMatrixAlloc(mlDsa_l, ML_DSA_N); + int[][] cs2 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] ct0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); int kappa = 0; while (true) { @@ -621,7 +621,6 @@ public ML_DSA_Signature signInternal(byte[] message, byte[] rnd, byte[] skBytes) matrixVectorPointwiseMultiply(w, aHat, y); mlDsaVectorInverseNtt(w); //w is now in normal domain decompose(w, w0, w1); - //mlDsaVectorInverseNtt(y); //Get commitment hash hash.update(mu); @@ -693,13 +692,13 @@ public boolean verifyInternal(byte[] pkBytes, byte[] message, byte[] sigBytes) mlDsaVectorNtt(sig.response()); //Reconstruct signer's commitment - int[][] aHatZ = new int[mlDsa_k][ML_DSA_N]; + int[][] aHatZ = integerMatrixAlloc(mlDsa_k, ML_DSA_N); matrixVectorPointwiseMultiply(aHatZ, aHat, sig.response()); int[][] t1Hat = vectorConstMul(1 << ML_DSA_D, pk.t1()); mlDsaVectorNtt(t1Hat); - int[][] ct1 = new int[mlDsa_k][ML_DSA_N]; + int[][] ct1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); nttConstMultiply(ct1, cHat, t1Hat); int[][] wApprox = vectorSub(aHatZ, ct1, true); @@ -763,7 +762,7 @@ public void bitPack(int[][] vector, int bitsPerCoeff, int maxValue, //This is simpleBitUnpack from FIPS 204. Since it is only called on the //vector t1 we can optimize for that case public int[][] t1Unpack(byte[] v) { - int[][] t1 = new int[mlDsa_k][ML_DSA_N]; + int[][] t1 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); for (int i = 0; i < mlDsa_k; i++) { for (int j = 0; j < ML_DSA_N / 4; j++) { int tOffset = j*4; @@ -872,7 +871,7 @@ private void hintBitPack(boolean[][] h, byte[] buffer, int offset) { } private boolean[][] hintBitUnpack(byte[] y, int offset) { - boolean[][] h = new boolean[mlDsa_k][ML_DSA_N]; + boolean[][] h = booleanMatrixAlloc(mlDsa_k, ML_DSA_N); int idx = 0; for (int i = 0; i < mlDsa_k; i++) { int j = y[offset + omega + i]; @@ -956,18 +955,18 @@ public ML_DSA_PrivateKey skDecode(byte[] sk) { //Parse s1 int start = A_SEED_LEN + K_LEN + TR_LEN; int end = start + (32 * mlDsa_l * s1s2CoeffSize); - int[][] s1 = new int[mlDsa_l][ML_DSA_N]; + int[][] s1 = integerMatrixAlloc(mlDsa_l, ML_DSA_N); bitUnpack(s1, sk, start, mlDsa_l, eta, s1s2CoeffSize); //Parse s2 start = end; end += 32 * s1s2CoeffSize * mlDsa_k; - int[][] s2 = new int[mlDsa_k][ML_DSA_N]; + int[][] s2 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); bitUnpack(s2, sk, start, mlDsa_k, eta, s1s2CoeffSize); //Parse t0 start = end; - int[][] t0 = new int[mlDsa_k][ML_DSA_N]; + int[][] t0 = integerMatrixAlloc(mlDsa_k, ML_DSA_N); bitUnpack(t0, sk, start, mlDsa_k, 1 << 12, T0_COEFF_SIZE); return new ML_DSA_PrivateKey(rho, k, tr, s1, s2, t0); @@ -1002,7 +1001,7 @@ public ML_DSA_Signature sigDecode(byte[] sig) throws SignatureException { //Decode z int start = cSize; int end = start + zSize; - int[][] z = new int[mlDsa_l][ML_DSA_N]; + int[][] z = integerMatrixAlloc(mlDsa_l, ML_DSA_N); bitUnpack(z, sig, start, mlDsa_l, gamma1, gamma1Bits + 1); //Decode h @@ -1092,7 +1091,12 @@ private void sampleInBall(int[] c, byte[] rho) { } private int[][][] generateA(byte[] seed) { - int[][][] a = new int[mlDsa_k][mlDsa_l][]; + + // Manually do multidimensional array initialization for performance + int[][][] a = new int[mlDsa_k][][]; + for (int i = 0; i < mlDsa_k; i++) { + a[i] = new int[mlDsa_l][]; + } int nrPar = 2; int rhoLen = seed.length; @@ -1270,8 +1274,8 @@ private void decompose(int[][] input, int[][] lowPart, int[][] highPart) { } private int[][] highBits(int[][] input) { - int[][] lowPart = new int[mlDsa_k][ML_DSA_N]; - int[][] highPart = new int[mlDsa_k][ML_DSA_N]; + int[][] lowPart = integerMatrixAlloc(mlDsa_k, ML_DSA_N); + int[][] highPart = integerMatrixAlloc(mlDsa_k, ML_DSA_N); decompose(input, lowPart, highPart); return highPart; } @@ -1297,7 +1301,7 @@ private int makeHint(boolean[][] res, int[][] z, int[][] r) { private int[][] useHint(boolean[][] h, int[][] r) { int m = (ML_DSA_Q - 1) / (2*gamma2); int[][] lowPart = r; - int[][] highPart = new int[mlDsa_k][ML_DSA_N]; + int[][] highPart = integerMatrixAlloc(mlDsa_k, ML_DSA_N); decompose(r, lowPart, highPart); for (int i = 0; i < mlDsa_k; i++) { @@ -1482,7 +1486,7 @@ private void nttConstMultiply(int[][] res, int[] a, int[][] b) { } private int[][] vectorConstMul(int c, int[][] vec) { - int[][] res = new int[vec.length][vec[0].length]; + int[][] res = integerMatrixAlloc(vec.length, vec[0].length); for (int i = 0; i < vec.length; i++) { for (int j = 0; j < vec[0].length; j++) { res[i][j] = montMul(c, toMont(vec[i][j])); @@ -1496,7 +1500,7 @@ private int[][] vectorConstMul(int c, int[][] vec) { // The coefficients in the output will be nonnegative and less than MONT_Q int[][] vectorAddPos(int[][] vec1, int[][] vec2) { int dim = vec1.length; - int[][] result = new int[dim][ML_DSA_N]; + int[][] result = integerMatrixAlloc(dim, ML_DSA_N); for (int i = 0; i < dim; i++) { for (int m = 0; m < ML_DSA_N; m++) { int r = vec1[i][m] + vec2[i][m]; // -2 * MONT_Q < r < 2 * MONT_Q @@ -1568,4 +1572,22 @@ private static int montMul(int b, int c) { static int toMont(int a) { return montMul(a, MONT_R_SQUARE_MOD_Q); } + + // For multidimensional array initialization, manually allocating each entry is + // faster than doing the entire initialization in one go + static boolean[][] booleanMatrixAlloc(int first, int second) { + boolean[][] res = new boolean[first][]; + for (int i = 0; i < first; i++) { + res[i] = new boolean[second]; + } + return res; + } + + static int[][] integerMatrixAlloc(int first, int second) { + int[][] res = new int[first][]; + for (int i = 0; i < first; i++) { + res[i] = new int[second]; + } + return res; + } } 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 5f974bc6ea6..a096cac5f50 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -476,9 +476,28 @@ public byte[] squeeze(int numBytes) { public void reset() { engineReset(); + // engineReset (final in DigestBase) skips implReset if there's + // no update. This works for MessageDigest, since digest() always + // resets. But for XOF, squeeze() may be called without update, + // and still modifies state. So we always call implReset here + // to ensure correct behavior. + implReset(); } } + public static final class SHAKE128Hash extends SHA3 { + public SHAKE128Hash() { + super("SHAKE128-256", 32, (byte) 0x1F, 32); + } + } + + public static final class SHAKE256Hash extends SHA3 { + public SHAKE256Hash() { + super("SHAKE256-512", 64, (byte) 0x1F, 64); + } + } + + /* * The SHAKE128 extendable output function. */ 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 9f5e3447aeb..bfc702ec6a2 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * 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,10 @@ public final class SunEntries { "sun.security.provider.SHA3$SHA384", attrs); addWithAlias(p, "MessageDigest", "SHA3-512", "sun.security.provider.SHA3$SHA512", attrs); + addWithAlias(p, "MessageDigest", "SHAKE128-256", + "sun.security.provider.SHA3$SHAKE128Hash", attrs); + addWithAlias(p, "MessageDigest", "SHAKE256-512", + "sun.security.provider.SHA3$SHAKE256Hash", attrs); /* * Certificates diff --git a/src/java.base/share/classes/sun/security/provider/X509Factory.java b/src/java.base/share/classes/sun/security/provider/X509Factory.java index ad48c0c598d..1a8ace55fc8 100644 --- a/src/java.base/share/classes/sun/security/provider/X509Factory.java +++ b/src/java.base/share/classes/sun/security/provider/X509Factory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.io.*; +import java.security.PEMRecord; import java.security.cert.*; import java.util.*; @@ -36,6 +37,7 @@ import sun.security.provider.certpath.X509CertificatePair; import sun.security.util.Cache; import sun.security.util.DerValue; +import sun.security.util.Pem; import sun.security.x509.X509CRLImpl; import sun.security.x509.X509CertImpl; @@ -556,118 +558,20 @@ private static byte[] readOneBlock(InputStream is) throws IOException { readBERInternal(is, bout, c); return bout.toByteArray(); } else { - // Read BASE64 encoded data, might skip info at the beginning - ByteArrayOutputStream data = new ByteArrayOutputStream(); - - // Step 1: Read until header is found - int hyphen = (c=='-') ? 1: 0; // count of consequent hyphens - int last = (c=='-') ? -1: c; // the char before hyphen - while (true) { - int next = is.read(); - if (next == -1) { - // We accept useless data after the last block, - // say, empty lines. + try { + PEMRecord rec; + try { + rec = Pem.readPEM(is, (c == '-' ? true : false)); + } catch (EOFException e) { return null; } - if (next == '-') { - hyphen++; - } else { - hyphen = 0; - last = next; - } - if (hyphen == 5 && (last == -1 || last == '\r' || last == '\n')) { - break; - } - } - - // Step 2: Read the rest of header, determine the line end - int end; - StringBuilder header = new StringBuilder("-----"); - while (true) { - int next = is.read(); - if (next == -1) { - throw new IOException("Incomplete data"); - } - if (next == '\n') { - end = '\n'; - break; - } - if (next == '\r') { - next = is.read(); - if (next == -1) { - throw new IOException("Incomplete data"); - } - if (next == '\n') { - end = '\n'; - } else { - end = '\r'; - // Skip all white space chars - if (next != 9 && next != 10 && next != 13 && next != 32) { - data.write(next); - } - } - break; - } - header.append((char)next); - } - - // Step 3: Read the data - while (true) { - int next = is.read(); - if (next == -1) { - throw new IOException("Incomplete data"); - } - if (next != '-') { - // Skip all white space chars - if (next != 9 && next != 10 && next != 13 && next != 32) { - data.write(next); - } - } else { - break; - } - } - - // Step 4: Consume the footer - StringBuilder footer = new StringBuilder("-"); - while (true) { - int next = is.read(); - // Add next == '\n' for maximum safety, in case endline - // is not consistent. - if (next == -1 || next == end || next == '\n') { - break; - } - if (next != '\r') footer.append((char)next); - } - - checkHeaderFooter(header.toString().stripTrailing(), - footer.toString().stripTrailing()); - - try { - return Base64.getDecoder().decode(data.toByteArray()); + return Base64.getDecoder().decode(rec.content()); } catch (IllegalArgumentException e) { throw new IOException(e); } } } - private static void checkHeaderFooter(String header, - String footer) throws IOException { - if (header.length() < 16 || !header.startsWith("-----BEGIN ") || - !header.endsWith("-----")) { - throw new IOException("Illegal header: " + header); - } - if (footer.length() < 14 || !footer.startsWith("-----END ") || - !footer.endsWith("-----")) { - throw new IOException("Illegal footer: " + footer); - } - String headerType = header.substring(11, header.length()-5); - String footerType = footer.substring(9, footer.length()-5); - if (!headerType.equals(footerType)) { - throw new IOException("Header and footer do not match: " + - header + " " + footer); - } - } - /** * Read one BER data block. This method is aware of indefinite-length BER * encoding and will read all the subsections in a recursive way diff --git a/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java b/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java index c6fa1cf8980..0b8f2a0aded 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.security.spec.*; import java.util.Arrays; +import sun.security.pkcs.PKCS8Key; import sun.security.rsa.RSAUtil.KeyType; /** @@ -319,65 +320,83 @@ private PrivateKey translatePrivateKey(PrivateKey key) // internal implementation of generatePublic. See JCA doc private PublicKey generatePublic(KeySpec keySpec) throws GeneralSecurityException { - if (keySpec instanceof X509EncodedKeySpec) { - return RSAPublicKeyImpl.newKey(type, "X.509", - ((X509EncodedKeySpec)keySpec).getEncoded()); - } else if (keySpec instanceof RSAPublicKeySpec rsaSpec) { - try { - return new RSAPublicKeyImpl( - type, rsaSpec.getParams(), - rsaSpec.getModulus(), - rsaSpec.getPublicExponent() - ); - } catch (ProviderException e) { - throw new InvalidKeySpecException(e); + return switch (keySpec) { + case X509EncodedKeySpec x509 -> + RSAPublicKeyImpl.newKey(type, "X.509", x509.getEncoded()); + + case RSAPublicKeySpec rsaSpec -> { + try { + yield new RSAPublicKeyImpl( + type, rsaSpec.getParams(), + rsaSpec.getModulus(), + rsaSpec.getPublicExponent() + ); + } catch (ProviderException e) { + throw new InvalidKeySpecException(e); + } } - } else { - throw new InvalidKeySpecException("Only RSAPublicKeySpec " - + "and X509EncodedKeySpec supported for RSA public keys"); - } + case PKCS8EncodedKeySpec p8 -> { + PKCS8Key p8key = new PKCS8Key(p8.getEncoded()); + if (!p8key.hasPublicKey()) { + throw new InvalidKeySpecException("No public key found."); + } + yield RSAPublicKeyImpl.newKey(type, "X.509", + p8key.getPubKeyEncoded()); + } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; } // internal implementation of generatePrivate. See JCA doc private PrivateKey generatePrivate(KeySpec keySpec) throws GeneralSecurityException { - if (keySpec instanceof PKCS8EncodedKeySpec) { - byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); - try { - return RSAPrivateCrtKeyImpl.newKey(type, "PKCS#8", encoded); - } finally { - Arrays.fill(encoded, (byte)0); + return switch (keySpec) { + case PKCS8EncodedKeySpec p8 -> { + byte[] encoded = p8.getEncoded(); + try { + yield RSAPrivateCrtKeyImpl.newKey(type, "PKCS#8", encoded); + } finally { + Arrays.fill(encoded, (byte) 0); + } } - } else if (keySpec instanceof RSAPrivateCrtKeySpec rsaSpec) { - try { - return new RSAPrivateCrtKeyImpl( - type, rsaSpec.getParams(), - rsaSpec.getModulus(), - rsaSpec.getPublicExponent(), - rsaSpec.getPrivateExponent(), - rsaSpec.getPrimeP(), - rsaSpec.getPrimeQ(), - rsaSpec.getPrimeExponentP(), - rsaSpec.getPrimeExponentQ(), - rsaSpec.getCrtCoefficient() - ); - } catch (ProviderException e) { - throw new InvalidKeySpecException(e); + case RSAPrivateCrtKeySpec rsaSpec -> { + try { + yield new RSAPrivateCrtKeyImpl( + type, rsaSpec.getParams(), + rsaSpec.getModulus(), + rsaSpec.getPublicExponent(), + rsaSpec.getPrivateExponent(), + rsaSpec.getPrimeP(), + rsaSpec.getPrimeQ(), + rsaSpec.getPrimeExponentP(), + rsaSpec.getPrimeExponentQ(), + rsaSpec.getCrtCoefficient() + ); + } catch (ProviderException e) { + throw new InvalidKeySpecException(e); + } } - } else if (keySpec instanceof RSAPrivateKeySpec rsaSpec) { - try { - return new RSAPrivateKeyImpl( - type, rsaSpec.getParams(), - rsaSpec.getModulus(), - rsaSpec.getPrivateExponent() - ); - } catch (ProviderException e) { - throw new InvalidKeySpecException(e); + case RSAPrivateKeySpec rsaSpec -> { + try { + yield new RSAPrivateKeyImpl( + type, rsaSpec.getParams(), + rsaSpec.getModulus(), + rsaSpec.getPrivateExponent() + ); + } catch (ProviderException e) { + throw new InvalidKeySpecException(e); + } } - } else { - throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec " - + "and PKCS8EncodedKeySpec supported for RSA private keys"); - } + case null -> throw new InvalidKeySpecException( + "keySpec must not be null"); + default -> + throw new InvalidKeySpecException(keySpec.getClass().getName() + + " not supported."); + }; } protected T engineGetKeySpec(Key key, Class keySpec) 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 b6ef067d449..857914e6997 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,6 +69,7 @@ public final class RSAPrivateCrtKeyImpl private BigInteger qe; // prime exponent q private BigInteger coeff; // CRT coefficient + // RSA or RSA-PSS KeyType private final transient KeyType type; // Optional parameters associated with this RSA key @@ -101,7 +102,7 @@ public static RSAPrivateKey newKey(KeyType type, String format, } case "PKCS#1": try { - BigInteger[] comps = parseASN1(encoded); + BigInteger[] comps = parsePKCS1(encoded); if ((comps[1].signum() == 0) || (comps[3].signum() == 0) || (comps[4].signum() == 0) || (comps[5].signum() == 0) || (comps[6].signum() == 0) || (comps[7].signum() == 0)) { @@ -237,7 +238,7 @@ private RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException { Arrays.fill(nbytes[6], (byte) 0); Arrays.fill(nbytes[7], (byte) 0); DerValue val = DerValue.wrap(DerValue.tag_Sequence, out); - key = val.toByteArray(); + privKeyMaterial = val.toByteArray(); val.clear(); } @@ -304,7 +305,7 @@ public AlgorithmParameterSpec getParams() { // utility method for parsing DER encoding of RSA private keys in PKCS#1 // format as defined in RFC 8017 Appendix A.1.2, i.e. SEQ of version, n, // e, d, p, q, pe, qe, and coeff, and return the parsed components. - private static BigInteger[] parseASN1(byte[] raw) throws IOException { + private static BigInteger[] parsePKCS1(byte[] raw) throws IOException { DerValue derValue = new DerValue(raw); try { if (derValue.tag != DerValue.tag_Sequence) { @@ -337,7 +338,7 @@ private static BigInteger[] parseASN1(byte[] raw) throws IOException { private void parseKeyBits() throws InvalidKeyException { try { - BigInteger[] comps = parseASN1(key); + BigInteger[] comps = parsePKCS1(privKeyMaterial); n = comps[0]; e = comps[1]; d = comps[2]; @@ -351,6 +352,30 @@ private void parseKeyBits() throws InvalidKeyException { } } + /** + * With a given PKCS#1/slleay/OpenSSL old default RSA binary encoding, + * decode and return the proper RSA encoded KeySpec + * @param encoded RSA binary encoding + * @return KeySpec + * @throws InvalidKeyException on decoding failure + */ + public static KeySpec getKeySpec(byte[] encoded) throws + InvalidKeyException { + try { + BigInteger[] comps = parsePKCS1(encoded); + if ((comps[1].signum() == 0) || (comps[3].signum() == 0) || + (comps[4].signum() == 0) || (comps[5].signum() == 0) || + (comps[6].signum() == 0) || (comps[7].signum() == 0)) { + return new RSAPrivateKeySpec(comps[0], comps[2]); + } else { + return new RSAPrivateCrtKeySpec(comps[0], + comps[1], comps[2], comps[3], comps[4], comps[5], + comps[6], comps[7]); + } + } catch (IOException ioe) { + throw new InvalidKeyException("Invalid PKCS#1 encoding", ioe); + } + } /** * Restores the state of this object from the stream. *

                diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java b/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java index 91bc5f771d6..c67f934b0c3 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,7 +110,7 @@ public final class RSAPrivateKeyImpl extends PKCS8Key implements RSAPrivateKey { out.putInteger(0); out.putInteger(0); DerValue val = DerValue.wrap(DerValue.tag_Sequence, out); - key = val.toByteArray(); + privKeyMaterial = val.toByteArray(); val.clear(); } diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPublicKeyImpl.java b/src/java.base/share/classes/sun/security/rsa/RSAPublicKeyImpl.java index 5a0745604d2..47d95cdd6a0 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPublicKeyImpl.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPublicKeyImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,7 +82,7 @@ public static RSAPublicKey newKey(KeyType type, String format, break; case "PKCS#1": try { - BigInteger[] comps = parseASN1(encoded); + BigInteger[] comps = parsePKCS1(encoded); key = new RSAPublicKeyImpl(type, null, comps[0], comps[1]); } catch (IOException ioe) { throw new InvalidKeyException("Invalid PKCS#1 encoding", ioe); @@ -199,7 +199,7 @@ public AlgorithmParameterSpec getParams() { // utility method for parsing DER encoding of RSA public keys in PKCS#1 // format as defined in RFC 8017 Appendix A.1.1, i.e. SEQ of n and e. - private static BigInteger[] parseASN1(byte[] raw) throws IOException { + private static BigInteger[] parsePKCS1(byte[] raw) throws IOException { DerValue derValue = new DerValue(raw); if (derValue.tag != DerValue.tag_Sequence) { throw new IOException("Not a SEQUENCE"); @@ -218,7 +218,7 @@ private static BigInteger[] parseASN1(byte[] raw) throws IOException { */ protected void parseKeyBits() throws InvalidKeyException { try { - BigInteger[] comps = parseASN1(getKey().toByteArray()); + BigInteger[] comps = parsePKCS1(getKey().toByteArray()); n = comps[0]; e = comps[1]; } catch (IOException e) { diff --git a/src/java.base/share/classes/sun/security/ssl/ChangeCipherSpec.java b/src/java.base/share/classes/sun/security/ssl/ChangeCipherSpec.java index 8a49a9550f4..6da6f745691 100644 --- a/src/java.base/share/classes/sun/security/ssl/ChangeCipherSpec.java +++ b/src/java.base/share/classes/sun/security/ssl/ChangeCipherSpec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,22 +77,20 @@ public byte[] produce(ConnectionContext context, try { writeAuthenticator = Authenticator.valueOf( hc.negotiatedProtocol, ncs.macAlg, - tkd.getTrafficKey(hc.sslConfig.isClientMode ? + tkd.deriveKey(hc.sslConfig.isClientMode ? "clientMacKey" : "serverMacKey")); } catch (NoSuchAlgorithmException | InvalidKeyException e) { // unlikely throw new SSLException("Algorithm missing: ", e); } } - - SecretKey writeKey = - tkd.getTrafficKey(hc.sslConfig.isClientMode ? - "clientWriteKey" : "serverWriteKey"); - SecretKey writeIv = - tkd.getTrafficKey(hc.sslConfig.isClientMode ? - "clientWriteIv" : "serverWriteIv"); + SecretKey writeKey = tkd.deriveKey(hc.sslConfig.isClientMode ? + "clientWriteKey" : "serverWriteKey"); + byte[] writeIv = tkd.deriveData(hc.sslConfig.isClientMode ? + "clientWriteIv" : "serverWriteIv"); IvParameterSpec iv = (writeIv == null) ? null : - new IvParameterSpec(writeIv.getEncoded()); + new IvParameterSpec(writeIv); + SSLWriteCipher writeCipher; try { writeCipher = ncs.bulkCipher.createWriteCipher( @@ -173,7 +171,7 @@ public void consume(ConnectionContext context, try { readAuthenticator = Authenticator.valueOf( hc.negotiatedProtocol, ncs.macAlg, - tkd.getTrafficKey(hc.sslConfig.isClientMode ? + tkd.deriveKey(hc.sslConfig.isClientMode ? "serverMacKey" : "clientMacKey")); } catch (NoSuchAlgorithmException | InvalidKeyException e) { // unlikely @@ -181,14 +179,12 @@ public void consume(ConnectionContext context, } } - SecretKey readKey = - tkd.getTrafficKey(hc.sslConfig.isClientMode ? - "serverWriteKey" : "clientWriteKey"); - SecretKey readIv = - tkd.getTrafficKey(hc.sslConfig.isClientMode ? - "serverWriteIv" : "clientWriteIv"); + SecretKey readKey = tkd.deriveKey(hc.sslConfig.isClientMode ? + "serverWriteKey" : "clientWriteKey"); + byte[] readIv = tkd.deriveData(hc.sslConfig.isClientMode ? + "serverWriteIv" : "clientWriteIv"); IvParameterSpec iv = (readIv == null) ? null : - new IvParameterSpec(readIv.getEncoded()); + new IvParameterSpec(readIv); SSLReadCipher readCipher; try { readCipher = ncs.bulkCipher.createReadCipher( 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 019f1ad34d9..4a2063ded42 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1199,11 +1199,13 @@ enum HashAlg { final String name; final int hashLength; final int blockSize; + final String hkdfAlgorithm; HashAlg(String hashAlg, int hashLength, int blockSize) { this.name = hashAlg; this.hashLength = hashLength; this.blockSize = blockSize; + this.hkdfAlgorithm = "HKDF-" + hashAlg.replace("-", ""); } @Override 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 b8f83102840..fb5d6feef55 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -206,8 +206,7 @@ public byte[] produce(ConnectionContext context, "Not supported key exchange type"); } else { SSLKeyDerivation masterKD = ke.createKeyDerivation(chc); - SecretKey masterSecret = - masterKD.deriveKey("MasterSecret", null); + SecretKey masterSecret = masterKD.deriveKey("MasterSecret"); chc.handshakeSession.setMasterSecret(masterSecret); SSLTrafficKeyDerivation kd = @@ -302,8 +301,7 @@ public void consume(ConnectionContext context, // update the states SSLKeyDerivation masterKD = ke.createKeyDerivation(shc); - SecretKey masterSecret = - masterKD.deriveKey("MasterSecret", null); + SecretKey masterSecret = masterKD.deriveKey("MasterSecret"); shc.handshakeSession.setMasterSecret(masterSecret); SSLTrafficKeyDerivation kd = diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java index 0dcf5ec27b7..e1c1b1377ad 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -218,8 +218,7 @@ public byte[] produce(ConnectionContext context, "Not supported key exchange type"); } else { SSLKeyDerivation masterKD = ke.createKeyDerivation(chc); - SecretKey masterSecret = - masterKD.deriveKey("MasterSecret", null); + SecretKey masterSecret = masterKD.deriveKey("MasterSecret"); chc.handshakeSession.setMasterSecret(masterSecret); SSLTrafficKeyDerivation kd = @@ -338,8 +337,7 @@ public void consume(ConnectionContext context, // update the states SSLKeyDerivation masterKD = ke.createKeyDerivation(shc); - SecretKey masterSecret = - masterKD.deriveKey("MasterSecret", null); + SecretKey masterSecret = masterKD.deriveKey("MasterSecret"); shc.handshakeSession.setMasterSecret(masterSecret); SSLTrafficKeyDerivation kd = @@ -418,8 +416,7 @@ public byte[] produce(ConnectionContext context, "Not supported key exchange type"); } else { SSLKeyDerivation masterKD = ke.createKeyDerivation(chc); - SecretKey masterSecret = - masterKD.deriveKey("MasterSecret", null); + SecretKey masterSecret = masterKD.deriveKey("MasterSecret"); chc.handshakeSession.setMasterSecret(masterSecret); SSLTrafficKeyDerivation kd = @@ -522,8 +519,7 @@ public void consume(ConnectionContext context, // update the states SSLKeyDerivation masterKD = ke.createKeyDerivation(shc); - SecretKey masterSecret = - masterKD.deriveKey("MasterSecret", null); + SecretKey masterSecret = masterKD.deriveKey("MasterSecret"); shc.handshakeSession.setMasterSecret(masterSecret); SSLTrafficKeyDerivation kd = diff --git a/src/java.base/share/classes/sun/security/ssl/Finished.java b/src/java.base/share/classes/sun/security/ssl/Finished.java index 9afa83a0afc..e388672cb7f 100644 --- a/src/java.base/share/classes/sun/security/ssl/Finished.java +++ b/src/java.base/share/classes/sun/security/ssl/Finished.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,14 +32,14 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.ProviderException; -import java.security.spec.AlgorithmParameterSpec; import java.text.MessageFormat; import java.util.Locale; +import javax.crypto.KDF; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.SSLPeerUnverifiedException; import jdk.internal.event.EventHelper; @@ -47,11 +47,11 @@ import sun.security.internal.spec.TlsPrfParameterSpec; import sun.security.ssl.CipherSuite.HashAlg; import static sun.security.ssl.CipherSuite.HashAlg.H_NONE; -import sun.security.ssl.SSLBasicKeyDerivation.SecretSizeSpec; import sun.security.ssl.SSLCipher.SSLReadCipher; import sun.security.ssl.SSLCipher.SSLWriteCipher; import sun.security.ssl.SSLHandshake.HandshakeMessage; import sun.security.util.HexDumpEncoder; +import sun.security.util.KeyUtil; /** * Pack of the Finished handshake message. @@ -338,12 +338,8 @@ public byte[] createVerifyData(HandshakeContext context, SecretKey secret = isValidation ? context.baseReadSecret : context.baseWriteSecret; SSLBasicKeyDerivation kdf = new SSLBasicKeyDerivation( - secret, hashAlg.name, - hkdfLabel, hkdfContext, hashAlg.hashLength); - AlgorithmParameterSpec keySpec = - new SecretSizeSpec(hashAlg.hashLength); - SecretKey finishedSecret = - kdf.deriveKey("TlsFinishedSecret", keySpec); + secret, hashAlg, hkdfLabel, hkdfContext); + SecretKey finishedSecret = kdf.deriveKey("TlsFinishedSecret"); String hmacAlg = "Hmac" + hashAlg.name.replace("-", ""); @@ -354,6 +350,8 @@ public byte[] createVerifyData(HandshakeContext context, } catch (NoSuchAlgorithmException |InvalidKeyException ex) { throw new ProviderException( "Failed to generate verify_data", ex); + } finally { + KeyUtil.destroySecretKeys(finishedSecret); } } } @@ -717,17 +715,14 @@ private byte[] onProduceFinished(ClientHandshakeContext chc, try { // update the application traffic read keys. - SecretKey writeSecret = kd.deriveKey( - "TlsClientAppTrafficSecret", null); + SecretKey writeSecret = + kd.deriveKey("TlsClientAppTrafficSecret"); SSLKeyDerivation writeKD = kdg.createKeyDerivation(chc, writeSecret); - SecretKey writeKey = writeKD.deriveKey( - "TlsKey", null); - SecretKey writeIvSecret = writeKD.deriveKey( - "TlsIv", null); + SecretKey writeKey = writeKD.deriveKey("TlsKey"); IvParameterSpec writeIv = - new IvParameterSpec(writeIvSecret.getEncoded()); + new IvParameterSpec(writeKD.deriveData("TlsIv")); SSLWriteCipher writeCipher = chc.negotiatedCipherSuite.bulkCipher.createWriteCipher( Authenticator.valueOf(chc.negotiatedProtocol), @@ -750,11 +745,17 @@ private byte[] onProduceFinished(ClientHandshakeContext chc, "Failure to derive application secrets", gse); } + // Calculate/save the exporter_master_secret. It uses + // the same handshakeHash as the client/server app traffic. + SecretKey exporterSecret = kd.deriveKey( + "TlsExporterMasterSecret"); + chc.handshakeSession.setExporterMasterSecret(exporterSecret); + // The resumption master secret is stored in the session so // it can be used after the handshake is completed. SSLSecretDerivation sd = ((SSLSecretDerivation) kd).forContext(chc); SecretKey resumptionMasterSecret = sd.deriveKey( - "TlsResumptionMasterSecret", null); + "TlsResumptionMasterSecret"); chc.handshakeSession.setResumptionMasterSecret( resumptionMasterSecret); @@ -803,33 +804,29 @@ private byte[] onProduceFinished(ServerHandshakeContext shc, shc.negotiatedProtocol); } - // derive salt secret + SecretKey saltSecret = null; try { - SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null); + // derive salt secret + saltSecret = kd.deriveKey("TlsSaltSecret"); // derive application secrets HashAlg hashAlg = shc.negotiatedCipherSuite.hashAlg; - HKDF hkdf = new HKDF(hashAlg.name); + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); byte[] zeros = new byte[hashAlg.hashLength]; - SecretKeySpec sharedSecret = - new SecretKeySpec(zeros, "TlsZeroSecret"); - SecretKey masterSecret = - hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret"); - + SecretKey masterSecret = hkdf.deriveKey("TlsMasterSecret", + HKDFParameterSpec.ofExtract().addSalt(saltSecret) + .addIKM(zeros).extractOnly()); SSLKeyDerivation secretKD = new SSLSecretDerivation(shc, masterSecret); // update the handshake traffic write keys. SecretKey writeSecret = secretKD.deriveKey( - "TlsServerAppTrafficSecret", null); + "TlsServerAppTrafficSecret"); SSLKeyDerivation writeKD = kdg.createKeyDerivation(shc, writeSecret); - SecretKey writeKey = writeKD.deriveKey( - "TlsKey", null); - SecretKey writeIvSecret = writeKD.deriveKey( - "TlsIv", null); + SecretKey writeKey = writeKD.deriveKey("TlsKey"); IvParameterSpec writeIv = - new IvParameterSpec(writeIvSecret.getEncoded()); + new IvParameterSpec(writeKD.deriveData("TlsIv")); SSLWriteCipher writeCipher = shc.negotiatedCipherSuite.bulkCipher.createWriteCipher( Authenticator.valueOf(shc.negotiatedProtocol), @@ -852,6 +849,8 @@ private byte[] onProduceFinished(ServerHandshakeContext shc, } catch (GeneralSecurityException gse) { throw shc.conContext.fatal(Alert.INTERNAL_ERROR, "Failure to derive application secrets", gse); + } finally { + KeyUtil.destroySecretKeys(saltSecret); } /* @@ -960,34 +959,31 @@ private void onConsumeFinished(ClientHandshakeContext chc, engineGetClientSessionContext()). put(chc.handshakeSession); } - - // derive salt secret + SecretKey saltSecret = null; try { - SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null); + // derive salt secret + saltSecret = kd.deriveKey("TlsSaltSecret"); // derive application secrets HashAlg hashAlg = chc.negotiatedCipherSuite.hashAlg; - HKDF hkdf = new HKDF(hashAlg.name); + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); byte[] zeros = new byte[hashAlg.hashLength]; - SecretKeySpec sharedSecret = - new SecretKeySpec(zeros, "TlsZeroSecret"); - SecretKey masterSecret = - hkdf.extract(saltSecret, sharedSecret, "TlsMasterSecret"); + SecretKey masterSecret = hkdf.deriveKey("TlsMasterSecret", + HKDFParameterSpec.ofExtract() + .addSalt(saltSecret) + .addIKM(zeros).extractOnly()); SSLKeyDerivation secretKD = new SSLSecretDerivation(chc, masterSecret); // update the handshake traffic read keys. SecretKey readSecret = secretKD.deriveKey( - "TlsServerAppTrafficSecret", null); + "TlsServerAppTrafficSecret"); SSLKeyDerivation writeKD = kdg.createKeyDerivation(chc, readSecret); - SecretKey readKey = writeKD.deriveKey( - "TlsKey", null); - SecretKey readIvSecret = writeKD.deriveKey( - "TlsIv", null); + SecretKey readKey = writeKD.deriveKey("TlsKey"); IvParameterSpec readIv = - new IvParameterSpec(readIvSecret.getEncoded()); + new IvParameterSpec(writeKD.deriveData("TlsIv")); SSLReadCipher readCipher = chc.negotiatedCipherSuite.bulkCipher.createReadCipher( Authenticator.valueOf(chc.negotiatedProtocol), @@ -1009,6 +1005,8 @@ private void onConsumeFinished(ClientHandshakeContext chc, } catch (GeneralSecurityException gse) { throw chc.conContext.fatal(Alert.INTERNAL_ERROR, "Failure to derive application secrets", gse); + } finally { + KeyUtil.destroySecretKeys(saltSecret); } // @@ -1084,16 +1082,13 @@ private void onConsumeFinished(ServerHandshakeContext shc, try { // update the application traffic read keys. SecretKey readSecret = kd.deriveKey( - "TlsClientAppTrafficSecret", null); + "TlsClientAppTrafficSecret"); SSLKeyDerivation readKD = kdg.createKeyDerivation(shc, readSecret); - SecretKey readKey = readKD.deriveKey( - "TlsKey", null); - SecretKey readIvSecret = readKD.deriveKey( - "TlsIv", null); + SecretKey readKey = readKD.deriveKey("TlsKey"); IvParameterSpec readIv = - new IvParameterSpec(readIvSecret.getEncoded()); + new IvParameterSpec(readKD.deriveData("TlsIv")); SSLReadCipher readCipher = shc.negotiatedCipherSuite.bulkCipher.createReadCipher( Authenticator.valueOf(shc.negotiatedProtocol), @@ -1110,13 +1105,19 @@ private void onConsumeFinished(ServerHandshakeContext shc, shc.baseReadSecret = readSecret; shc.conContext.inputRecord.changeReadCiphers(readCipher); + // Calculate/save the exporter_master_secret. It uses + // the same handshakeHash as the client/server app traffic. + SecretKey exporterSecret = kd.deriveKey( + "TlsExporterMasterSecret"); + shc.handshakeSession.setExporterMasterSecret(exporterSecret); + // The resumption master secret is stored in the session so // it can be used after the handshake is completed. shc.handshakeHash.update(); SSLSecretDerivation sd = ((SSLSecretDerivation)kd).forContext(shc); - SecretKey resumptionMasterSecret = sd.deriveKey( - "TlsResumptionMasterSecret", null); + SecretKey resumptionMasterSecret = + sd.deriveKey("TlsResumptionMasterSecret"); shc.handshakeSession.setResumptionMasterSecret( resumptionMasterSecret); } catch (GeneralSecurityException gse) { diff --git a/src/java.base/share/classes/sun/security/ssl/HKDF.java b/src/java.base/share/classes/sun/security/ssl/HKDF.java deleted file mode 100644 index 5e5cd144305..00000000000 --- a/src/java.base/share/classes/sun/security/ssl/HKDF.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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.ssl; - -import java.security.NoSuchAlgorithmException; -import java.security.InvalidKeyException; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.SecretKeySpec; -import java.util.Objects; - -/** - * An implementation of the HKDF key derivation algorithm outlined in RFC 5869, - * specific to the needs of TLS 1.3 key derivation in JSSE. This is not a - * general purpose HKDF implementation and is suited only to single-key output - * derivations. - * - * HKDF objects are created by specifying a message digest algorithm. That - * digest algorithm will be used by the HMAC function as part of the HKDF - * derivation process. - */ -public final class HKDF { - private final Mac hmacObj; - private final int hmacLen; - - /** - * Create an HDKF object, specifying the underlying message digest - * algorithm. - * - * @param hashAlg a standard name corresponding to a supported message - * digest algorithm. - * - * @throws NoSuchAlgorithmException if that message digest algorithm does - * not have an HMAC variant supported on any available provider. - */ - public HKDF(String hashAlg) throws NoSuchAlgorithmException { - Objects.requireNonNull(hashAlg, - "Must provide underlying HKDF Digest algorithm."); - String hmacAlg = "Hmac" + hashAlg.replace("-", ""); - hmacObj = Mac.getInstance(hmacAlg); - hmacLen = hmacObj.getMacLength(); - } - - /** - * Perform the HMAC-Extract derivation. - * - * @param salt a salt value, implemented as a {@code SecretKey}. A - * {@code null} value is allowed, which will internally use an array of - * zero bytes the same size as the underlying hash output length. - * @param inputKey the input keying material provided as a - * {@code SecretKey}. - * @param keyAlg the algorithm name assigned to the resulting - * {@code SecretKey} object. - * - * @return a {@code SecretKey} that is the result of the HKDF extract - * operation. - * - * @throws InvalidKeyException if the {@code salt} parameter cannot be - * used to initialize the underlying HMAC. - */ - public SecretKey extract(SecretKey salt, SecretKey inputKey, String keyAlg) - throws InvalidKeyException { - if (salt == null) { - salt = new SecretKeySpec(new byte[hmacLen], "HKDF-Salt"); - } - hmacObj.init(salt); - - return new SecretKeySpec(hmacObj.doFinal(inputKey.getEncoded()), - keyAlg); - } - - /** - * Perform the HMAC-Extract derivation. - * - * @param salt a salt value as cleartext bytes. A {@code null} value is - * allowed, which will internally use an array of zero bytes the same - * size as the underlying hash output length. - * @param inputKey the input keying material provided as a - * {@code SecretKey}. - * @param keyAlg the algorithm name assigned to the resulting - * {@code SecretKey} object. - * - * @return a {@code SecretKey} that is the result of the HKDF extract - * operation. - * - * @throws InvalidKeyException if the {@code salt} parameter cannot be - * used to initialize the underlying HMAC. - */ - public SecretKey extract(byte[] salt, SecretKey inputKey, String keyAlg) - throws InvalidKeyException { - if (salt == null) { - salt = new byte[hmacLen]; - } - return extract(new SecretKeySpec(salt, "HKDF-Salt"), inputKey, keyAlg); - } - - /** - * Perform the HKDF-Expand derivation for a single-key output. - * - * @param pseudoRandKey the pseudo random key (PRK). - * @param info optional context-specific info. A {@code null} value is - * allowed in which case a zero-length byte array will be used. - * @param outLen the length of the resulting {@code SecretKey} - * @param keyAlg the algorithm name applied to the resulting - * {@code SecretKey} - * - * @return the resulting key derivation as a {@code SecretKey} object - * - * @throws InvalidKeyException if the underlying HMAC operation cannot - * be initialized using the provided {@code pseudoRandKey} object. - */ - public SecretKey expand(SecretKey pseudoRandKey, byte[] info, int outLen, - String keyAlg) throws InvalidKeyException { - byte[] kdfOutput; - - // Calculate the number of rounds of HMAC that are needed to - // meet the requested data. Then set up the buffers we will need. - Objects.requireNonNull(pseudoRandKey, "A null PRK is not allowed."); - - // Output from the expand operation must be <= 255 * hmac length - if (outLen > 255 * hmacLen) { - throw new IllegalArgumentException("Requested output length " + - "exceeds maximum length allowed for HKDF expansion"); - } - hmacObj.init(pseudoRandKey); - if (info == null) { - info = new byte[0]; - } - int rounds = (outLen + hmacLen - 1) / hmacLen; - kdfOutput = new byte[rounds * hmacLen]; - int offset = 0; - int tLength = 0; - - for (int i = 0; i < rounds ; i++) { - - // Calculate this round - try { - // Add T(i). This will be an empty string on the first - // iteration since tLength starts at zero. After the first - // iteration, tLength is changed to the HMAC length for the - // rest of the loop. - hmacObj.update(kdfOutput, - Math.max(0, offset - hmacLen), tLength); - hmacObj.update(info); // Add info - hmacObj.update((byte)(i + 1)); // Add round number - hmacObj.doFinal(kdfOutput, offset); - - tLength = hmacLen; - offset += hmacLen; // For next iteration - } catch (ShortBufferException sbe) { - // This really shouldn't happen given that we've - // sized the buffers to their largest possible size up-front, - // but just in case... - throw new RuntimeException(sbe); - } - } - - return new SecretKeySpec(kdfOutput, 0, outLen, keyAlg); - } -} - 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 b76da75c763..623f83f547a 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,15 +24,18 @@ */ package sun.security.ssl; +import javax.crypto.KDF; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; +import javax.crypto.spec.HKDFParameterSpec; import javax.net.ssl.SSLHandshakeException; + import java.io.IOException; import java.security.GeneralSecurityException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.AlgorithmParameterSpec; +import sun.security.util.KeyUtil; /** * A common class for creating various KeyDerivation types. @@ -55,29 +58,26 @@ public class KAKeyDerivation implements SSLKeyDerivation { } @Override - public SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { + public SecretKey deriveKey(String type) throws IOException { if (!context.negotiatedProtocol.useTLS13PlusSpec()) { - return t12DeriveKey(algorithm, params); + return t12DeriveKey(); } else { - return t13DeriveKey(algorithm, params); + return t13DeriveKey(type); } } /** * Handle the TLSv1-1.2 objects, which don't use the HKDF algorithms. */ - private SecretKey t12DeriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { + private SecretKey t12DeriveKey() throws IOException { + SecretKey preMasterSecret = null; try { KeyAgreement ka = KeyAgreement.getInstance(algorithmName); ka.init(localPrivateKey); ka.doPhase(peerPublicKey, true); - SecretKey preMasterSecret - = ka.generateSecret("TlsPremasterSecret"); - SSLMasterKeyDerivation mskd - = SSLMasterKeyDerivation.valueOf( - context.negotiatedProtocol); + preMasterSecret = ka.generateSecret("TlsPremasterSecret"); + SSLMasterKeyDerivation mskd = + SSLMasterKeyDerivation.valueOf(context.negotiatedProtocol); if (mskd == null) { // unlikely throw new SSLHandshakeException( @@ -86,45 +86,55 @@ private SecretKey t12DeriveKey(String algorithm, } SSLKeyDerivation kd = mskd.createKeyDerivation( context, preMasterSecret); - return kd.deriveKey("MasterSecret", params); + return kd.deriveKey("MasterSecret"); } catch (GeneralSecurityException gse) { throw new SSLHandshakeException("Could not generate secret", gse); + } finally { + KeyUtil.destroySecretKeys(preMasterSecret); } } /** * Handle the TLSv1.3 objects, which use the HKDF algorithms. */ - private SecretKey t13DeriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { + private SecretKey t13DeriveKey(String type) + throws IOException { + SecretKey sharedSecret = null; + SecretKey earlySecret = null; + SecretKey saltSecret = null; try { KeyAgreement ka = KeyAgreement.getInstance(algorithmName); ka.init(localPrivateKey); ka.doPhase(peerPublicKey, true); - SecretKey sharedSecret - = ka.generateSecret("TlsPremasterSecret"); + sharedSecret = ka.generateSecret("TlsPremasterSecret"); CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; SSLKeyDerivation kd = context.handshakeKeyDerivation; - HKDF hkdf = new HKDF(hashAlg.name); if (kd == null) { // No PSK is in use. - // If PSK is not in use Early Secret will still be + // If PSK is not in use, Early Secret will still be // HKDF-Extract(0, 0). byte[] zeros = new byte[hashAlg.hashLength]; - SecretKeySpec ikm - = new SecretKeySpec(zeros, "TlsPreSharedSecret"); - SecretKey earlySecret - = hkdf.extract(zeros, ikm, "TlsEarlySecret"); + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); + earlySecret = hkdf.deriveKey("TlsEarlySecret", + HKDFParameterSpec.ofExtract().addSalt(zeros) + .addIKM(zeros).extractOnly()); kd = new SSLSecretDerivation(context, earlySecret); } // derive salt secret - SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null); + saltSecret = kd.deriveKey("TlsSaltSecret"); // derive handshake secret - return hkdf.extract(saltSecret, sharedSecret, algorithm); + // NOTE: do not reuse the HKDF object for "TlsEarlySecret" for + // the handshake secret key derivation (below) as it may not + // work with the "sharedSecret" obj. + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); + return hkdf.deriveKey(type, HKDFParameterSpec.ofExtract() + .addSalt(saltSecret).addIKM(sharedSecret).extractOnly()); } catch (GeneralSecurityException gse) { throw new SSLHandshakeException("Could not generate secret", gse); + } finally { + KeyUtil.destroySecretKeys(sharedSecret, earlySecret, saltSecret); } } } diff --git a/src/java.base/share/classes/sun/security/ssl/KeyUpdate.java b/src/java.base/share/classes/sun/security/ssl/KeyUpdate.java index 49eb0420f47..c4549070f02 100644 --- a/src/java.base/share/classes/sun/security/ssl/KeyUpdate.java +++ b/src/java.base/share/classes/sun/security/ssl/KeyUpdate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -214,11 +214,11 @@ public void consume(ConnectionContext context, Alert.INTERNAL_ERROR, "no key derivation"); } - SecretKey nplus1 = skd.deriveKey("TlsUpdateNplus1", null); + SecretKey nplus1 = skd.deriveKey("TlsUpdateNplus1"); SSLKeyDerivation kd = kdg.createKeyDerivation(hc, nplus1); - SecretKey key = kd.deriveKey("TlsKey", null); - IvParameterSpec ivSpec = new IvParameterSpec( - kd.deriveKey("TlsIv", null).getEncoded()); + SecretKey key = kd.deriveKey("TlsKey"); + IvParameterSpec ivSpec = + new IvParameterSpec(kd.deriveData("TlsIv")); try { SSLReadCipher rc = hc.negotiatedCipherSuite.bulkCipher.createReadCipher( @@ -293,11 +293,11 @@ public byte[] produce(ConnectionContext context, Alert.INTERNAL_ERROR, "no key derivation"); } - SecretKey nplus1 = skd.deriveKey("TlsUpdateNplus1", null); + SecretKey nplus1 = skd.deriveKey("TlsUpdateNplus1"); SSLKeyDerivation kd = kdg.createKeyDerivation(hc, nplus1); - SecretKey key = kd.deriveKey("TlsKey", null); - IvParameterSpec ivSpec = new IvParameterSpec( - kd.deriveKey("TlsIv", null).getEncoded()); + SecretKey key = kd.deriveKey("TlsKey"); + IvParameterSpec ivSpec = + new IvParameterSpec(kd.deriveData("TlsIv")); SSLWriteCipher wc; try { 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 8be021b4111..4c879e0dc4d 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,10 @@ import java.text.MessageFormat; import java.util.Arrays; import java.util.Locale; +import javax.crypto.KDF; import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; +import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.SSLHandshakeException; import sun.security.ssl.PskKeyExchangeModesExtension.PskKeyExchangeMode; import sun.security.ssl.PskKeyExchangeModesExtension.PskKeyExchangeModesSpec; @@ -286,11 +289,16 @@ public String toString() { private static SecretKey derivePreSharedKey(CipherSuite.HashAlg hashAlg, SecretKey resumptionMasterSecret, byte[] nonce) throws IOException { try { - HKDF hkdf = new HKDF(hashAlg.name); + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); + byte[] hkdfInfo = SSLSecretDerivation.createHkdfInfo( "tls13 resumption".getBytes(), nonce, hashAlg.hashLength); - return hkdf.expand(resumptionMasterSecret, hkdfInfo, - hashAlg.hashLength, "TlsPreSharedKey"); + // SSLSessionImpl.write() uses the PreSharedKey encoding for + // the stateless session ticket; use SecretKeySpec instead of opaque + // Key objects + return new SecretKeySpec(hkdf.deriveData( + HKDFParameterSpec.expandOnly(resumptionMasterSecret, + hkdfInfo, hashAlg.hashLength)), "TlsPreSharedKey"); } catch (GeneralSecurityException gse) { throw new SSLHandshakeException("Could not derive PSK", gse); } diff --git a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java index 4751708e5dc..76bb64a66c3 100644 --- a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -29,8 +29,10 @@ import java.security.*; import java.text.MessageFormat; import java.util.*; +import javax.crypto.KDF; import javax.crypto.Mac; import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLProtocolException; import static sun.security.ssl.ClientAuthType.CLIENT_AUTH_REQUIRED; @@ -40,6 +42,7 @@ import sun.security.ssl.SSLHandshake.HandshakeMessage; import sun.security.ssl.SessionTicketExtension.SessionTicketSpec; import sun.security.util.HexDumpEncoder; +import sun.security.util.KeyUtil; import static sun.security.ssl.SSLExtension.*; @@ -440,12 +443,6 @@ private static boolean canRejoin(ClientHelloMessage clientHello, result = false; } - // Make sure that the server handshake context's - // localSupportedCertSignAlgs field is populated. This is particularly - // important when client authentication was used in an initial session, - // and it is now being resumed. - SignatureScheme.updateHandshakeLocalSupportedAlgs(shc); - // Validate the required client authentication. if (result && (shc.sslConfig.clientAuthType == CLIENT_AUTH_REQUIRED)) { @@ -461,7 +458,9 @@ private static boolean canRejoin(ClientHelloMessage clientHello, result = false; } - // Make sure the list of supported signature algorithms matches + // Make sure the list of supported signature algorithms matches. + // HandshakeContext's localSupportedCertSignAlgs has been already + // updated when we set the negotiated protocol. Collection sessionSigAlgs = s.getLocalSupportedSignatureSchemes(); if (result && @@ -559,11 +558,15 @@ private static void checkBinder(ServerHandshakeContext shc, } SecretKey binderKey = deriveBinderKey(shc, psk, session); - byte[] computedBinder = - computeBinder(shc, binderKey, session, pskBinderHash); - if (!MessageDigest.isEqual(binder, computedBinder)) { - throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, - "Incorrect PSK binder value"); + try { + byte[] computedBinder = + computeBinder(shc, binderKey, session, pskBinderHash); + if (!MessageDigest.isEqual(binder, computedBinder)) { + throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, + "Incorrect PSK binder value"); + } + } finally { + KeyUtil.destroySecretKeys(binderKey); } } @@ -712,21 +715,25 @@ public byte[] produce(ConnectionContext context, SecretKey binderKey = deriveBinderKey(chc, psk, chc.resumingSession); - ClientHelloMessage clientHello = (ClientHelloMessage)message; - CHPreSharedKeySpec pskPrototype = createPskPrototype( - chc.resumingSession.getSuite().hashAlg.hashLength, identities); - HandshakeHash pskBinderHash = chc.handshakeHash.copy(); + try { + ClientHelloMessage clientHello = (ClientHelloMessage)message; + CHPreSharedKeySpec pskPrototype = createPskPrototype( + chc.resumingSession.getSuite().hashAlg.hashLength, identities); + HandshakeHash pskBinderHash = chc.handshakeHash.copy(); - byte[] binder = computeBinder(chc, binderKey, pskBinderHash, - chc.resumingSession, chc, clientHello, pskPrototype); + byte[] binder = computeBinder(chc, binderKey, pskBinderHash, + chc.resumingSession, chc, clientHello, pskPrototype); - List binders = new ArrayList<>(); - binders.add(binder); + List binders = new ArrayList<>(); + binders.add(binder); - CHPreSharedKeySpec pskMessage = - new CHPreSharedKeySpec(identities, binders); - chc.handshakeExtensions.put(CH_PRE_SHARED_KEY, pskMessage); - return pskMessage.getEncoded(); + CHPreSharedKeySpec pskMessage = + new CHPreSharedKeySpec(identities, binders); + chc.handshakeExtensions.put(CH_PRE_SHARED_KEY, pskMessage); + return pskMessage.getEncoded(); + } finally { + KeyUtil.destroySecretKeys(binderKey); + } } private CHPreSharedKeySpec createPskPrototype( @@ -780,12 +787,13 @@ private static byte[] computeBinder(HandshakeContext context, SSLSessionImpl session, byte[] digest) throws IOException { try { CipherSuite.HashAlg hashAlg = session.getSuite().hashAlg; - HKDF hkdf = new HKDF(hashAlg.name); + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); byte[] label = ("tls13 finished").getBytes(); byte[] hkdfInfo = SSLSecretDerivation.createHkdfInfo( label, new byte[0], hashAlg.hashLength); - SecretKey finishedKey = hkdf.expand( - binderKey, hkdfInfo, hashAlg.hashLength, "TlsBinderKey"); + SecretKey finishedKey = hkdf.deriveKey("TlsBinderKey", + HKDFParameterSpec.expandOnly(binderKey, hkdfInfo, + hashAlg.hashLength)); String hmacAlg = "Hmac" + hashAlg.name.replace("-", ""); @@ -795,6 +803,8 @@ private static byte[] computeBinder(HandshakeContext context, return hmac.doFinal(digest); } catch (NoSuchAlgorithmException | InvalidKeyException ex) { throw context.conContext.fatal(Alert.INTERNAL_ERROR, ex); + } finally { + KeyUtil.destroySecretKeys(finishedKey); } } catch (GeneralSecurityException ex) { throw context.conContext.fatal(Alert.INTERNAL_ERROR, ex); @@ -805,16 +815,16 @@ private static SecretKey deriveBinderKey(HandshakeContext context, SecretKey psk, SSLSessionImpl session) throws IOException { try { CipherSuite.HashAlg hashAlg = session.getSuite().hashAlg; - HKDF hkdf = new HKDF(hashAlg.name); byte[] zeros = new byte[hashAlg.hashLength]; - SecretKey earlySecret = hkdf.extract(zeros, psk, "TlsEarlySecret"); - byte[] label = ("tls13 res binder").getBytes(); MessageDigest md = MessageDigest.getInstance(hashAlg.name); byte[] hkdfInfo = SSLSecretDerivation.createHkdfInfo( label, md.digest(new byte[0]), hashAlg.hashLength); - return hkdf.expand(earlySecret, - hkdfInfo, hashAlg.hashLength, "TlsBinderKey"); + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); + HKDFParameterSpec spec = HKDFParameterSpec.ofExtract() + .addSalt(zeros).addIKM(psk) + .thenExpand(hkdfInfo, hashAlg.hashLength); + return hkdf.deriveKey("TlsBinderKey", spec); } catch (GeneralSecurityException ex) { throw context.conContext.fatal(Alert.INTERNAL_ERROR, ex); } diff --git a/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java index 5189822da30..701ba35174e 100644 --- a/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,8 +208,7 @@ public byte[] produce(ConnectionContext context, "Not supported key exchange type"); } else { SSLKeyDerivation masterKD = ke.createKeyDerivation(chc); - SecretKey masterSecret = - masterKD.deriveKey("MasterSecret", null); + SecretKey masterSecret = masterKD.deriveKey("MasterSecret"); // update the states chc.handshakeSession.setMasterSecret(masterSecret); @@ -296,8 +295,7 @@ public void consume(ConnectionContext context, "Not supported key exchange type"); } else { SSLKeyDerivation masterKD = ke.createKeyDerivation(shc); - SecretKey masterSecret = - masterKD.deriveKey("MasterSecret", null); + SecretKey masterSecret = masterKD.deriveKey("MasterSecret"); // update the states shc.handshakeSession.setMasterSecret(masterSecret); diff --git a/src/java.base/share/classes/sun/security/ssl/RSAKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/RSAKeyExchange.java index 3ad4a009556..311ac97e744 100644 --- a/src/java.base/share/classes/sun/security/ssl/RSAKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/RSAKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -292,8 +292,7 @@ class RSAKAKeyDerivation implements SSLKeyDerivation { } @Override - public SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { + public SecretKey deriveKey(String typeNotUsed) throws IOException { SSLMasterKeyDerivation mskd = SSLMasterKeyDerivation.valueOf( context.negotiatedProtocol); @@ -305,7 +304,7 @@ public SecretKey deriveKey(String algorithm, } SSLKeyDerivation kd = mskd.createKeyDerivation( context, preMasterSecret); - return kd.deriveKey("MasterSecret", params); + return kd.deriveKey("MasterSecret"); } } } 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 20fc7112593..58ed20792ad 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,29 +28,33 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; -import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.KDF; import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; import javax.net.ssl.SSLHandshakeException; +import sun.security.ssl.CipherSuite.HashAlg; + final class SSLBasicKeyDerivation implements SSLKeyDerivation { - private final String hashAlg; + private final String hkdfAlg; private final SecretKey secret; private final byte[] hkdfInfo; + private final int keyLen; - SSLBasicKeyDerivation(SecretKey secret, String hashAlg, - byte[] label, byte[] context, int length) { - this.hashAlg = hashAlg.replace("-", ""); + SSLBasicKeyDerivation(SecretKey secret, HashAlg hashAlg, byte[] label, + byte[] context) { + this.hkdfAlg = hashAlg.hkdfAlgorithm; this.secret = secret; - this.hkdfInfo = createHkdfInfo(label, context, length); + this.hkdfInfo = createHkdfInfo(label, context, hashAlg.hashLength); + this.keyLen = hashAlg.hashLength; } @Override - public SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec keySpec) throws IOException { + public SecretKey deriveKey(String type) throws IOException { try { - HKDF hkdf = new HKDF(hashAlg); - return hkdf.expand(secret, hkdfInfo, - ((SecretSizeSpec)keySpec).length, algorithm); + KDF hkdf = KDF.getInstance(hkdfAlg); + return hkdf.deriveKey(type, + HKDFParameterSpec.expandOnly(secret, hkdfInfo, keyLen)); } catch (GeneralSecurityException gse) { throw new SSLHandshakeException("Could not generate secret", gse); } @@ -69,12 +73,4 @@ private static byte[] createHkdfInfo( } return info; } - - static class SecretSizeSpec implements AlgorithmParameterSpec { - final int length; - - SecretSizeSpec(int length) { - this.length = length; - } - } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLKeyDerivation.java index d132af3b0b0..ab415bdae4b 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,9 @@ import javax.crypto.SecretKey; interface SSLKeyDerivation { - SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException; + SecretKey deriveKey(String purpose) throws IOException; + + default byte[] deriveData(String purpose) throws IOException { + throw new UnsupportedOperationException("No support for deriveData!"); + }; } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java index 9736bfaba0d..ec5dee26cfc 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLLogger.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -142,8 +142,10 @@ private static boolean hasOption(String option) { if (property.contains("all")) { return true; } else { - int offset = property.indexOf("ssl"); - if (offset != -1 && property.indexOf("sslctx", offset) != -1) { + // remove first occurrence of "sslctx" since + // it interferes with search for "ssl" + String modified = property.replaceFirst("sslctx", ""); + if (modified.contains("ssl")) { // don't enable data and plaintext options by default if (!(option.equals("data") || option.equals("packet") diff --git a/src/java.base/share/classes/sun/security/ssl/SSLMasterKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLMasterKeyDerivation.java index b3e60553d55..db5887c5e8e 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLMasterKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLMasterKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,9 +84,7 @@ class LegacyMasterKeyDerivation implements SSLKeyDerivation { @Override @SuppressWarnings("deprecation") - public SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - + public SecretKey deriveKey(String typeNotUsed) throws IOException { CipherSuite cipherSuite = context.negotiatedCipherSuite; ProtocolVersion protocolVersion = context.negotiatedProtocol; 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 0c0dc46d33d..dc3b2bcb4bc 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,9 @@ import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.KDF; import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; import javax.net.ssl.SSLHandshakeException; import sun.security.ssl.CipherSuite.HashAlg; @@ -87,9 +89,8 @@ SSLSecretDerivation forContext(HandshakeContext context) { } @Override - public SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - SecretSchedule ks = SecretSchedule.valueOf(algorithm); + public SecretKey deriveKey(String type) throws IOException { + SecretSchedule ks = SecretSchedule.valueOf(type); try { byte[] expandContext; if (ks == SecretSchedule.TlsSaltSecret) { @@ -102,16 +103,16 @@ public SecretKey deriveKey(String algorithm, // get supported in the future. throw new SSLHandshakeException( "Unexpected unsupported hash algorithm: " + - algorithm); + hashAlg); } } else { expandContext = transcriptHash; } + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); byte[] hkdfInfo = createHkdfInfo(ks.label, expandContext, hashAlg.hashLength); - - HKDF hkdf = new HKDF(hashAlg.name); - return hkdf.expand(secret, hkdfInfo, hashAlg.hashLength, algorithm); + return hkdf.deriveKey(type, HKDFParameterSpec.expandOnly( + secret, hkdfInfo, hashAlg.hashLength)); } catch (GeneralSecurityException gse) { throw new SSLHandshakeException("Could not generate secret", gse); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java index 0ff80f0c76c..4baa3304fee 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,7 @@ import javax.net.ssl.SSLSessionContext; import sun.security.util.Cache; - +import sun.security.util.KeyUtil; /** * {@systemProperty jdk.tls.server.enableSessionTicketExtension} determines if the @@ -197,11 +197,7 @@ private void cleanupStatelessKeys() { SessionTicketExtension.StatelessKey k = entry.getValue(); if (k.isInvalid(this)) { it.remove(); - try { - k.key.destroy(); - } catch (Exception e) { - // Suppress - } + KeyUtil.destroySecretKeys(k.key); } } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java index 2e7d99ee293..5eb9f72af46 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -24,34 +24,37 @@ */ package sun.security.ssl; -import sun.security.provider.X509Factory; - import java.io.IOException; -import java.math.BigInteger; import java.net.InetAddress; import java.nio.ByteBuffer; -import java.security.Principal; -import java.security.PrivateKey; +import java.nio.charset.StandardCharsets; +import java.security.*; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; -import java.util.Queue; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Queue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.locks.ReentrantLock; +import java.util.zip.Adler32; +import javax.crypto.KDF; +import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.ExtendedSSLSession; -import javax.net.ssl.SNIHostName; -import javax.net.ssl.SNIServerName; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSessionBindingEvent; -import javax.net.ssl.SSLSessionBindingListener; -import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.*; + +import sun.security.ssl.CipherSuite.HashAlg; +import sun.security.internal.spec.TlsPrfParameterSpec; +import static sun.security.ssl.CipherSuite.HashAlg.H_NONE; +import static sun.security.ssl.ProtocolVersion.*; +import sun.security.util.KeyUtil; +import sun.security.provider.X509Factory; +import sun.security.ssl.X509Authentication.X509Possession; /** * Implements the SSL session interface, and exposes the session context @@ -100,6 +103,9 @@ final class SSLSessionImpl extends ExtendedSSLSession { private Collection peerSupportedSignAlgs; //for certificate private boolean useDefaultPeerSignAlgs = false; private List statusResponses; + private SecretKey exporterMasterSecret; // TLSv1.3+ exporter info + private RandomCookie clientRandom; // TLSv1.2- exporter info + private RandomCookie serverRandom; private SecretKey resumptionMasterSecret; private SecretKey preSharedKey; private byte[] pskIdentity; @@ -256,266 +262,216 @@ final class SSLSessionImpl extends ExtendedSSLSession { } /** + * Reassemble new session ticket. + *

                * < 2 bytes > protocolVersion * < 2 bytes > cipherSuite * < 1 byte > localSupportedSignAlgs entries * < 2 bytes per entries > localSupportedSignAlgs - * < 1 bytes > peerSupportedSignAlgs entries - * < 2 bytes per entries > peerSupportedSignAlgs - * < 2 bytes > preSharedKey length - * < length in bytes > preSharedKey - * < 1 byte > pskIdentity length - * < length in bytes > pskIdentity - * < 1 byte > masterSecret length - * < 1 byte > masterSecret algorithm length - * < length in bytes > masterSecret algorithm - * < 2 bytes > masterSecretKey length - * < length in bytes> masterSecretKey - * < 1 byte > useExtendedMasterSecret + * select (protocolVersion) + * case TLS13Plus: + * < 2 bytes > preSharedKey length + * < length in bytes > preSharedKey + * case non-TLS13Plus: + * < 2 bytes > masterSecretKey length + * < length in bytes> masterSecretKey + * < 1 byte > useExtendedMasterSecret * < 1 byte > identificationProtocol length - * < length in bytes > identificationProtocol + * < length in bytes > identificationProtocol * < 1 byte > serverNameIndication length - * < length in bytes > serverNameIndication + * < length in bytes > serverNameIndication * < 1 byte > Number of requestedServerNames entries - * < 1 byte > ServerName length - * < length in bytes > ServerName + * For each entry { + * < 1 byte > ServerName length + * < length in bytes > ServerName + * } + * < 4 bytes > maximumPacketSize + * < 4 bytes > negotiatedMaxFragSize * < 4 bytes > creationTime - * < 2 byte > status response length - * < 2 byte > status response entry length - * < length in byte > status response entry * < 1 byte > Length of peer host * < length in bytes > peer host * < 2 bytes> peer port - * < 1 byte > Number of peerCerts entries - * < 4 byte > peerCert length - * < length in bytes > peerCert - * < 1 byte > localCerts type (Cert, PSK, Anonymous) - * Certificate - * < 1 byte > Number of Certificate entries - * < 4 byte> Certificate length - * < length in bytes> Certificate - * PSK - * < 1 byte > Number of PSK entries - * < 1 bytes > PSK algorithm length - * < length in bytes > PSK algorithm string - * < 4 bytes > PSK key length - * < length in bytes> PSK key - * < 4 bytes > PSK identity length - * < length in bytes> PSK identity - * Anonymous - * < 1 byte > - * < 4 bytes > maximumPacketSize - * < 4 bytes > negotiatedMaxFragSize + * < 1 byte > Number of Peer Certificate entries + * For each entry { + * < 4 bytes > Peer certificate length + * < length in bytes> Peer certificate + * } + * < 1 byte > Number of Local Certificate entries + * For each entry { + * < 1 byte > Local Certificate algorithm length + * < length in bytes> Local Certificate algorithm + * < 4 bytes > Certificate checksum + * } */ SSLSessionImpl(HandshakeContext hc, ByteBuffer buf) throws IOException { + int len; + byte[] b; boundValues = new ConcurrentHashMap<>(); this.protocolVersion = - ProtocolVersion.valueOf(Short.toUnsignedInt(buf.getShort())); + ProtocolVersion.valueOf(Record.getInt16(buf)); // The CH session id may reset this if it's provided this.sessionId = new SessionId(true, hc.sslContext.getSecureRandom()); this.cipherSuite = - CipherSuite.valueOf(Short.toUnsignedInt(buf.getShort())); + CipherSuite.valueOf(Record.getInt16(buf)); // Local Supported signature algorithms - ArrayList list = new ArrayList<>(); - int i = Byte.toUnsignedInt(buf.get()); - while (i-- > 0) { + List list = new ArrayList<>(); + len = Record.getInt8(buf); + while (len-- > 0) { list.add(SignatureScheme.valueOf( - Short.toUnsignedInt(buf.getShort()))); + Record.getInt16(buf))); } this.localSupportedSignAlgs = Collections.unmodifiableCollection(list); - // Peer Supported signature algorithms - i = Byte.toUnsignedInt(buf.get()); - list.clear(); - while (i-- > 0) { - list.add(SignatureScheme.valueOf( - Short.toUnsignedInt(buf.getShort()))); - } - this.peerSupportedSignAlgs = Collections.unmodifiableCollection(list); - - // PSK - byte[] b; - i = Short.toUnsignedInt(buf.getShort()); - if (i > 0) { - b = new byte[i]; - // Get algorithm string - buf.get(b, 0, i); - // Encoded length - i = Short.toUnsignedInt(buf.getShort()); - // Encoded SecretKey - b = new byte[i]; - buf.get(b); - this.preSharedKey = new SecretKeySpec(b, "TlsMasterSecret"); - } else { - this.preSharedKey = null; - } + if (protocolVersion.useTLS13PlusSpec()) { + // PSK + b = Record.getBytes16(buf); + if (b.length > 0) { + this.preSharedKey = new SecretKeySpec(b, "TlsMasterSecret"); + } else { + this.preSharedKey = null; + } - // PSK identity - i = buf.get(); - if (i > 0) { - b = new byte[i]; - buf.get(b); - this.pskIdentity = b; + this.useExtendedMasterSecret = false; } else { - this.pskIdentity = null; - } + // Master secret + b = Record.getBytes16(buf); + if (b.length > 0) { + this.masterSecret = new SecretKeySpec(b, "TlsMasterSecret"); + } else { + this.masterSecret = null; + } - // Master secret length of secret key algorithm (one byte) - i = buf.get(); - if (i > 0) { - b = new byte[i]; - // Get algorithm string - buf.get(b, 0, i); - // Encoded length - i = Short.toUnsignedInt(buf.getShort()); - // Encoded SecretKey - b = new byte[i]; - buf.get(b); - this.masterSecret = new SecretKeySpec(b, "TlsMasterSecret"); - } else { - this.masterSecret = null; + // Extended master secret usage. + this.useExtendedMasterSecret = (Record.getInt8(buf) != 0); } - // Use extended master secret - this.useExtendedMasterSecret = (buf.get() != 0); // Identification Protocol - i = buf.get(); - if (i == 0) { + b = Record.getBytes8(buf); + if (b.length == 0) { identificationProtocol = null; } else { - b = new byte[i]; - buf.get(b); identificationProtocol = new String(b); } // SNI - i = buf.get(); // length - if (i == 0) { + b = Record.getBytes8(buf); + if (b.length == 0) { serverNameIndication = null; } else { - b = new byte[i]; - buf.get(b, 0, b.length); serverNameIndication = new SNIHostName(b); } // List of SNIServerName - int len = Short.toUnsignedInt(buf.getShort()); + len = Record.getInt16(buf); if (len == 0) { this.requestedServerNames = Collections.emptyList(); } else { requestedServerNames = new ArrayList<>(); while (len > 0) { - int l = buf.get(); - b = new byte[l]; - buf.get(b, 0, l); + b = Record.getBytes8(buf); requestedServerNames.add(new SNIHostName(new String(b))); len--; } } - maximumPacketSize = buf.getInt(); negotiatedMaxFragLen = buf.getInt(); // Get creation time this.creationTime = buf.getLong(); - // Get Buffer sizes - - // Status Response - len = Short.toUnsignedInt(buf.getShort()); - if (len == 0) { - statusResponses = Collections.emptyList(); - } else { - statusResponses = new ArrayList<>(); - } - while (len-- > 0) { - b = new byte[Short.toUnsignedInt(buf.getShort())]; - buf.get(b); - statusResponses.add(b); - } - // Get Peer host & port - i = Byte.toUnsignedInt(buf.get()); - if (i == 0) { + b = Record.getBytes8(buf); + if (b.length == 0) { this.host = ""; } else { - b = new byte[i]; - buf.get(b, 0, i); this.host = new String(b); } - this.port = Short.toUnsignedInt(buf.getShort()); + this.port = Record.getInt16(buf); - // Peer certs - i = buf.get(); - if (i == 0) { + // Peer certs. + len = Record.getInt8(buf); + if (len == 0) { this.peerCerts = null; } else { - this.peerCerts = new X509Certificate[i]; - int j = 0; - while (i > j) { + this.peerCerts = new X509Certificate[len]; + for (int i = 0; len > i; i++) { b = new byte[buf.getInt()]; buf.get(b); try { - this.peerCerts[j] = X509Factory.cachedGetX509Cert(b); + this.peerCerts[i] = X509Factory.cachedGetX509Cert(b); } catch (Exception e) { throw new IOException(e); } - j++; } } - // Get local certs of PSK - switch (buf.get()) { - case 0: - break; - case 1: - // number of certs - len = buf.get(); - this.localCerts = new X509Certificate[len]; - i = 0; - while (len > i) { - b = new byte[buf.getInt()]; - buf.get(b); + // Restore local certificates if cert algorithm(s) present. + len = Record.getInt8(buf); + if (len == 0) { + this.localCerts = null; + } else { + String[] certAlgs = new String[len]; + int[] certCheckSums = new int[len]; + + for (int i = 0; len > i; i++) { + certAlgs[i] = new String(Record.getBytes8(buf)); + certCheckSums[i] = Record.getInt32(buf); + } + + SSLPossession pos = X509Authentication.createPossession( + hc, certAlgs); + boolean same = false; + + if (pos instanceof X509Possession x509Pos + && x509Pos.popCerts != null + && x509Pos.popCerts.length == len) { + // Make sure we got the exact same cert chain. + for (int i = 0; i < x509Pos.popCerts.length; i++) { try { - this.localCerts[i] = X509Factory.cachedGetX509Cert(b); + byte[] encoded = x509Pos.popCerts[i].getEncoded(); + String popAlg = x509Pos.popCerts[i] + .getPublicKey().getAlgorithm(); + + if (certCheckSums[i] == getChecksum(encoded) + && certAlgs[i].equals(popAlg)) { + // Use certs from cache. + x509Pos.popCerts[i] = + X509Factory.cachedGetX509Cert(encoded); + same = true; + } else { + same = false; + break; + } } catch (Exception e) { throw new IOException(e); } - i++; } - break; - case 2: - // pre-shared key - // Length of pre-shared key algorithm (one byte) - i = buf.get(); - b = new byte[i]; - buf.get(b, 0, i); - String alg = new String(b); - // Get length of encoding - i = Short.toUnsignedInt(buf.getShort()); - // Get encoding - b = new byte[i]; - buf.get(b); - this.preSharedKey = new SecretKeySpec(b, alg); - // Get identity len - i = buf.get(); - if (i > 0) { - this.pskIdentity = new byte[buf.get()]; - buf.get(pskIdentity); - } else { - this.pskIdentity = null; + } + + if (same) { + this.localCerts = ((X509Possession) pos).popCerts; + if (SSLLogger.isOn && SSLLogger.isOn("ssl,session")) { + SSLLogger.fine("Restored " + len + + " local certificates from session ticket" + + " for algorithms " + Arrays.toString(certAlgs)); + } + } else { + this.localCerts = null; + this.invalidated = true; + if (SSLLogger.isOn && SSLLogger.isOn("ssl,session")) { + SSLLogger.warning("Local certificates can not be restored " + + "from session ticket " + + "for algorithms " + Arrays.toString(certAlgs)); } - break; - default: - throw new SSLException("Failed local certs of session."); + } } - context = (SSLSessionContextImpl) + this.context = (SSLSessionContextImpl) hc.sslContext.engineGetServerSessionContext(); this.lastUsedTime = System.currentTimeMillis(); } @@ -560,49 +516,25 @@ byte[] write() throws Exception { hos.putInt16(s.id); } - // Peer Supported signature algorithms - hos.putInt8(peerSupportedSignAlgs.size()); - for (SignatureScheme s : peerSupportedSignAlgs) { - hos.putInt16(s.id); - } - - // PSK - if (preSharedKey == null || - preSharedKey.getAlgorithm() == null) { - hos.putInt16(0); - } else { - hos.putInt16(preSharedKey.getAlgorithm().length()); - if (preSharedKey.getAlgorithm().length() != 0) { - hos.write(preSharedKey.getAlgorithm().getBytes()); + // PreSharedKey is only needed by TLSv1.3, + // masterSecret is only needed by pre-TLSv1.3. + if (protocolVersion.useTLS13PlusSpec()) { + // PSK + if (preSharedKey == null) { + hos.putInt16(0); + } else { + hos.putBytes16(preSharedKey.getEncoded()); } - b = preSharedKey.getEncoded(); - hos.putInt16(b.length); - hos.write(b, 0, b.length); - } - - // PSK Identity - if (pskIdentity == null) { - hos.putInt8(0); } else { - hos.putInt8(pskIdentity.length); - hos.write(pskIdentity, 0, pskIdentity.length); - } - - // Master Secret - if (getMasterSecret() == null || - getMasterSecret().getAlgorithm() == null) { - hos.putInt8(0); - } else { - hos.putInt8(getMasterSecret().getAlgorithm().length()); - if (getMasterSecret().getAlgorithm().length() != 0) { - hos.write(getMasterSecret().getAlgorithm().getBytes()); + // Master Secret + if (getMasterSecret() == null) { + hos.putInt16(0); + } else { + hos.putBytes16(masterSecret.getEncoded()); } - b = getMasterSecret().getEncoded(); - hos.putInt16(b.length); - hos.write(b, 0, b.length); - } - hos.putInt8(useExtendedMasterSecret ? 1 : 0); + hos.putInt8(useExtendedMasterSecret ? 1 : 0); + } // Identification Protocol if (identificationProtocol == null) { @@ -636,20 +568,11 @@ byte[] write() throws Exception { hos.putInt32(maximumPacketSize); hos.putInt32(negotiatedMaxFragLen); - // creation time + // Creation time ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES); hos.writeBytes(buffer.putLong(creationTime).array()); - // Status Responses - List list = getStatusResponses(); - int l = list.size(); - hos.putInt16(l); - for (byte[] e : list) { - hos.putInt16(e.length); - hos.write(e); - } - - // peer Host & Port + // Peer Host & Port if (host == null || host.length() == 0) { hos.putInt8(0); } else { @@ -658,7 +581,7 @@ byte[] write() throws Exception { } hos.putInt16(port); - // Peer cert + // Peer certs. if (peerCerts == null || peerCerts.length == 0) { hos.putInt8(0); } else { @@ -670,38 +593,41 @@ byte[] write() throws Exception { } } - // Client identity - if (localCerts != null && localCerts.length > 0) { - // certificate based - hos.putInt8(1); + // Local certificates' algorithms and checksums. + // We don't include the complete local certificates in a session ticket + // to decrease the size of ClientHello message. + if (localCerts == null || localCerts.length == 0) { + hos.putInt8(0); + } else { hos.putInt8(localCerts.length); for (X509Certificate c : localCerts) { - b = c.getEncoded(); - hos.putInt32(b.length); - hos.writeBytes(b); + hos.putBytes8(c.getPublicKey().getAlgorithm().getBytes()); + hos.putInt32(getChecksum(c.getEncoded())); } - } else if (preSharedKey != null) { - // pre-shared key - hos.putInt8(2); - hos.putInt8(preSharedKey.getAlgorithm().length()); - hos.write(preSharedKey.getAlgorithm().getBytes()); - b = preSharedKey.getEncoded(); - hos.putInt32(b.length); - hos.writeBytes(b); - hos.putInt32(pskIdentity.length); - hos.writeBytes(pskIdentity); - } else { - // anonymous - hos.putInt8(0); } return hos.toByteArray(); } + private static int getChecksum(byte[] input) { + Adler32 adler32 = new Adler32(); + adler32.update(input); + return (int) adler32.getValue(); + } + void setMasterSecret(SecretKey secret) { masterSecret = secret; } + void setExporterMasterSecret(SecretKey secret) { + exporterMasterSecret = secret; + } + + void setRandoms(RandomCookie client, RandomCookie server) { + clientRandom = client; + serverRandom = server; + } + void setResumptionMasterSecret(SecretKey secret) { resumptionMasterSecret = secret; } @@ -1300,12 +1226,12 @@ public String[] getValueNames() { /** * Use large packet sizes now or follow RFC 2246 packet sizes (2^14) * until changed. - * + *

                * In the TLS specification (section 6.2.1, RFC2246), it is not * recommended that the plaintext has more than 2^14 bytes. * However, some TLS implementations violate the specification. * This is a workaround for interoperability with these stacks. - * + *

                * Application could accept large fragments up to 2^15 bytes by * setting the system property jsse.SSLEngine.acceptLargeFragments * to "true". @@ -1318,7 +1244,7 @@ public String[] getValueNames() { * Expand the buffer size of both SSL/TLS network packet and * application data. */ - protected void expandBufferSizes() { + void expandBufferSizes() { sessionLock.lock(); try { acceptLargeFragments = true; @@ -1487,6 +1413,269 @@ public List getRequestedServerNames() { return requestedServerNames; } + /* + * keyAlg is used for switching between Keys/Data. If keyAlg is + * non-null, we are producing a Key, otherwise data. + */ + public Object exportKeyingMaterial( + String keyAlg, String label, byte[] context, int length) + throws SSLKeyException { + + // Global preconditions + + Objects.requireNonNull(label, "label can not be null"); + if (length < 1) { + throw new IllegalArgumentException( + "length must be positive"); + } + + // Calculations are primarily based on protocol version. + if (protocolVersion.useTLS13PlusSpec()) { + + // Unlikely, but check anyway. + if (exporterMasterSecret == null) { + throw new IllegalStateException( + "Exporter master secret not captured"); + } + + // TLS 1.3+ using HKDF-based calcs. + // TLS 1.3 (RFC 8446) + + // Check the label/context lengths: + // struct { + // uint16 length = Length; + // opaque label<7..255> = "tls13 " + Label; + // opaque context<0..255> = Context; + // } HkdfLabel; + // label can have 249 bytes (+6 for "tls13 "), and context 255 + + // RFC 8446 allows for length of 2^16-1 (65536), but RFC 5869 + // states: + // + // L length of output keying material in octets + // (<= 255*HashLen) + if (length > (255 * cipherSuite.hashAlg.hashLength )) { + throw new IllegalArgumentException( + "length is too large"); + } + + byte[] hkdfInfoLabel = + ("tls13 " + label).getBytes(StandardCharsets.UTF_8); + if ((hkdfInfoLabel.length < 7) || hkdfInfoLabel.length > 255) { + throw new IllegalArgumentException( + "label length outside range"); + } + + // If no context (null) is provided, RFC 8446 requires an empty + // context be used, unlike RFC 5705. + context = (context != null ? context : new byte[0]); + if (context.length > 255) { + throw new IllegalArgumentException( + "context length outside range"); + } + + // Do RFC 8446:7.1-7.5 calculations + + /* + * TLS-Exporter(label, context_value, key_length) = + * HKDF-Expand-Label(Derive-Secret(Secret, label, ""), + * "exporter", Hash(context_value), key_length) + * + * Derive-Secret(Secret, Label, Messages) = + * HKDF-Expand-Label(Secret, Label, + * Transcript-Hash(Messages), Hash.length) + */ + + try { + // Use the ciphersuite's hashAlg for these calcs. + HashAlg hashAlg = cipherSuite.hashAlg; + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); + + // First calculate the inner Derive-Secret(Secret, label, "") + MessageDigest md; + byte[] emptyHash; + + // Create the "" digest... + try { + md = MessageDigest.getInstance(hashAlg.toString()); + emptyHash = md.digest(); + } catch (NoSuchAlgorithmException nsae) { + throw new ProviderException( + "Hash algorithm " + cipherSuite.hashAlg.name + + " is not available", nsae); + } + + // ...then the hkdfInfo... + byte[] hkdfInfo = SSLSecretDerivation.createHkdfInfo( + hkdfInfoLabel, emptyHash, hashAlg.hashLength); + + // ...then the "inner" HKDF-Expand-Label() to get the + // derivedSecret that is used as the Secret in the "outer" + // HKDF-Expand-Label(). + SecretKey derivedSecret = hkdf.deriveKey("TlsKey", + HKDFParameterSpec.expandOnly(exporterMasterSecret, + hkdfInfo, hashAlg.hashLength)); + try { + // Now do the "outer" HKDF-Expand-Label. + // HKDF-Expand-Label(derivedSecret, "exporter", + // Hash(context_value), key_length) + + // If a context was supplied, use it, otherwise, use the + // previous hashed value of ""... + byte[] hash = ((context.length > 0) ? + md.digest(context) : emptyHash); + + // ...now the hkdfInfo... + hkdfInfo = SSLSecretDerivation.createHkdfInfo( + ("tls13 exporter").getBytes(StandardCharsets.UTF_8), + hash, length); + + // ...now the final expand. + return ((keyAlg != null) ? + hkdf.deriveKey(keyAlg, + HKDFParameterSpec.expandOnly(derivedSecret, + hkdfInfo, length)) : + hkdf.deriveData( + HKDFParameterSpec.expandOnly(derivedSecret, + hkdfInfo, length))); + } finally { + KeyUtil.destroySecretKeys(derivedSecret); + } + } catch (Exception e) { + // For whatever reason, we couldn't generate. Wrap and return. + throw new SSLKeyException("Couldn't generate Exporter/HKDF", e); + } + } else if (protocolVersion.useTLS10PlusSpec()) { + + // Unlikely, but check if randoms were not captured. + if (clientRandom == null || serverRandom == null) { + throw new IllegalStateException("Random nonces not captured"); + } + + // RFC 7505 using PRF-based calcs. + // TLS 1/1.1/1.2 (RFCs 2246/4346/5246) or + // DTLS 1.0/1.2 (RFCs 4347/6347) + + // Note: In RFC 7627: + // + // If a client or server chooses to continue with a full handshake + // without the extended master secret extension ... they MUST NOT + // export any key material based on the new master secret for any + // subsequent application-level authentication ... it MUST + // disable [RFC5705] ... + if (!useExtendedMasterSecret) { + throw new SSLKeyException( + "Exporters require extended master secrets"); + } + + // Check for a "disambiguating label string" (i.e. non-empty). + // Don't see a max length restriction. + if (label.isEmpty()) { + throw new IllegalArgumentException( + "label length outside range"); + } + + // context length must fit in 2 unsigned bytes. + if ((context != null) && (context.length > 0xFFFF)) { + throw new IllegalArgumentException( + "Only 16-bit context lengths supported"); + } + + // Perform RFC 5705 calculations using the internal SunJCE PRF. + String prfAlg; + HashAlg hashAlg; + if (protocolVersion == TLS12) { + prfAlg = "SunTls12Prf"; + hashAlg = cipherSuite.hashAlg; + } else { // all other cases + prfAlg = "SunTlsPrf"; + hashAlg = H_NONE; + } + + // Make a seed with randoms and optional context + // Note that if context is null, it is omitted from the calc + byte[] clientRandomBytes = clientRandom.randomBytes; + byte[] serverRandomBytes = serverRandom.randomBytes; + byte[] seed = new byte[ + clientRandomBytes.length + serverRandomBytes.length + + ((context != null) ? (2 + context.length) : 0)]; + + int pos = 0; + System.arraycopy( + clientRandomBytes, 0, seed, pos, clientRandomBytes.length); + pos += clientRandomBytes.length; + System.arraycopy( + serverRandomBytes, 0, seed, pos, serverRandomBytes.length); + pos += serverRandomBytes.length; + if (context != null) { + // RFC 5705, "If no context is provided, ..." + seed[pos++] = (byte) ((context.length >> 8) & 0xFF); + seed[pos++] = (byte) ((context.length) & 0xFF); + System.arraycopy( + context, 0, seed, pos, context.length); + } + + // Call the PRF function. + try { + @SuppressWarnings("deprecation") + TlsPrfParameterSpec spec = new TlsPrfParameterSpec( + masterSecret, (keyAlg == null) ? "TlsKey" : keyAlg, + label, seed, length, + hashAlg.name, hashAlg.hashLength, hashAlg.blockSize); + KeyGenerator kg = KeyGenerator.getInstance(prfAlg); + kg.init(spec); + SecretKey key = kg.generateKey(); + if (keyAlg != null) { + return key; + } else { + byte[] b = key.getEncoded(); + if (b == null) { + throw new UnsupportedOperationException( + "Could not extract encoding from SecretKey"); + } + return b; + } + } catch (NoSuchAlgorithmException | + InvalidAlgorithmParameterException e) { + throw new SSLKeyException("Could not generate Exporter/PRF", e); + } + } else { + // SSLv3 is vulnerable to a triple handshake attack and can't be + // mitigated by RFC 7627. Don't support this or any other + // unknown protocol. + throw new SSLKeyException( + "Exporters not supported in " + protocolVersion); + } + } + + /** + * Generate Exported Key Material (EKM) calculated according to the + * algorithms defined in RFCs 5705/8446. + */ + @Override + public SecretKey exportKeyingMaterialKey(String keyAlg, + String label, byte[] context, int length) throws SSLKeyException { + + Objects.requireNonNull(keyAlg, "keyAlg can not be null"); + if (keyAlg.isEmpty()) { + throw new IllegalArgumentException( + "keyAlg is empty"); + } + + return (SecretKey) exportKeyingMaterial(keyAlg, label, context, + length); + } + + /** + * Generate Exported Key Material (EKM) calculated according to the + * algorithms defined in RFCs 5705/8446. + */ + @Override + public byte[] exportKeyingMaterialData( + String label, byte[] context, int length) throws SSLKeyException { + return (byte[])exportKeyingMaterial(null, label, context, length); + } + /** Returns a string representation of this SSL session */ @Override public String toString() { 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 b17a03f0cb4..1db07c77160 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,8 +30,10 @@ import java.security.GeneralSecurityException; import java.security.ProviderException; import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.KDF; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.SSLHandshakeException; @@ -69,7 +71,6 @@ static SSLTrafficKeyDerivation valueOf(ProtocolVersion protocolVersion) { case TLS13: return SSLTrafficKeyDerivation.TLS13; } - return null; } @@ -143,16 +144,29 @@ static final class T13TrafficKeyDerivation implements SSLKeyDerivation { } @Override - public SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - KeySchedule ks = KeySchedule.valueOf(algorithm); + public SecretKey deriveKey(String type) throws IOException { + KeySchedule ks = KeySchedule.valueOf(type); + try { + KDF hkdf = KDF.getInstance(cs.hashAlg.hkdfAlgorithm); + byte[] hkdfInfo = createHkdfInfo(ks.label, ks.getKeyLength(cs)); + HKDFParameterSpec spec = HKDFParameterSpec.expandOnly(secret, + hkdfInfo, ks.getKeyLength(cs)); + return hkdf.deriveKey(ks.getAlgorithm(cs, type), spec); + } catch (GeneralSecurityException gse) { + throw new SSLHandshakeException( + "Could not generate secret", gse); + } + } + + @Override + public byte[] deriveData(String type) throws IOException { + KeySchedule ks = KeySchedule.valueOf(type); try { - HKDF hkdf = new HKDF(cs.hashAlg.name); - byte[] hkdfInfo = - createHkdfInfo(ks.label, ks.getKeyLength(cs)); - return hkdf.expand(secret, hkdfInfo, - ks.getKeyLength(cs), - ks.getAlgorithm(cs, algorithm)); + KDF hkdf = KDF.getInstance(cs.hashAlg.hkdfAlgorithm); + byte[] hkdfInfo = createHkdfInfo(ks.label, ks.getKeyLength(cs)); + HKDFParameterSpec spec = HKDFParameterSpec.expandOnly(secret, + hkdfInfo, ks.getKeyLength(cs)); + return hkdf.deriveData(spec); } catch (GeneralSecurityException gse) { throw new SSLHandshakeException( "Could not generate secret", gse); @@ -171,13 +185,12 @@ private static byte[] createHkdfInfo( // unlikely throw new RuntimeException("Unexpected exception", ioe); } - return info; } } private enum KeySchedule { - // Note that we use enum name as the key/ name. + // Note that we use enum name as the key name. TlsKey ("key", false), TlsIv ("iv", true), TlsUpdateNplus1 ("traffic upd", false); @@ -285,8 +298,9 @@ static final class LegacyTrafficKeyDerivation implements SSLKeyDerivation { } } - SecretKey getTrafficKey(String algorithm) { - switch (algorithm) { + @Override + public SecretKey deriveKey(String type) throws IOException { + switch (type) { case "clientMacKey": return keyMaterialSpec.getClientMacKey(); case "serverMacKey": @@ -295,24 +309,25 @@ SecretKey getTrafficKey(String algorithm) { return keyMaterialSpec.getClientCipherKey(); case "serverWriteKey": return keyMaterialSpec.getServerCipherKey(); + default: + throw new SSLHandshakeException( + "Cannot deriveKey for " + type); + } + } + + @Override + public byte[] deriveData(String type) throws IOException { + switch (type) { case "clientWriteIv": IvParameterSpec cliIvSpec = keyMaterialSpec.getClientIv(); - return (cliIvSpec == null) ? null : - new SecretKeySpec(cliIvSpec.getIV(), "TlsIv"); + return (cliIvSpec == null) ? null : cliIvSpec.getIV(); case "serverWriteIv": IvParameterSpec srvIvSpec = keyMaterialSpec.getServerIv(); - return (srvIvSpec == null) ? null : - new SecretKeySpec(srvIvSpec.getIV(), "TlsIv"); + return (srvIvSpec == null) ? null : srvIvSpec.getIV(); + default: + throw new SSLHandshakeException( + "Cannot deriveData for " + type); } - - return null; - } - - @Override - public SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - return getTrafficKey(algorithm); } } } - 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 303095a0722..d092d6c07de 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -32,7 +32,9 @@ import java.security.GeneralSecurityException; import java.text.MessageFormat; import java.util.*; +import javax.crypto.KDF; import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; import javax.crypto.spec.IvParameterSpec; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; @@ -354,6 +356,9 @@ public byte[] produce(ConnectionContext context, clientHello); shc.serverHelloRandom = shm.serverRandom; + shc.handshakeSession.setRandoms(shc.clientHelloRandom, + shc.serverHelloRandom); + // Produce extensions for ServerHello handshake message. SSLExtension[] serverHelloExtensions = shc.sslConfig.getEnabledExtensions( @@ -585,7 +590,7 @@ public byte[] produce(ConnectionContext context, SSLKeyDerivation handshakeKD = ke.createKeyDerivation(shc); SecretKey handshakeSecret = handshakeKD.deriveKey( - "TlsHandshakeSecret", null); + "TlsHandshakeSecret"); SSLTrafficKeyDerivation kdg = SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol); @@ -601,15 +606,12 @@ public byte[] produce(ConnectionContext context, // update the handshake traffic read keys. SecretKey readSecret = kd.deriveKey( - "TlsClientHandshakeTrafficSecret", null); + "TlsClientHandshakeTrafficSecret"); SSLKeyDerivation readKD = kdg.createKeyDerivation(shc, readSecret); - SecretKey readKey = readKD.deriveKey( - "TlsKey", null); - SecretKey readIvSecret = readKD.deriveKey( - "TlsIv", null); + SecretKey readKey = readKD.deriveKey("TlsKey"); IvParameterSpec readIv = - new IvParameterSpec(readIvSecret.getEncoded()); + new IvParameterSpec(readKD.deriveData("TlsIv")); SSLReadCipher readCipher; try { readCipher = @@ -635,15 +637,12 @@ public byte[] produce(ConnectionContext context, // update the handshake traffic write secret. SecretKey writeSecret = kd.deriveKey( - "TlsServerHandshakeTrafficSecret", null); + "TlsServerHandshakeTrafficSecret"); SSLKeyDerivation writeKD = kdg.createKeyDerivation(shc, writeSecret); - SecretKey writeKey = writeKD.deriveKey( - "TlsKey", null); - SecretKey writeIvSecret = writeKD.deriveKey( - "TlsIv", null); + SecretKey writeKey = writeKD.deriveKey("TlsKey"); IvParameterSpec writeIv = - new IvParameterSpec(writeIvSecret.getEncoded()); + new IvParameterSpec(writeKD.deriveData("TlsIv")); SSLWriteCipher writeCipher; try { writeCipher = @@ -1133,6 +1132,9 @@ public void consume(ConnectionContext context, chc.sslConfig.maximumPacketSize); } + chc.handshakeSession.setRandoms(chc.clientHelloRandom, + chc.serverHelloRandom); + // // update // @@ -1195,12 +1197,13 @@ private static void setUpPskKD(HandshakeContext hc, try { CipherSuite.HashAlg hashAlg = hc.negotiatedCipherSuite.hashAlg; - HKDF hkdf = new HKDF(hashAlg.name); - byte[] zeros = new byte[hashAlg.hashLength]; - SecretKey earlySecret = hkdf.extract(zeros, psk, "TlsEarlySecret"); + KDF hkdf = KDF.getInstance(hashAlg.hkdfAlgorithm); + SecretKey earlySecret = hkdf.deriveKey("TlsEarlySecret", + HKDFParameterSpec.ofExtract().addIKM(psk) + .addSalt(new byte[hashAlg.hashLength]).extractOnly()); hc.handshakeKeyDerivation = new SSLSecretDerivation(hc, earlySecret); - } catch (GeneralSecurityException gse) { + } catch (GeneralSecurityException gse) { throw new SSLHandshakeException("Could not generate secret", gse); } } @@ -1284,7 +1287,7 @@ public void consume(ConnectionContext context, SSLKeyDerivation handshakeKD = ke.createKeyDerivation(chc); SecretKey handshakeSecret = handshakeKD.deriveKey( - "TlsHandshakeSecret", null); + "TlsHandshakeSecret"); SSLTrafficKeyDerivation kdg = SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol); if (kdg == null) { @@ -1299,16 +1302,13 @@ public void consume(ConnectionContext context, // update the handshake traffic read keys. SecretKey readSecret = secretKD.deriveKey( - "TlsServerHandshakeTrafficSecret", null); + "TlsServerHandshakeTrafficSecret"); SSLKeyDerivation readKD = kdg.createKeyDerivation(chc, readSecret); - SecretKey readKey = readKD.deriveKey( - "TlsKey", null); - SecretKey readIvSecret = readKD.deriveKey( - "TlsIv", null); + SecretKey readKey = readKD.deriveKey("TlsKey"); IvParameterSpec readIv = - new IvParameterSpec(readIvSecret.getEncoded()); + new IvParameterSpec(readKD.deriveData("TlsIv")); SSLReadCipher readCipher; try { readCipher = @@ -1334,15 +1334,12 @@ public void consume(ConnectionContext context, // update the handshake traffic write keys. SecretKey writeSecret = secretKD.deriveKey( - "TlsClientHandshakeTrafficSecret", null); + "TlsClientHandshakeTrafficSecret"); SSLKeyDerivation writeKD = kdg.createKeyDerivation(chc, writeSecret); - SecretKey writeKey = writeKD.deriveKey( - "TlsKey", null); - SecretKey writeIvSecret = writeKD.deriveKey( - "TlsIv", null); + SecretKey writeKey = writeKD.deriveKey("TlsKey"); IvParameterSpec writeIv = - new IvParameterSpec(writeIvSecret.getEncoded()); + new IvParameterSpec(writeKD.deriveData("TlsIv")); SSLWriteCipher writeCipher; try { writeCipher = diff --git a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java index 6cf930619f7..c0d2bea77ca 100644 --- a/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SessionTicketExtension.java @@ -25,12 +25,16 @@ package sun.security.ssl; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.text.MessageFormat; import java.util.Locale; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; @@ -70,6 +74,9 @@ final class SessionTicketExtension { new T12SHSessionTicketConsumer(); static final SSLStringizer steStringizer = new SessionTicketStringizer(); + // No need to compress a ticket if it can fit in a single packet. + // Besides, small buffers often end up to be larger when compressed. + static final int MIN_COMPRESS_SIZE = 600; // Time in milliseconds until key is changed for encrypting session state private static final int TIMEOUT_DEFAULT = 3600 * 1000; @@ -196,7 +203,7 @@ static final class SessionTicketSpec implements SSLExtensionSpec { data = buf; } - public byte[] encrypt(HandshakeContext hc, SSLSessionImpl session) { + byte[] encrypt(HandshakeContext hc, SSLSessionImpl session) { byte[] encrypted; if (!hc.statelessResumption || @@ -213,26 +220,34 @@ public byte[] encrypt(HandshakeContext hc, SSLSessionImpl session) { Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); c.init(Cipher.ENCRYPT_MODE, key.key, new GCMParameterSpec(GCM_TAG_LEN, iv)); - c.updateAAD(new byte[] { - (byte)(key.num >>> 24), - (byte)(key.num >>> 16), - (byte)(key.num >>> 8), - (byte)(key.num)} - ); + byte[] data = session.write(); if (data.length == 0) { return data; } + + // Compress the session before encryption if needed. + byte compressed = 0; + if (data.length >= MIN_COMPRESS_SIZE) { + data = compress(data); + compressed = 1; + } + + ByteBuffer aad = ByteBuffer.allocate(Integer.BYTES + 1); + aad.putInt(key.num).put(compressed); + c.updateAAD(aad); + encrypted = c.doFinal(data); byte[] result = new byte[encrypted.length + Integer.BYTES + - iv.length]; + iv.length + 1]; result[0] = (byte)(key.num >>> 24); result[1] = (byte)(key.num >>> 16); result[2] = (byte)(key.num >>> 8); result[3] = (byte)(key.num); System.arraycopy(iv, 0, result, Integer.BYTES, iv.length); + result[Integer.BYTES + iv.length] = compressed; System.arraycopy(encrypted, 0, result, - Integer.BYTES + iv.length, encrypted.length); + Integer.BYTES + iv.length + 1, encrypted.length); return result; } catch (Exception e) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { @@ -257,26 +272,67 @@ ByteBuffer decrypt(HandshakeContext hc) { Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); c.init(Cipher.DECRYPT_MODE, key.key, new GCMParameterSpec(GCM_TAG_LEN, iv)); - c.updateAAD(new byte[] { - (byte)(keyID >>> 24), - (byte)(keyID >>> 16), - (byte)(keyID >>> 8), - (byte)(keyID)} - ); - - ByteBuffer out; - out = ByteBuffer.allocate(data.remaining() - GCM_TAG_LEN / 8); + + byte compressed = data.get(); + ByteBuffer aad = ByteBuffer.allocate(Integer.BYTES + 1); + aad.putInt(keyID).put(compressed); + c.updateAAD(aad); + + ByteBuffer out = ByteBuffer.allocate( + data.remaining() - GCM_TAG_LEN / 8); c.doFinal(data, out); out.flip(); + + // Decompress the session after decryption if needed. + if (compressed == 1) { + out = decompress(out); + } + return out; } catch (Exception e) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine("Decryption failed." + e.getMessage()); } } + return null; } + private static byte[] compress(byte[] input) throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + GZIPOutputStream gos = new GZIPOutputStream(baos)) { + final int decompressedLen = input.length; + gos.write(input, 0, decompressedLen); + gos.finish(); + + if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + SSLLogger.fine("decompressed bytes: " + decompressedLen + + "; compressed bytes: " + baos.size()); + } + + return baos.toByteArray(); + } + } + + private static ByteBuffer decompress(ByteBuffer input) + throws IOException { + final int compressedLen = input.remaining(); + byte[] bytes = new byte[compressedLen]; + input.get(bytes); + + try (GZIPInputStream gis = new GZIPInputStream( + new ByteArrayInputStream(bytes))) { + byte[] out = gis.readAllBytes(); + + if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + SSLLogger.fine("compressed bytes: " + compressedLen + + "; decompressed bytes: " + out.length); + } + + return ByteBuffer.wrap(out); + } + } + byte[] getEncoded() { byte[] out = new byte[data.capacity()]; data.duplicate().get(out); diff --git a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java index 80029e73afb..a95b31583bb 100644 --- a/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java @@ -25,6 +25,7 @@ package sun.security.ssl; +import static sun.security.ssl.SignatureScheme.CERTIFICATE_SCOPE; import static sun.security.ssl.SignatureScheme.HANDSHAKE_SCOPE; import java.io.IOException; @@ -33,6 +34,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; +import javax.net.ssl.SSLException; import javax.net.ssl.SSLProtocolException; import sun.security.ssl.SSLExtension.ExtensionConsumer; import sun.security.ssl.SSLExtension.SSLExtensionSpec; @@ -270,30 +272,8 @@ public void consume(ConnectionContext context, return; } - // update the context - List sss = - SignatureScheme.getSupportedAlgorithms( - shc.sslConfig, - shc.algorithmConstraints, shc.negotiatedProtocol, - spec.signatureSchemes, - HANDSHAKE_SCOPE); - - if (sss == null || sss.isEmpty()) { - throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE, - "No supported signature algorithm"); - } - shc.peerRequestedSignatureSchemes = sss; - - // If no "signature_algorithms_cert" extension is present, then - // the "signature_algorithms" extension also applies to - // signatures appearing in certificates. - SignatureSchemesSpec certSpec = - (SignatureSchemesSpec)shc.handshakeExtensions.get( - SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT); - if (certSpec == null) { - shc.peerRequestedCertSignSchemes = sss; - shc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); - } + updateHandshakeContext(shc, spec.signatureSchemes, + SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT); if (!shc.isResumption && shc.negotiatedProtocol.useTLS13PlusSpec()) { @@ -497,30 +477,8 @@ public void consume(ConnectionContext context, return; } - // update the context - List sss = - SignatureScheme.getSupportedAlgorithms( - chc.sslConfig, - chc.algorithmConstraints, chc.negotiatedProtocol, - spec.signatureSchemes, - HANDSHAKE_SCOPE); - - if (sss == null || sss.isEmpty()) { - throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, - "No supported signature algorithm"); - } - chc.peerRequestedSignatureSchemes = sss; - - // If no "signature_algorithms_cert" extension is present, then - // the "signature_algorithms" extension also applies to - // signatures appearing in certificates. - SignatureSchemesSpec certSpec = - (SignatureSchemesSpec)chc.handshakeExtensions.get( - SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT); - if (certSpec == null) { - chc.peerRequestedCertSignSchemes = sss; - chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss); - } + updateHandshakeContext(chc, spec.signatureSchemes, + SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT); } } @@ -543,4 +501,49 @@ public void absent(ConnectionContext context, "received CertificateRequest handshake message"); } } + + // Updates given HandshakeContext with peer signature schemes. + private static void updateHandshakeContext(HandshakeContext hc, + int[] signatureSchemes, SSLExtension signatureAlgorithmsCertExt) + throws SSLException { + List handshakeSS = + SignatureScheme.getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + hc.negotiatedProtocol, + signatureSchemes, + HANDSHAKE_SCOPE); + + if (handshakeSS.isEmpty()) { + throw hc.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No supported signature algorithm"); + } + + hc.peerRequestedSignatureSchemes = handshakeSS; + + // If no "signature_algorithms_cert" extension is present, then + // the "signature_algorithms" extension also applies to + // signatures appearing in certificates. + SignatureSchemesSpec certSpec = + (SignatureSchemesSpec) hc.handshakeExtensions.get( + signatureAlgorithmsCertExt); + + if (certSpec == null) { + List certSS = + SignatureScheme.getSupportedAlgorithms( + hc.sslConfig, + hc.algorithmConstraints, + hc.negotiatedProtocol, + signatureSchemes, + CERTIFICATE_SCOPE); + + if (certSS.isEmpty()) { + throw hc.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No supported signature algorithm"); + } + + hc.peerRequestedCertSignSchemes = certSS; + hc.handshakeSession.setPeerSupportedSignatureAlgorithms(certSS); + } + } } diff --git a/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java b/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java index 8f464e058e2..82dc82362ca 100644 --- a/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java +++ b/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java @@ -112,7 +112,7 @@ private TrustStoreDescriptor(String storeName, String storeType, SSLLogger.fine( "trustStore is: " + storeName + "\n" + "trustStore type is: " + storeType + "\n" + - "trustStore provider is: " + storeProvider + "\n" + + "trustStore provider is: " + (storeProvider.isEmpty() ? "unspecified" : storeProvider) + "\n" + "the last modified time is: " + (new Date(lastModified))); } } 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 74d33c036ef..9f7649fc73c 100644 --- a/src/java.base/share/classes/sun/security/util/Debug.java +++ b/src/java.base/share/classes/sun/security/util/Debug.java @@ -31,8 +31,6 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.HexFormat; -import java.util.regex.Pattern; -import java.util.regex.Matcher; import java.util.Locale; /** @@ -43,14 +41,7 @@ public class Debug { private String prefix; - private boolean printDateTime; - private boolean printThreadDetails; - private static String args; - private static boolean threadInfoAll; - private static boolean timeStampInfoAll; - private static final String TIMESTAMP_OPTION = "+timestamp"; - private static final String THREAD_OPTION = "+thread"; static { args = System.getProperty("java.security.debug"); @@ -65,19 +56,9 @@ public class Debug { } if (args != null) { - args = marshal(args); + args = args.toLowerCase(Locale.ENGLISH); if (args.equals("help")) { Help(); - } else if (args.contains("all")) { - // "all" option has special handling for decorator options - // If the thread or timestamp decorator option is detected - // with the "all" option, then it impacts decorator options - // for other categories - int beginIndex = args.lastIndexOf("all") + "all".length(); - int commaIndex = args.indexOf(',', beginIndex); - if (commaIndex == -1) commaIndex = args.length(); - threadInfoAll = args.substring(beginIndex, commaIndex).contains(THREAD_OPTION); - timeStampInfoAll = args.substring(beginIndex, commaIndex).contains(TIMESTAMP_OPTION); } } } @@ -108,11 +89,6 @@ public static void Help() { System.err.println("ts timestamping"); System.err.println("x509 X.509 certificate debugging"); System.err.println(); - System.err.println("+timestamp can be appended to any of above options to print"); - System.err.println(" a timestamp for that debug option"); - System.err.println("+thread can be appended to any of above options to print"); - System.err.println(" thread and caller information for that debug option"); - System.err.println(); System.err.println("The following can be used with provider:"); System.err.println(); System.err.println("engine="); @@ -153,7 +129,6 @@ public static Debug getInstance(String option, String prefix) { if (isOn(option)) { Debug d = new Debug(); d.prefix = prefix; - d.configureExtras(option); return d; } else { return null; @@ -168,32 +143,6 @@ private static String formatCaller() { .findFirst().orElse("unknown caller")); } - // parse an option string to determine if extra details, - // like thread and timestamp, should be printed - private void configureExtras(String option) { - // treat "all" as special case, only used for java.security.debug property - this.printDateTime = timeStampInfoAll; - this.printThreadDetails = threadInfoAll; - - if (printDateTime && printThreadDetails) { - // nothing left to configure - return; - } - - // args is converted to lower case for the most part via marshal method - int optionIndex = args.lastIndexOf(option); - if (optionIndex == -1) { - // option not in args list. Only here since "all" was present - // in debug property argument. "all" option already parsed - return; - } - int beginIndex = optionIndex + option.length(); - int commaIndex = args.indexOf(',', beginIndex); - if (commaIndex == -1) commaIndex = args.length(); - String subOpt = args.substring(beginIndex, commaIndex); - printDateTime = printDateTime || subOpt.contains(TIMESTAMP_OPTION); - printThreadDetails = printThreadDetails || subOpt.contains(THREAD_OPTION); - } /** * Get a Debug object corresponding to the given option on the given @@ -210,11 +159,6 @@ private void configureExtras(String option) { * Debug debug = Debug.of("login", property); * } * - * +timestamp string can be appended to property value - * to print timestamp information. (e.g. true+timestamp) - * +thread string can be appended to property value - * to print thread and caller information. (e.g. true+thread) - * * @param prefix the debug option name * @param property debug setting for this option * @return a new Debug object if the property is true @@ -223,8 +167,6 @@ public static Debug of(String prefix, String property) { if (property != null && property.toLowerCase(Locale.ROOT).startsWith("true")) { Debug d = new Debug(); d.prefix = prefix; - d.printThreadDetails = property.contains(THREAD_OPTION); - d.printDateTime = property.contains(TIMESTAMP_OPTION); return d; } return null; @@ -287,23 +229,18 @@ public void println(String prefix, String message) { } /** - * If thread debug option enabled, include information containing - * hex value of threadId and the current thread name - * If timestamp debug option enabled, include timestamp string - * @return extra info if debug option enabled. + * Include information containing: + * - hex value of threadId + * - the current thread name + * - timestamp string + * @return String with above metadata */ private String extraInfo() { - String retString = ""; - if (printThreadDetails) { - retString = "0x" + Long.toHexString( - Thread.currentThread().threadId()).toUpperCase(Locale.ROOT) + - "|" + Thread.currentThread().getName() + "|" + formatCaller(); - } - if (printDateTime) { - retString += (retString.isEmpty() ? "" : "|") - + FormatHolder.DATE_TIME_FORMATTER.format(Instant.now()); - } - return retString.isEmpty() ? "" : "[" + retString + "]"; + return String.format("[0x%s|%s|%s|%s]", + Long.toHexString(Thread.currentThread().threadId()).toUpperCase(Locale.ROOT), + Thread.currentThread().getName(), + formatCaller(), + FormatHolder.DATE_TIME_FORMATTER.format(Instant.now())); } /** @@ -349,69 +286,6 @@ public static String toHexString(BigInteger b) { return sb.toString(); } - /** - * change a string into lower case except permission classes and URLs. - */ - private static String marshal(String args) { - if (args != null) { - StringBuilder target = new StringBuilder(); - StringBuilder source = new StringBuilder(args); - - // obtain the "permission=" options - // the syntax of classname: IDENTIFIER.IDENTIFIER - // the regular express to match a class name: - // "[a-zA-Z_$][a-zA-Z0-9_$]*([.][a-zA-Z_$][a-zA-Z0-9_$]*)*" - String keyReg = "[Pp][Ee][Rr][Mm][Ii][Ss][Ss][Ii][Oo][Nn]="; - String keyStr = "permission="; - String reg = keyReg + - "[a-zA-Z_$][a-zA-Z0-9_$]*([.][a-zA-Z_$][a-zA-Z0-9_$]*)*"; - Pattern pattern = Pattern.compile(reg); - Matcher matcher = pattern.matcher(source); - StringBuilder left = new StringBuilder(); - while (matcher.find()) { - String matched = matcher.group(); - target.append(matched.replaceFirst(keyReg, keyStr)); - target.append(" "); - - // delete the matched sequence - matcher.appendReplacement(left, ""); - } - matcher.appendTail(left); - source = left; - - // obtain the "codebase=" options - // the syntax of URL is too flexible, and here assumes that the - // URL contains no space, comma(','), and semicolon(';'). That - // also means those characters also could be used as separator - // after codebase option. - // However, the assumption is incorrect in some special situation - // when the URL contains comma or semicolon - keyReg = "[Cc][Oo][Dd][Ee][Bb][Aa][Ss][Ee]="; - keyStr = "codebase="; - reg = keyReg + "[^, ;]*"; - pattern = Pattern.compile(reg); - matcher = pattern.matcher(source); - left = new StringBuilder(); - while (matcher.find()) { - String matched = matcher.group(); - target.append(matched.replaceFirst(keyReg, keyStr)); - target.append(" "); - - // delete the matched sequence - matcher.appendReplacement(left, ""); - } - matcher.appendTail(left); - source = left; - - // convert the rest to lower-case characters - target.append(source.toString().toLowerCase(Locale.ENGLISH)); - - return target.toString(); - } - - return null; - } - public static String toString(byte[] b) { if (b == null) { return "(null)"; diff --git a/src/java.base/share/classes/sun/security/util/DerValue.java b/src/java.base/share/classes/sun/security/util/DerValue.java index f2fcf350b39..19e7083180b 100644 --- a/src/java.base/share/classes/sun/security/util/DerValue.java +++ b/src/java.base/share/classes/sun/security/util/DerValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * 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 @@ public class DerValue { /** The tag class types */ public static final byte TAG_UNIVERSAL = (byte)0x000; + public static final byte TAG_CONSTRUCT = (byte)0x020; public static final byte TAG_APPLICATION = (byte)0x040; public static final byte TAG_CONTEXT = (byte)0x080; public static final byte TAG_PRIVATE = (byte)0x0c0; diff --git a/src/java.base/share/classes/sun/security/util/DomainName.java b/src/java.base/share/classes/sun/security/util/DomainName.java index 53a646c8102..4f577f1114c 100644 --- a/src/java.base/share/classes/sun/security/util/DomainName.java +++ b/src/java.base/share/classes/sun/security/util/DomainName.java @@ -61,7 +61,7 @@ * co.uk * k12.ak.us * com.tw - * \u7db2\u8def.tw + * 網路.tw * * Public suffixes effectively denote registration authorities. * diff --git a/src/java.base/share/classes/sun/security/util/FilePermCompat.java b/src/java.base/share/classes/sun/security/util/FilePermCompat.java deleted file mode 100644 index 651c84a462b..00000000000 --- a/src/java.base/share/classes/sun/security/util/FilePermCompat.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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.io.FilePermission; -import java.security.Permission; -import jdk.internal.access.SharedSecrets; - -/** - * Take care of FilePermission compatibility after JDK-8164705. - */ -public class FilePermCompat { - /** - * New behavior? Keep compatibility? Both default true. - */ - public static final boolean nb; - public static final boolean compat; - - static { - String flag = SecurityProperties.getOverridableProperty( - "jdk.io.permissionsUseCanonicalPath"); - if (flag == null) { - flag = "false"; - } - switch (flag) { - case "true": - nb = false; - compat = false; - break; - case "false": - nb = true; - compat = true; - break; - default: - throw new RuntimeException( - "Invalid jdk.io.permissionsUseCanonicalPath: " + flag); - } - } - - @SuppressWarnings("removal") - public static Permission newPermPlusAltPath(Permission input) { - if (compat && input instanceof FilePermission) { - return SharedSecrets.getJavaIOFilePermissionAccess() - .newPermPlusAltPath((FilePermission) input); - } - return input; - } - - @SuppressWarnings("removal") - public static Permission newPermUsingAltPath(Permission input) { - if (input instanceof FilePermission) { - return SharedSecrets.getJavaIOFilePermissionAccess() - .newPermUsingAltPath((FilePermission) input); - } - return null; - } -} 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 95223ec0b12..7a58ac0d4e9 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -36,8 +36,12 @@ import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import javax.crypto.spec.DHPublicKeySpec; +import javax.crypto.spec.SecretKeySpec; +import javax.security.auth.DestroyFailedException; +import jdk.internal.access.SharedSecrets; import sun.security.jca.JCAUtil; +import sun.security.x509.AlgorithmId; /** * A utility class to get key length, validate keys, etc. @@ -457,5 +461,90 @@ public static boolean isSupportedKeyAgreementOutputAlgorithm(String alg) { return alg.equalsIgnoreCase("TlsPremasterSecret") || alg.equalsIgnoreCase("Generic"); } + + // destroy secret keys in a best-effort way + public static void destroySecretKeys(SecretKey... keys) { + for (SecretKey k : keys) { + if (k != null) { + if (k instanceof SecretKeySpec sk) { + SharedSecrets.getJavaxCryptoSpecAccess() + .clearSecretKeySpec(sk); + } else { + try { + k.destroy(); + } catch (DestroyFailedException e) { + // swallow + } + } + } + } + } + + /** + * With a given DER encoded bytes, read through and return the AlgorithmID + * stored if it can be found. If none is found or there is an IOException, + * null is returned. + * + * @param encoded DER encoded bytes + * @return AlgorithmID stored in the DER encoded bytes or null. + */ + public static String getAlgorithm(byte[] encoded) throws IOException { + try { + return getAlgorithmId(encoded).getName(); + } catch (IOException e) { + throw new IOException("No recognized algorithm detected in " + + "encoding", e); + } + } + + /** + * With a given DER encoded bytes, read through and return the AlgorithmID + * stored if it can be found. + * + * @param encoded DER encoded bytes + * @return AlgorithmID stored in the DER encoded bytes + * @throws IOException if there was a DER or other parsing error + */ + public static AlgorithmId getAlgorithmId(byte[] encoded) throws IOException { + DerInputStream is = new DerInputStream(encoded); + DerValue value = is.getDerValue(); + if (value.tag != DerValue.tag_Sequence) { + throw new IOException("Unknown DER Format: Value 1 not a Sequence"); + } + + is = value.data; + value = is.getDerValue(); + // This route is for: RSAPublic, Encrypted RSAPrivate, EC Public, + // Encrypted EC Private, + if (value.tag == DerValue.tag_Sequence) { + return AlgorithmId.parse(value); + } else if (value.tag == DerValue.tag_Integer) { + // RSAPrivate, ECPrivate + // current value is version, which can be ignored + value = is.getDerValue(); + if (value.tag == DerValue.tag_OctetString) { + value = is.getDerValue(); + if (value.tag == DerValue.tag_Sequence) { + return AlgorithmId.parse(value); + } else { + // OpenSSL/X9.62 (0xA0) + ObjectIdentifier oid = value.data.getOID(); + AlgorithmId algo = new AlgorithmId(oid, (AlgorithmParameters) null); + if (CurveDB.lookup(algo.getName()) != null) { + return new AlgorithmId(AlgorithmId.EC_oid); + } + + } + + } else if (value.tag == DerValue.tag_Sequence) { + // Public Key + return AlgorithmId.parse(value); + } + + } + throw new IOException("No algorithm detected"); + } + + } diff --git a/src/java.base/share/classes/sun/security/util/KnownOIDs.java b/src/java.base/share/classes/sun/security/util/KnownOIDs.java index 223dddb7f61..8e764b75730 100644 --- a/src/java.base/share/classes/sun/security/util/KnownOIDs.java +++ b/src/java.base/share/classes/sun/security/util/KnownOIDs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,10 +91,7 @@ public enum KnownOIDs { ipsecEndSystem("1.3.6.1.5.5.7.3.5"), ipsecTunnel("1.3.6.1.5.5.7.3.6"), ipsecUser("1.3.6.1.5.5.7.3.7"), - KP_TimeStamping("1.3.6.1.5.5.7.3.8", "timeStamping") { - @Override - boolean registerNames() { return false; } - }, + KP_TimeStamping("1.3.6.1.5.5.7.3.8", "timeStamping", false), OCSPSigning("1.3.6.1.5.5.7.3.9"), // access descriptors - PKIX.48.* OCSP("1.3.6.1.5.5.7.48.1"), @@ -102,10 +99,7 @@ public enum KnownOIDs { OCSPNonceExt("1.3.6.1.5.5.7.48.1.2"), OCSPNoCheck("1.3.6.1.5.5.7.48.1.5"), caIssuers("1.3.6.1.5.5.7.48.2"), - AD_TimeStamping("1.3.6.1.5.5.7.48.3", "timeStamping") { - @Override - boolean registerNames() { return false; } - }, + AD_TimeStamping("1.3.6.1.5.5.7.48.3", "timeStamping", false), caRepository("1.3.6.1.5.5.7.48.5", "caRepository"), // NIST -- @@ -152,8 +146,8 @@ public enum KnownOIDs { SHA3_256("2.16.840.1.101.3.4.2.8", "SHA3-256"), SHA3_384("2.16.840.1.101.3.4.2.9", "SHA3-384"), SHA3_512("2.16.840.1.101.3.4.2.10", "SHA3-512"), - SHAKE128("2.16.840.1.101.3.4.2.11"), - SHAKE256("2.16.840.1.101.3.4.2.12"), + SHAKE128_256("2.16.840.1.101.3.4.2.11", "SHAKE128-256", "SHAKE128"), + SHAKE256_512("2.16.840.1.101.3.4.2.12", "SHAKE256-512", "SHAKE256"), HmacSHA3_224("2.16.840.1.101.3.4.2.13", "HmacSHA3-224"), HmacSHA3_256("2.16.840.1.101.3.4.2.14", "HmacSHA3-256"), HmacSHA3_384("2.16.840.1.101.3.4.2.15", "HmacSHA3-384"), @@ -189,10 +183,7 @@ public enum KnownOIDs { // RSASecurity // PKCS1 1.2.840.113549.1.1.* - PKCS1("1.2.840.113549.1.1", "RSA") { // RSA KeyPairGenerator and KeyFactory - @Override - boolean registerNames() { return false; } - }, + PKCS1("1.2.840.113549.1.1", "RSA", false), // RSA KeyPairGenerator and KeyFactory RSA("1.2.840.113549.1.1.1"), // RSA encryption MD2withRSA("1.2.840.113549.1.1.2"), @@ -322,10 +313,7 @@ public enum KnownOIDs { SpecifiedSHA2withECDSA("1.2.840.10045.4.3"), // X9.42 1.2.840.10046.2.* - X942_DH("1.2.840.10046.2.1", "DiffieHellman") { // unused by JDK providers - @Override - boolean registerNames() { return false; } - }, + X942_DH("1.2.840.10046.2.1", "DiffieHellman", false), // unused by JDK providers // Teletrust 1.3.36.* brainpoolP160r1("1.3.36.3.3.2.8.1.1.1"), @@ -375,34 +363,19 @@ public enum KnownOIDs { // OIW secsig 1.3.14.3.* OIW_DES_CBC("1.3.14.3.2.7", "DES/CBC", "DES"), - OIW_DSA("1.3.14.3.2.12", "DSA") { - @Override - boolean registerNames() { return false; } - }, + OIW_DSA("1.3.14.3.2.12", "DSA", false), - OIW_JDK_SHA1withDSA("1.3.14.3.2.13", "SHA1withDSA") { - @Override - boolean registerNames() { return false; } - }, + OIW_JDK_SHA1withDSA("1.3.14.3.2.13", "SHA1withDSA", false), - OIW_SHA1withRSA_Odd("1.3.14.3.2.15", "SHA1withRSA") { - @Override - boolean registerNames() { return false; } - }, + OIW_SHA1withRSA_Odd("1.3.14.3.2.15", "SHA1withRSA", false), DESede("1.3.14.3.2.17", "DESede"), SHA_1("1.3.14.3.2.26", "SHA-1", "SHA", "SHA1"), - OIW_SHA1withDSA("1.3.14.3.2.27", "SHA1withDSA") { - @Override - boolean registerNames() { return false; } - }, + OIW_SHA1withDSA("1.3.14.3.2.27", "SHA1withDSA", false), - OIW_SHA1withRSA("1.3.14.3.2.29", "SHA1withRSA") { - @Override - boolean registerNames() { return false; } - }, + OIW_SHA1withRSA("1.3.14.3.2.29", "SHA1withRSA", false), // Thawte 1.3.101.* X25519("1.3.101.110"), @@ -426,11 +399,9 @@ public enum KnownOIDs { // Consider removing them in future releases when their usage // have died out - ITUX509_RSA("2.5.8.1.1", "RSA") { // unused by JDK providers - // defined in X.509 for RSA keys - @Override // with modulus length as its parameter - boolean registerNames() { return false; } - }, + ITUX509_RSA("2.5.8.1.1", "RSA", false), // unused by JDK providers + // defined in X.509 for RSA keys + // with modulus length as its parameter SkipIPAddress("1.3.6.1.4.1.42.2.11.2.1"), JAVASOFT_JDKKeyProtector("1.3.6.1.4.1.42.2.17.1.1"), @@ -442,6 +413,7 @@ public enum KnownOIDs { private final String stdName; private final String oid; private final String[] aliases; + private final boolean registerNames; // find the matching enum using either name or oid string // return null if no match found @@ -476,9 +448,8 @@ private static void register(KnownOIDs o) { } else if (debug != null) { debug.println(o.oid + " => " + o.name()); } - // only register the stdName and aliases if o.registerNames() - // returns true - if (o.registerNames()) { + // only register the stdName and aliases if o.registerNames is true + if (o.registerNames) { String stdNameUpper = o.stdName.toUpperCase(Locale.ENGLISH); if (Objects.nonNull(name2enum.put(stdNameUpper, o))) { throw new RuntimeException("ERROR: Duplicate " + @@ -505,12 +476,21 @@ private static void register(KnownOIDs o) { this.oid = oid; this.stdName = name(); // defaults to enum name this.aliases = new String[0]; + this.registerNames = true; } KnownOIDs(String oid, String stdName, String... aliases) { this.oid = oid; this.stdName = stdName; this.aliases = aliases; + this.registerNames = true; + } + + KnownOIDs(String oid, String stdName, boolean registerNames) { + this.oid = oid; + this.stdName = stdName; + this.aliases = new String[0]; + this.registerNames = registerNames; } // returns the oid string associated with this enum @@ -527,8 +507,4 @@ public String stdName() { public String[] aliases() { return aliases; } - - boolean registerNames() { - return true; - } } diff --git a/src/java.base/share/classes/sun/security/util/PBEUtil.java b/src/java.base/share/classes/sun/security/util/PBEUtil.java index 12e71418bf4..5b7d6d5ce83 100644 --- a/src/java.base/share/classes/sun/security/util/PBEUtil.java +++ b/src/java.base/share/classes/sun/security/util/PBEUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Red Hat, Inc. + * Copyright (c) 2023, 2025, 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 @@ -25,6 +25,9 @@ package sun.security.util; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.StandardCharsets; import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -195,10 +198,7 @@ public PBEKeySpec getPBEKeySpec(int blkSize, int keyLength, int opmode, } initialize(blkSize, opmode, iCountInit, saltInit, ivSpecInit, random); - passwdChars = new char[passwdBytes.length]; - for (int i = 0; i < passwdChars.length; i++) { - passwdChars[i] = (char) (passwdBytes[i] & 0x7f); - } + passwdChars = decodePassword(passwdBytes); return new PBEKeySpec(passwdChars, salt, iCount, keyLength); } finally { // password char[] was cloned in PBEKeySpec constructor, @@ -254,7 +254,7 @@ private static int check(int iCount) public static PBEKeySpec getPBAKeySpec(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { - char[] passwdChars; + char[] passwdChars = null; byte[] salt = null; int iCount = 0; if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) { @@ -267,10 +267,7 @@ public static PBEKeySpec getPBAKeySpec(Key key, (passwdBytes = key.getEncoded()) == null) { throw new InvalidKeyException("Missing password"); } - passwdChars = new char[passwdBytes.length]; - for (int i = 0; i < passwdChars.length; i++) { - passwdChars[i] = (char) (passwdBytes[i] & 0x7f); - } + passwdChars = decodePassword(passwdBytes); Arrays.fill(passwdBytes, (byte)0x00); } else { throw new InvalidKeyException("SecretKey of PBE type required"); @@ -286,11 +283,7 @@ public static PBEKeySpec getPBAKeySpec(Key key, "PBEParameterSpec required for salt " + "and iteration count"); } - } else if (!(params instanceof PBEParameterSpec)) { - throw new InvalidAlgorithmParameterException( - "PBEParameterSpec type required"); - } else { - PBEParameterSpec pbeParams = (PBEParameterSpec) params; + } else if (params instanceof PBEParameterSpec pbeParams) { // make sure the parameter values are consistent if (salt != null) { if (!Arrays.equals(salt, pbeParams.getSalt())) { @@ -310,7 +303,11 @@ public static PBEKeySpec getPBAKeySpec(Key key, } else { iCount = pbeParams.getIterationCount(); } + } else { + throw new InvalidAlgorithmParameterException( + "PBEParameterSpec type required"); } + // For security purpose, we need to enforce a minimum length // for salt; just require the minimum salt length to be 8-byte // which is what PKCS#5 recommends and openssl does. @@ -324,32 +321,34 @@ public static PBEKeySpec getPBAKeySpec(Key key, } return new PBEKeySpec(passwdChars, salt, iCount); } finally { - Arrays.fill(passwdChars, '\0'); + if (passwdChars != null) { + Arrays.fill(passwdChars, '\0'); + } } } /* - * Check that the key implements the PBEKey interface. If params is an - * instance of PBEParameterSpec, validate consistency with the key's - * derivation data. Used by P11Mac and P11PBECipher (SunPKCS11). + * Converts the password char[] to the UTF-8 encoded byte[]. Used by PBEKey + * and PBKDF2KeyImpl (SunJCE). */ - public static void checkKeyAndParams(Key key, - AlgorithmParameterSpec params, String algorithm) - throws InvalidKeyException, InvalidAlgorithmParameterException { - if (key instanceof javax.crypto.interfaces.PBEKey pbeKey) { - if (params instanceof PBEParameterSpec pbeParams) { - if (pbeParams.getIterationCount() != - pbeKey.getIterationCount() || - !Arrays.equals(pbeParams.getSalt(), pbeKey.getSalt())) { - throw new InvalidAlgorithmParameterException( - "Salt or iteration count parameters are " + - "not consistent with PBE key"); - } - } - } else { - throw new InvalidKeyException( - "Cannot use a " + algorithm + " service with a key that " + - "does not implement javax.crypto.interfaces.PBEKey"); - } + public static byte[] encodePassword(char[] passwd) { + ByteBuffer bb = StandardCharsets.UTF_8.encode(CharBuffer.wrap(passwd)); + int len = bb.limit(); + byte[] passwdBytes = new byte[len]; + bb.get(passwdBytes, 0, len); + bb.clear().put(new byte[len]); + + return passwdBytes; + } + + // converts the UTF-8 encoded byte[] to the password char[] + private static char[] decodePassword(byte[] passwdBytes) { + CharBuffer cb = StandardCharsets.UTF_8.decode( + ByteBuffer.wrap(passwdBytes)); + int len = cb.limit(); + char[] passwd = new char[len]; + cb.get(passwd); + cb.clear().put(new char[len]); + return passwd; } } diff --git a/src/java.base/share/classes/sun/security/util/Pem.java b/src/java.base/share/classes/sun/security/util/Pem.java index ba01d91c82e..492017eca29 100644 --- a/src/java.base/share/classes/sun/security/util/Pem.java +++ b/src/java.base/share/classes/sun/security/util/Pem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,60 @@ package sun.security.util; -import java.io.IOException; +import sun.security.x509.AlgorithmId; + +import java.io.*; import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.PEMRecord; +import java.security.Security; +import java.util.Arrays; import java.util.Base64; +import java.util.HexFormat; +import java.util.Objects; +import java.util.regex.Pattern; /** * A utility class for PEM format encoding. */ public class Pem { + private static final char WS = 0x20; // Whitespace + private static final byte[] CRLF = new byte[] {'\r', '\n'}; + + // Default algorithm from jdk.epkcs8.defaultAlgorithm in java.security + public static final String DEFAULT_ALGO; + + // Pattern matching for EKPI operations + private static final Pattern PBE_PATTERN; + + // Pattern matching for stripping whitespace. + private static final Pattern STRIP_WHITESPACE_PATTERN; + + // Lazy initialized PBES2 OID value + private static ObjectIdentifier PBES2OID; + + // Lazy initialized singleton encoder. + private static Base64.Encoder b64Encoder; + + static { + String algo = Security.getProperty("jdk.epkcs8.defaultAlgorithm"); + DEFAULT_ALGO = (algo == null || algo.isBlank()) ? + "PBEWithHmacSHA256AndAES_128" : algo; + PBE_PATTERN = Pattern.compile("^PBEWith.*And.*", + Pattern.CASE_INSENSITIVE); + STRIP_WHITESPACE_PATTERN = Pattern.compile("\\s+"); + } + + public static final String CERTIFICATE = "CERTIFICATE"; + public static final String X509_CRL = "X509 CRL"; + public static final String ENCRYPTED_PRIVATE_KEY = "ENCRYPTED PRIVATE KEY"; + public static final String PRIVATE_KEY = "PRIVATE KEY"; + public static final String RSA_PRIVATE_KEY = "RSA PRIVATE KEY"; + public static final String PUBLIC_KEY = "PUBLIC KEY"; + // old PEM types per RFC 7468 + public static final String X509_CERTIFICATE = "X509 CERTIFICATE"; + public static final String X_509_CERTIFICATE = "X.509 CERTIFICATE"; + public static final String CRL = "CRL"; /** * Decodes a PEM-encoded block. @@ -40,15 +86,264 @@ public class Pem { * @param input the input string, according to RFC 1421, can only contain * characters in the base-64 alphabet and whitespaces. * @return the decoded bytes - * @throws java.io.IOException if input is invalid */ - public static byte[] decode(String input) throws IOException { - byte[] src = input.replaceAll("\\s+", "") - .getBytes(StandardCharsets.ISO_8859_1); + public static byte[] decode(String input) { + byte[] src = STRIP_WHITESPACE_PATTERN.matcher(input).replaceAll(""). + getBytes(StandardCharsets.ISO_8859_1); + return Base64.getDecoder().decode(src); + } + + /** + * Return the OID for a given PBE algorithm. PBES1 has an OID for each + * algorithm, while PBES2 has one OID for everything that complies with + * the formatting. Therefore, if the algorithm is not PBES1, it will + * return PBES2. Cipher will determine if this is a valid PBE algorithm. + * PBES2 specifies AES as the cipher algorithm, but any block cipher could + * be supported. + */ + public static ObjectIdentifier getPBEID(String algorithm) { + + // Verify pattern matches PBE Standard Name spec + if (!PBE_PATTERN.matcher(algorithm).matches()) { + throw new IllegalArgumentException("Invalid algorithm format."); + } + + // Return the PBES1 OID if it matches try { - return Base64.getDecoder().decode(src); - } catch (IllegalArgumentException e) { - throw new IOException(e); + return AlgorithmId.get(algorithm).getOID(); + } catch (NoSuchAlgorithmException e) { + // fall-through + } + + // Lazy initialize + if (PBES2OID == null) { + try { + // Set to the hardcoded OID in KnownOID.java + PBES2OID = AlgorithmId.get("PBES2").getOID(); + } catch (NoSuchAlgorithmException e) { + // Should never fail. + throw new IllegalArgumentException(e); + } + } + return PBES2OID; + } + + /* + * RFC 7468 has some rules what generators should return given a historical + * type name. This converts read in PEM to the RFC. Change the type to + * be uniform is likely to help apps from not using all 3 certificate names. + */ + private static String typeConverter(String type) { + return switch (type) { + case Pem.X509_CERTIFICATE, Pem.X_509_CERTIFICATE -> Pem.CERTIFICATE; + case Pem.CRL -> Pem.X509_CRL; + default -> type; + }; + } + + /** + * Read the PEM text and return it in it's three components: header, + * base64, and footer. + * + * The method will leave the stream after reading the end of line of the + * footer or end of file + * @param is an InputStream + * @param shortHeader if true, the hyphen length is 4 because the first + * hyphen is assumed to have been read. This is needed + * for the CertificateFactory X509 implementation. + * @return a new PEMRecord + * @throws IOException on IO errors or PEM syntax errors that leave + * the read position not at the end of a PEM block + * @throws EOFException when at the unexpected end of the stream + * @throws IllegalArgumentException when a PEM syntax error occurs, + * but the read position in the stream is at the end of the block, so + * future reads can be successful. + */ + public static PEMRecord readPEM(InputStream is, boolean shortHeader) + throws IOException { + Objects.requireNonNull(is); + + int hyphen = (shortHeader ? 1 : 0); + int eol = 0; + + ByteArrayOutputStream os = new ByteArrayOutputStream(6); + // Find starting hyphens + do { + int d = is.read(); + switch (d) { + case '-' -> hyphen++; + case -1 -> { + if (os.size() == 0) { + throw new EOFException("No data available"); + } + throw new EOFException("No PEM data found"); + } + default -> hyphen = 0; + } + os.write(d); + } while (hyphen != 5); + + StringBuilder sb = new StringBuilder(64); + sb.append("-----"); + hyphen = 0; + int c; + + // Get header definition until first hyphen + do { + switch (c = is.read()) { + case '-' -> hyphen++; + case -1 -> throw new EOFException("Input ended prematurely"); + case '\n', '\r' -> throw new IOException("Incomplete header"); + default -> sb.append((char) c); + } + } while (hyphen == 0); + + // Verify header ending with 5 hyphens. + do { + switch (is.read()) { + case '-' -> hyphen++; + default -> + throw new IOException("Incomplete header"); + } + } while (hyphen < 5); + + sb.append("-----"); + String header = sb.toString(); + if (header.length() < 16 || !header.startsWith("-----BEGIN ") || + !header.endsWith("-----")) { + throw new IOException("Illegal header: " + header); + } + + hyphen = 0; + sb = new StringBuilder(1024); + + // Determine the line break using the char after the last hyphen + switch (is.read()) { + case WS -> {} // skip whitespace + case '\r' -> { + c = is.read(); + if (c == '\n') { + eol = '\n'; + } else { + eol = '\r'; + sb.append((char) c); + } + } + case '\n' -> eol = '\n'; + default -> + throw new IOException("No EOL character found"); + } + + // Read data until we find the first footer hyphen. + do { + switch (c = is.read()) { + case -1 -> + throw new EOFException("Incomplete header"); + case '-' -> hyphen++; + case WS, '\t', '\r', '\n' -> {} // skip whitespace and tab + default -> sb.append((char) c); + } + } while (hyphen == 0); + + String data = sb.toString(); + + // Verify footer starts with 5 hyphens. + do { + switch (is.read()) { + case '-' -> hyphen++; + case -1 -> throw new EOFException("Input ended prematurely"); + default -> throw new IOException("Incomplete footer"); + } + } while (hyphen < 5); + + hyphen = 0; + sb = new StringBuilder(64); + sb.append("-----"); + + // Look for Complete header by looking for the end of the hyphens + do { + switch (c = is.read()) { + case '-' -> hyphen++; + case -1 -> throw new EOFException("Input ended prematurely"); + default -> sb.append((char) c); + } + } while (hyphen == 0); + + // Verify ending with 5 hyphens. + do { + switch (is.read()) { + case '-' -> hyphen++; + case -1 -> throw new EOFException("Input ended prematurely"); + default -> throw new IOException("Incomplete footer"); + } + } while (hyphen < 5); + + while ((c = is.read()) != eol && c != -1 && c != WS) { + // skip when eol is '\n', the line separator is likely "\r\n". + if (c == '\r') { + continue; + } + throw new IOException("Invalid PEM format: " + + "No EOL char found in footer: 0x" + + HexFormat.of().toHexDigits((byte) c)); + } + + sb.append("-----"); + String footer = sb.toString(); + if (footer.length() < 14 || !footer.startsWith("-----END ") || + !footer.endsWith("-----")) { + // Not an IOE because the read pointer is correctly at the end. + throw new IOException("Illegal footer: " + footer); + } + + // Verify the object type in the header and the footer are the same. + String headerType = header.substring(11, header.length() - 5); + String footerType = footer.substring(9, footer.length() - 5); + if (!headerType.equals(footerType)) { + throw new IOException("Header and footer do not " + + "match: " + headerType + " " + footerType); } + + // If there was data before finding the 5 dashes of the PEM header, + // backup 5 characters and save that data. + byte[] preData = null; + if (os.size() > 5) { + preData = Arrays.copyOf(os.toByteArray(), os.size() - 5); + } + + return new PEMRecord(typeConverter(headerType), data, preData); + } + + public static PEMRecord readPEM(InputStream is) throws IOException { + return readPEM(is, false); + } + + private static String pemEncoded(String type, String base64) { + return + "-----BEGIN " + type + "-----\r\n" + + base64 + (!base64.endsWith("\n") ? "\r\n" : "") + + "-----END " + type + "-----\r\n"; + } + + /** + * Construct a String-based encoding based off the type. leadingData + * is not used with this method. + * @return PEM in a string + */ + public static String pemEncoded(String type, byte[] der) { + if (b64Encoder == null) { + b64Encoder = Base64.getMimeEncoder(64, CRLF); + } + return pemEncoded(type, b64Encoder.encodeToString(der)); + } + + /** + * Construct a String-based encoding based off the type. leadingData + * is not used with this method. + * @return PEM in a string + */ + public static String pemEncoded(PEMRecord pem) { + String p = pem.content().replaceAll("(.{64})", "$1\r\n"); + return pemEncoded(pem.type(), p); } } 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 c1ffd248f2a..05cad48c042 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureUtil.java +++ b/src/java.base/share/classes/sun/security/util/SignatureUtil.java @@ -198,7 +198,7 @@ public static class EdDSADigestAlgHolder { static { try { sha512 = new AlgorithmId(ObjectIdentifier.of(KnownOIDs.SHA_512)); - shake256 = new AlgorithmId(ObjectIdentifier.of(KnownOIDs.SHAKE256)); + shake256 = new AlgorithmId(ObjectIdentifier.of(KnownOIDs.SHAKE256_512)); shake256$512 = new AlgorithmId( ObjectIdentifier.of(KnownOIDs.SHAKE256_LEN), new DerValue((byte) 2, new byte[]{2, 0})); // int 512 diff --git a/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java b/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java index 591a7a26c68..984f5a0ab47 100644 --- a/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java +++ b/src/java.base/share/classes/sun/security/validator/CamerfirmaTLSPolicy.java @@ -43,26 +43,14 @@ final class CamerfirmaTLSPolicy { private static final Debug debug = Debug.getInstance("certpath"); - // SHA-256 certificate fingerprints of distrusted roots - private static final Set FINGERPRINTS = Set.of( - // cacerts alias: camerfirmachamberscommerceca - // DN: CN=Chambers of Commerce Root, - // OU=http://www.chambersign.org, - // O=AC Camerfirma SA CIF A82743287, C=EU - "0C258A12A5674AEF25F28BA7DCFAECEEA348E541E6F5CC4EE63B71B361606AC3", - // cacerts alias: camerfirmachambersca - // DN: CN=Chambers of Commerce Root - 2008, - // O=AC Camerfirma S.A., SERIALNUMBER=A82743287, - // L=Madrid (see current address at www.camerfirma.com/address), - // C=EU - "063E4AFAC491DFD332F3089B8542E94617D893D7FE944E10A7937EE29D9693C0", - // cacerts alias: camerfirmachambersignca - // DN: CN=Global Chambersign Root - 2008, - // O=AC Camerfirma S.A., SERIALNUMBER=A82743287, - // L=Madrid (see current address at www.camerfirma.com/address), - // C=EU - "136335439334A7698016A0D324DE72284E079D7B5220BB8FBD747816EEBEBACA" - ); + // SHA-256 certificate fingerprint of distrusted root for TLS + // cacerts alias: camerfirmachambersca + // DN: CN=Chambers of Commerce Root - 2008, + // O=AC Camerfirma S.A., SERIALNUMBER=A82743287, + // L=Madrid (see current address at www.camerfirma.com/address), + // C=EU + private static final String FINGERPRINT = + "063E4AFAC491DFD332F3089B8542E94617D893D7FE944E10A7937EE29D9693C0"; // Any TLS Server certificate that is anchored by one of the Camerfirma // roots above and is issued after this date will be distrusted. @@ -85,7 +73,7 @@ static void checkDistrust(X509Certificate[] chain) throw new ValidatorException("Cannot generate fingerprint for " + "trust anchor of TLS server certificate"); } - if (FINGERPRINTS.contains(fp)) { + if (FINGERPRINT.equalsIgnoreCase(fp)) { Date notBefore = chain[0].getNotBefore(); LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(), ZoneOffset.UTC); 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 719748394e1..c83e06f651e 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * 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.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; -import java.util.Objects; import sun.security.util.HexDumpEncoder; import sun.security.util.*; @@ -83,7 +82,8 @@ public X509Key() { } * data is stored and transmitted losslessly, but no knowledge * about this particular algorithm is available. */ - private X509Key(AlgorithmId algid, BitArray key) { + @SuppressWarnings("this-escape") + public X509Key(AlgorithmId algid, BitArray key) { this.algid = algid; setKey(key); encode(); @@ -100,7 +100,7 @@ protected void setKey(BitArray key) { * Gets the key. The key may or may not be byte aligned. * @return a BitArray containing the key. */ - protected BitArray getKey() { + public BitArray getKey() { return (BitArray)bitStringKey.clone(); } @@ -129,7 +129,7 @@ public static PublicKey parse(DerValue in) throws IOException algorithm = AlgorithmId.parse(in.data.getDerValue()); try { subjectKey = buildX509Key(algorithm, - in.data.getUnalignedBitString()); + in.data.getUnalignedBitString()); } catch (InvalidKeyException e) { throw new IOException("subject key, " + e.getMessage(), e); @@ -154,7 +154,7 @@ public static PublicKey parse(DerValue in) throws IOException * @exception InvalidKeyException on invalid key encodings. */ protected void parseKeyBits() throws InvalidKeyException { - encode(); + getEncodedInternal(); } /* @@ -243,7 +243,7 @@ public String getAlgorithm() { /** * Returns the algorithm ID to be used with this key. */ - public AlgorithmId getAlgorithmId() { return algid; } + public AlgorithmId getAlgorithmId() { return algid; } /** * Encode SubjectPublicKeyInfo sequence on the DER output stream. @@ -260,7 +260,7 @@ public byte[] getEncoded() { return getEncodedInternal().clone(); } - public byte[] getEncodedInternal() { + private byte[] getEncodedInternal() { byte[] encoded = encodedKey; if (encoded == null) { DerOutputStream out = new DerOutputStream(); @@ -314,7 +314,7 @@ public String toString() * @param val a DER-encoded X.509 SubjectPublicKeyInfo value * @exception InvalidKeyException on parsing errors. */ - void decode(DerValue val) throws InvalidKeyException { + public void decode(DerValue val) throws InvalidKeyException { try { if (val.tag != DerValue.tag_Sequence) throw new InvalidKeyException("invalid key format"); 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 ae5e64280bc..2ca99f6b618 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java @@ -93,8 +93,7 @@ protected String[] getDisplayNameArray(String id, Locale locale) { switch (namesSuper[i]) { case "": // Fill in empty elements - deriveFallbackName(namesSuper, i, locale, - ZoneInfo.getTimeZone(id).toZoneId().getRules().isFixedOffset()); + deriveFallbackName(namesSuper, i, locale, isFixedOffset(id)); break; case NO_INHERITANCE_MARKER: // CLDR's "no inheritance marker" @@ -132,7 +131,7 @@ protected String[][] getZoneStrings(Locale locale) { // Derive fallback time zone name according to LDML's logic private void deriveFallbackNames(String[] names, Locale locale) { - boolean noDST = ZoneInfo.getTimeZone(names[0]).toZoneId().getRules().isFixedOffset(); + boolean noDST = isFixedOffset(names[0]); for (int i = INDEX_STD_LONG; i <= INDEX_GEN_SHORT; i++) { deriveFallbackName(names, i, locale, noDST); @@ -312,4 +311,11 @@ private String toGMTFormat(String id, boolean daylight, Locale l) { String.format(l, hourFormat, offset / 60, offset % 60)); } } + + // ZoneInfo.getTimeZone() may return null if the tzdata has been + // forcibly downgraded to an older release using TZUpdater + private boolean isFixedOffset(String id) { + var zi = ZoneInfo.getTimeZone(id); + return zi == null || zi.toZoneId().getRules().isFixedOffset(); + } } diff --git a/src/java.base/share/classes/sun/util/locale/InternalLocaleBuilder.java b/src/java.base/share/classes/sun/util/locale/InternalLocaleBuilder.java index 894a49e8efe..5da725d59c8 100644 --- a/src/java.base/share/classes/sun/util/locale/InternalLocaleBuilder.java +++ b/src/java.base/share/classes/sun/util/locale/InternalLocaleBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -347,18 +347,18 @@ private InternalLocaleBuilder setExtensions(List bcpExtensions, String p */ public InternalLocaleBuilder setLanguageTag(LanguageTag langtag) { clear(); - if (!langtag.getExtlangs().isEmpty()) { - language = langtag.getExtlangs().get(0); + if (!langtag.extlangs().isEmpty()) { + language = langtag.extlangs().get(0); } else { - String lang = langtag.getLanguage(); + String lang = langtag.language(); if (!lang.equals(LanguageTag.UNDETERMINED)) { language = lang; } } - script = langtag.getScript(); - region = langtag.getRegion(); + script = langtag.script(); + region = langtag.region(); - List bcpVariants = langtag.getVariants(); + List bcpVariants = langtag.variants(); if (!bcpVariants.isEmpty()) { StringBuilder var = new StringBuilder(bcpVariants.get(0)); int size = bcpVariants.size(); @@ -368,7 +368,7 @@ public InternalLocaleBuilder setLanguageTag(LanguageTag langtag) { variant = var.toString(); } - setExtensions(langtag.getExtensions(), langtag.getPrivateuse()); + setExtensions(langtag.extensions(), langtag.privateuse()); return this; } diff --git a/src/java.base/share/classes/sun/util/locale/LanguageTag.java b/src/java.base/share/classes/sun/util/locale/LanguageTag.java index 5c905372c5a..a88937b7538 100644 --- a/src/java.base/share/classes/sun/util/locale/LanguageTag.java +++ b/src/java.base/share/classes/sun/util/locale/LanguageTag.java @@ -42,30 +42,21 @@ import java.util.Set; import java.util.StringJoiner; -public class LanguageTag { - // - // static fields - // +// List fields are unmodifiable +public record LanguageTag(String language, String script, String region, String privateuse, + List extlangs, List variants, List extensions) { + public static final String SEP = "-"; public static final String PRIVATEUSE = "x"; public static final String UNDETERMINED = "und"; public static final String PRIVUSE_VARIANT_PREFIX = "lvariant"; + private static final String EMPTY_SUBTAG = ""; + private static final List EMPTY_SUBTAGS = Collections.emptyList(); - // - // Language subtag fields - // - private String language = ""; // language subtag - private String script = ""; // script subtag - private String region = ""; // region subtag - private String privateuse = ""; // privateuse - - private List extlangs = Collections.emptyList(); // extlang subtags - private List variants = Collections.emptyList(); // variant subtags - private List extensions = Collections.emptyList(); // extensions // Map contains legacy language tags and its preferred mappings from // http://www.ietf.org/rfc/rfc5646.txt // Keys are lower-case strings. - private static final Map LEGACY = new HashMap<>(); + private static final Map LEGACY; static { // grandfathered = irregular ; non-redundant tags registered @@ -128,14 +119,12 @@ public class LanguageTag { {"zh-min-nan", "nan"}, {"zh-xiang", "hsn"}, }; + LEGACY = HashMap.newHashMap(entries.length); for (String[] e : entries) { LEGACY.put(LocaleUtils.toLowerString(e[0]), e); } } - private LanguageTag() { - } - /* * BNF in RFC5646 * @@ -195,17 +184,27 @@ public static LanguageTag parse(String languageTag, ParsePosition pp, itr = new StringTokenIterator(languageTag, SEP); } - LanguageTag tag = new LanguageTag(); - + String language = parseLanguage(itr, pp); + List extlangs; + String script; + String region; + List variants; + List extensions; // langtag must start with either language or privateuse - if (tag.parseLanguage(itr, pp)) { - tag.parseExtlangs(itr, pp); - tag.parseScript(itr, pp); - tag.parseRegion(itr, pp); - tag.parseVariants(itr, pp); - tag.parseExtensions(itr, pp, errorMsg); + if (!language.isEmpty()) { + extlangs = parseExtlangs(itr, pp); + script = parseScript(itr, pp); + region = parseRegion(itr, pp); + variants = parseVariants(itr, pp); + extensions = parseExtensions(itr, pp, errorMsg); + } else { + extlangs = EMPTY_SUBTAGS; + script = EMPTY_SUBTAG; + region = EMPTY_SUBTAG; + variants = EMPTY_SUBTAGS; + extensions = EMPTY_SUBTAGS; } - tag.parsePrivateuse(itr, pp, errorMsg); + String privateuse = parsePrivateuse(itr, pp, errorMsg); if (!itr.isDone() && pp.getErrorIndex() == -1) { String s = itr.current(); @@ -221,110 +220,94 @@ public static LanguageTag parse(String languageTag, ParsePosition pp, throw new IllformedLocaleException(errorMsg.toString(), pp.getErrorIndex()); } - return tag; + return new LanguageTag(language, script, region, privateuse, extlangs, variants, extensions); } // // Language subtag parsers // - private boolean parseLanguage(StringTokenIterator itr, ParsePosition pp) { + private static String parseLanguage(StringTokenIterator itr, ParsePosition pp) { if (itr.isDone() || pp.getErrorIndex() != -1) { - return false; + return EMPTY_SUBTAG; } - boolean found = false; - String s = itr.current(); if (isLanguage(s)) { - found = true; - language = s; pp.setIndex(itr.currentEnd()); itr.next(); + return s; } - return found; + return EMPTY_SUBTAG; } - private boolean parseExtlangs(StringTokenIterator itr, ParsePosition pp) { + private static List parseExtlangs(StringTokenIterator itr, ParsePosition pp) { if (itr.isDone() || pp.getErrorIndex() != -1) { - return false; + return EMPTY_SUBTAGS; } - - boolean found = false; - + List extlangs = null; while (!itr.isDone()) { String s = itr.current(); if (!isExtlang(s)) { break; } - found = true; - if (extlangs.isEmpty()) { + if (extlangs == null) { extlangs = new ArrayList<>(3); } extlangs.add(s); pp.setIndex(itr.currentEnd()); itr.next(); - if (extlangs.size() == 3) { // Maximum 3 extlangs break; } } - - return found; + return extlangs == null ? EMPTY_SUBTAGS : + Collections.unmodifiableList(extlangs); } - private boolean parseScript(StringTokenIterator itr, ParsePosition pp) { + private static String parseScript(StringTokenIterator itr, ParsePosition pp) { if (itr.isDone() || pp.getErrorIndex() != -1) { - return false; + return EMPTY_SUBTAG; } - boolean found = false; - String s = itr.current(); if (isScript(s)) { - found = true; - script = s; pp.setIndex(itr.currentEnd()); itr.next(); + return s; } - return found; + return EMPTY_SUBTAG; } - private boolean parseRegion(StringTokenIterator itr, ParsePosition pp) { + private static String parseRegion(StringTokenIterator itr, ParsePosition pp) { if (itr.isDone() || pp.getErrorIndex() != -1) { - return false; + return EMPTY_SUBTAG; } - - boolean found = false; - String s = itr.current(); if (isRegion(s)) { - found = true; - region = s; pp.setIndex(itr.currentEnd()); itr.next(); + return s; } - return found; + return EMPTY_SUBTAG; } - private boolean parseVariants(StringTokenIterator itr, ParsePosition pp) { + private static List parseVariants(StringTokenIterator itr, ParsePosition pp) { if (itr.isDone() || pp.getErrorIndex() != -1) { - return false; + return EMPTY_SUBTAGS; } - - boolean found = false; + List variants = null; while (!itr.isDone()) { String s = itr.current(); if (!isVariant(s)) { break; } - found = true; - if (variants.isEmpty()) { + if (variants == null) { variants = new ArrayList<>(3); } variants.add(s); @@ -332,16 +315,16 @@ private boolean parseVariants(StringTokenIterator itr, ParsePosition pp) { itr.next(); } - return found; + return variants == null ? EMPTY_SUBTAGS : + Collections.unmodifiableList(variants); } - private boolean parseExtensions(StringTokenIterator itr, ParsePosition pp, + private static List parseExtensions(StringTokenIterator itr, ParsePosition pp, StringBuilder err) { if (itr.isDone() || pp.getErrorIndex() != -1) { - return false; + return EMPTY_SUBTAGS; } - - boolean found = false; + List extensions = null; while (!itr.isDone()) { String s = itr.current(); @@ -368,26 +351,24 @@ private boolean parseExtensions(StringTokenIterator itr, ParsePosition pp, break; } - if (extensions.isEmpty()) { + if (extensions == null) { extensions = new ArrayList<>(4); } extensions.add(sb.toString()); - found = true; } else { break; } } - return found; + return extensions == null ? EMPTY_SUBTAGS : + Collections.unmodifiableList(extensions); } - private boolean parsePrivateuse(StringTokenIterator itr, ParsePosition pp, + private static String parsePrivateuse(StringTokenIterator itr, ParsePosition pp, StringBuilder err) { if (itr.isDone() || pp.getErrorIndex() != -1) { - return false; + return EMPTY_SUBTAG; } - boolean found = false; - String s = itr.current(); if (isPrivateusePrefix(s)) { int start = itr.currentStart(); @@ -410,12 +391,11 @@ private boolean parsePrivateuse(StringTokenIterator itr, ParsePosition pp, pp.setErrorIndex(start); err.append("Incomplete privateuse"); } else { - privateuse = sb.toString(); - found = true; + return sb.toString(); } } - return found; + return EMPTY_SUBTAG; } public static String caseFoldTag(String tag) { @@ -462,48 +442,50 @@ public static String caseFoldTag(String tag) { } public static LanguageTag parseLocale(BaseLocale baseLocale, LocaleExtensions localeExtensions) { - LanguageTag tag = new LanguageTag(); - String language = baseLocale.getLanguage(); - String script = baseLocale.getScript(); - String region = baseLocale.getRegion(); - String variant = baseLocale.getVariant(); + String language = EMPTY_SUBTAG; + String script = EMPTY_SUBTAG; + String region = EMPTY_SUBTAG; + + String baseLanguage = baseLocale.getLanguage(); + String baseScript = baseLocale.getScript(); + String baseRegion = baseLocale.getRegion(); + String baseVariant = baseLocale.getVariant(); boolean hasSubtag = false; String privuseVar = null; // store ill-formed variant subtags - if (isLanguage(language)) { + if (isLanguage(baseLanguage)) { // Convert a deprecated language code to its new code - if (language.equals("iw")) { - language = "he"; - } else if (language.equals("ji")) { - language = "yi"; - } else if (language.equals("in")) { - language = "id"; - } - tag.language = language; + baseLanguage = switch (baseLanguage) { + case "iw" -> "he"; + case "ji" -> "yi"; + case "in" -> "id"; + default -> baseLanguage; + }; + language = baseLanguage; } - if (isScript(script)) { - tag.script = canonicalizeScript(script); + if (isScript(baseScript)) { + script = canonicalizeScript(baseScript); hasSubtag = true; } - if (isRegion(region)) { - tag.region = canonicalizeRegion(region); + if (isRegion(baseRegion)) { + region = canonicalizeRegion(baseRegion); hasSubtag = true; } // Special handling for no_NO_NY - use nn_NO for language tag - if (tag.language.equals("no") && tag.region.equals("NO") && variant.equals("NY")) { - tag.language = "nn"; - variant = ""; + if (language.equals("no") && region.equals("NO") && baseVariant.equals("NY")) { + language = "nn"; + baseVariant = EMPTY_SUBTAG; } - if (!variant.isEmpty()) { - List variants = null; - StringTokenIterator varitr = new StringTokenIterator(variant, BaseLocale.SEP); + List variants = null; + if (!baseVariant.isEmpty()) { + StringTokenIterator varitr = new StringTokenIterator(baseVariant, BaseLocale.SEP); while (!varitr.isDone()) { String var = varitr.current(); if (!isVariant(var)) { @@ -516,7 +498,6 @@ public static LanguageTag parseLocale(BaseLocale baseLocale, LocaleExtensions lo varitr.next(); } if (variants != null) { - tag.variants = variants; hasSubtag = true; } if (!varitr.isDone()) { @@ -556,7 +537,6 @@ public static LanguageTag parseLocale(BaseLocale baseLocale, LocaleExtensions lo } if (extensions != null) { - tag.extensions = extensions; hasSubtag = true; } @@ -570,59 +550,21 @@ public static LanguageTag parseLocale(BaseLocale baseLocale, LocaleExtensions lo } } - if (privateuse != null) { - tag.privateuse = privateuse; - } - - if (tag.language.isEmpty() && (hasSubtag || privateuse == null)) { + if (language.isEmpty() && (hasSubtag || privateuse == null)) { // use lang "und" when 1) no language is available AND // 2) any of other subtags other than private use are available or // no private use tag is available - tag.language = UNDETERMINED; - } - - return tag; - } - - // - // Getter methods for language subtag fields - // - - public String getLanguage() { - return language; - } - - public List getExtlangs() { - if (extlangs.isEmpty()) { - return Collections.emptyList(); + language = UNDETERMINED; } - return Collections.unmodifiableList(extlangs); - } - - public String getScript() { - return script; - } - - public String getRegion() { - return region; - } - public List getVariants() { - if (variants.isEmpty()) { - return Collections.emptyList(); - } - return Collections.unmodifiableList(variants); - } - - public List getExtensions() { - if (extensions.isEmpty()) { - return Collections.emptyList(); - } - return Collections.unmodifiableList(extensions); - } + privateuse = privateuse == null ? EMPTY_SUBTAG : privateuse; + extensions = extensions == null ? EMPTY_SUBTAGS : + Collections.unmodifiableList(extensions); + variants = variants == null ? EMPTY_SUBTAGS : + Collections.unmodifiableList(variants); - public String getPrivateuse() { - return privateuse; + // extlangs always empty for locale parse + return new LanguageTag(language, script, region, privateuse, EMPTY_SUBTAGS, variants, extensions); } // diff --git a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties index 7e6acccf6e5..d2d9ff1035b 100644 --- a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties +++ b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -261,6 +261,7 @@ VES=VES VND=VND VUV=VUV WST=WST +XAD=XAD XAF=XAF XAG=XAG XAU=XAU @@ -488,6 +489,7 @@ ves=Venezuelan Bolívar Soberano vnd=Vietnamese Dong vuv=Vanuatu Vatu wst=Samoan Tala +xad=Arab Accounting Dinar xaf=CFA Franc BEAC xag=Silver xau=Gold diff --git a/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java b/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java index 2763ac30ca7..dced9151d5b 100644 --- a/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java +++ b/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -929,9 +929,7 @@ protected final Object[][] getContents() { {"Japan", JST}, {"Kwajalein", MHT}, {"Libya", EET}, - {"MET", new String[] {"Middle Europe Time", "MET", - "Middle Europe Summer Time", "MEST", - "Middle Europe Time", "MET"}}, + {"MET", CET}, {"Mexico/BajaNorte", PST}, {"Mexico/BajaSur", MST}, {"Mexico/General", CST}, diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index b115d479838..61e8aaaf6d1 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1277,8 +1277,13 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep # # Enhanced exception message information # -# By default, exception messages should not include potentially sensitive -# information such as file names, host names, or port numbers. This property +# Exception messages may include potentially sensitive information such as file +# names, host names, or port numbers. By default, socket related exceptions +# have this information restricted (meaning the sensitive details are removed). +# Exception messages relating to JAR files and exceptions containing user +# identity information are also restricted by default. +# This property can be used to relax this restriction or to place further +# restrictions on other categories, defined below. The property # accepts one or more comma separated values, each of which represents a # category of enhanced exception message information to enable. Values are # case-insensitive. Leading and trailing whitespaces, surrounding each value, @@ -1291,17 +1296,28 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep # # The categories are: # -# hostInfo - IOExceptions thrown by java.net.Socket and the socket types in the -# java.nio.channels package will contain enhanced exception -# message information +# hostInfo - All networking related exceptions will contain enhanced +# exception message information. +# +# hostInfoExclSocket - The hostInfo category defined above, excluding +# IOExceptions thrown by java.net.Socket and the NetworkChannel +# types in the java.nio.channels package, will contain enhanced +# exception message information # # jar - enables more detailed information in the IOExceptions thrown # by classes in the java.util.jar package # +# userInfo - enables more detailed information in exceptions which may contain +# user identity information +# # The property setting in this file can be overridden by a system property of # the same name, with the same syntax and possible values. # -#jdk.includeInExceptions=hostInfo,jar +# If the property is not set or set to an empty string, then this is the most +# restricted setting with all categories disabled. The following is the default +# (out of the box) setting, meaning these categories are not restricted. +# +jdk.includeInExceptions=hostInfoExclSocket # # Disabled mechanisms for the Simple Authentication and Security Layer (SASL) @@ -1549,3 +1565,12 @@ jdk.tls.alpnCharset=ISO_8859_1 # security property value defined here. # #jdk.security.krb5.name.case.sensitive=false + +# +# Default algorithm for PEMEncoder Encrypted PKCS#8 +# +# This property defines the default password-based encryption algorithm for +# java.security.PEMEncoder when configured for encryption with the +# withEncryption method. +# +jdk.epkcs8.defaultAlgorithm=PBEWithHmacSHA256AndAES_128 diff --git a/src/java.base/share/data/cacerts/camerfirmachamberscommerceca b/src/java.base/share/data/cacerts/camerfirmachamberscommerceca deleted file mode 100644 index b92255f770c..00000000000 --- a/src/java.base/share/data/cacerts/camerfirmachamberscommerceca +++ /dev/null @@ -1,35 +0,0 @@ -Owner: CN=Chambers of Commerce Root, OU=http://www.chambersign.org, O=AC Camerfirma SA CIF A82743287, C=EU -Issuer: CN=Chambers of Commerce Root, OU=http://www.chambersign.org, O=AC Camerfirma SA CIF A82743287, C=EU -Serial number: 0 -Valid from: Tue Sep 30 16:13:43 GMT 2003 until: Wed Sep 30 16:13:44 GMT 2037 -Signature algorithm name: SHA1withRSA -Subject Public Key Algorithm: 2048-bit RSA key -Version: 3 ------BEGIN CERTIFICATE----- -MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn -MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL -ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg -b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa -MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB -ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw -IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B -AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb -unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d -BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq -7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 -0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX -roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG -A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j -aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p -26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA -BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud -EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN -BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz -aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB -AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd -p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi -1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc -XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 -eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu -tGWaIZDgqtCYvDi1czyL+Nw= ------END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/camerfirmachambersignca b/src/java.base/share/data/cacerts/camerfirmachambersignca deleted file mode 100644 index 935eea9c212..00000000000 --- a/src/java.base/share/data/cacerts/camerfirmachambersignca +++ /dev/null @@ -1,48 +0,0 @@ -Owner: CN=Global Chambersign Root - 2008, O=AC Camerfirma S.A., SERIALNUMBER=A82743287, L=Madrid (see current address at www.camerfirma.com/address), C=EU -Issuer: CN=Global Chambersign Root - 2008, O=AC Camerfirma S.A., SERIALNUMBER=A82743287, L=Madrid (see current address at www.camerfirma.com/address), C=EU -Serial number: c9cdd3e9d57d23ce -Valid from: Fri Aug 01 12:31:40 GMT 2008 until: Sat Jul 31 12:31:40 GMT 2038 -Signature algorithm name: SHA1withRSA -Subject Public Key Algorithm: 4096-bit RSA key -Version: 3 ------BEGIN CERTIFICATE----- -MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD -VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 -IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 -MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD -aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx -MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy -cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG -A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl -BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI -hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed -KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 -G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 -zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 -ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG -HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 -Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V -yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e -beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r -6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh -wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog -zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW -BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr -ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp -ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk -cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt -YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC -CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow -KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI -hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ -UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz -X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x -fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz -a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd -Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd -SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O -AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso -M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge -v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z -09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B ------END CERTIFICATE----- diff --git a/src/java.base/share/data/currency/CurrencyData.properties b/src/java.base/share/data/currency/CurrencyData.properties index 5a28abccd00..ff2d1f87ed3 100644 --- a/src/java.base/share/data/currency/CurrencyData.properties +++ b/src/java.base/share/data/currency/CurrencyData.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ formatVersion=3 # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=177 +dataVersion=179 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -54,7 +54,7 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036 SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLE925-SLL694-SOS706-\ SRD968-SRG740-SSP728-STD678-STN930-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TMT934-TND788-TOP776-\ TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-UYI940-\ - UYU858-UZS860-VEB862-VED926-VEF937-VES928-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\ + UYU858-UZS860-VEB862-VED926-VEF937-VES928-VND704-VUV548-WST882-XAD396-XAF950-XAG961-XAU959-XBA955-\ XBB956-XBC957-XBD958-XCD951-XCG532-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ XPT962-XSU994-XTS963-XUA965-XXX999-YER886-YUM891-ZAR710-ZMK894-ZMW967-ZWD716-ZWG924-\ ZWL932-ZWN942-ZWR935 diff --git a/src/java.base/share/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt index b00ea67e7e8..64c40f28162 100644 --- a/src/java.base/share/data/lsrdata/language-subtag-registry.txt +++ b/src/java.base/share/data/lsrdata/language-subtag-registry.txt @@ -1,4 +1,4 @@ -File-Date: 2024-11-19 +File-Date: 2025-05-15 %% Type: language Subtag: aa @@ -5950,6 +5950,7 @@ Added: 2009-07-29 %% Type: language Subtag: bql +Description: Karian Description: Bilakura Added: 2009-07-29 %% @@ -9083,6 +9084,7 @@ Scope: collection %% Type: language Subtag: daz +Description: Moi-Wadea Description: Dao Added: 2009-07-29 %% @@ -9290,6 +9292,8 @@ Type: language Subtag: dek Description: Dek Added: 2009-07-29 +Deprecated: 2024-12-12 +Preferred-Value: sqm %% Type: language Subtag: del @@ -14082,6 +14086,12 @@ Added: 2009-07-29 Macrolanguage: hmn %% Type: language +Subtag: hnm +Description: Hainanese +Added: 2024-12-12 +Macrolanguage: zh +%% +Type: language Subtag: hnn Description: Hanunoo Added: 2009-07-29 @@ -16421,6 +16431,7 @@ Added: 2009-07-29 %% Type: language Subtag: kci +Description: Ngyian Description: Kamantan Added: 2009-07-29 %% @@ -21081,6 +21092,12 @@ Description: Laua Added: 2009-07-29 %% Type: language +Subtag: luh +Description: Leizhou Chinese +Added: 2024-12-12 +Macrolanguage: zh +%% +Type: language Subtag: lui Description: Luiseno Added: 2005-10-16 @@ -22850,6 +22867,8 @@ Added: 2009-07-29 %% Type: language Subtag: mmi +Description: Hember Avu +Description: Amben Description: Musar Added: 2009-07-29 %% @@ -25197,8 +25216,9 @@ Added: 2009-07-29 %% Type: language Subtag: new -Description: Newari Description: Nepal Bhasa +Description: Newar +Description: Newari Added: 2005-10-16 %% Type: language @@ -26641,6 +26661,8 @@ Type: language Subtag: nte Description: Nathembo Added: 2009-07-29 +Deprecated: 2024-12-12 +Preferred-Value: eko %% Type: language Subtag: ntg @@ -27185,6 +27207,12 @@ Description: Oroch Added: 2009-07-29 %% Type: language +Subtag: oak +Description: Noakhali +Description: Noakhailla +Added: 2025-05-14 +%% +Type: language Subtag: oar Description: Old Aramaic (up to 700 BCE) Description: Ancient Aramaic (up to 700 BCE) @@ -32147,6 +32175,12 @@ Description: Sajau Basap Added: 2009-07-29 %% Type: language +Subtag: sjc +Description: Shaojiang Chinese +Added: 2024-12-12 +Macrolanguage: zh +%% +Type: language Subtag: sjd Description: Kildin Sami Added: 2009-07-29 @@ -41302,6 +41336,11 @@ Description: Aluo Added: 2009-07-29 %% Type: language +Subtag: ynb +Description: Yamben +Added: 2025-02-06 +%% +Type: language Subtag: ynd Description: Yandruwandha Added: 2009-07-29 @@ -43616,6 +43655,14 @@ Preferred-Value: hks Prefix: sgn %% Type: extlang +Subtag: hnm +Description: Hainanese +Added: 2024-12-12 +Preferred-Value: hnm +Prefix: zh +Macrolanguage: zh +%% +Type: extlang Subtag: hos Description: Ho Chi Minh City Sign Language Added: 2009-07-29 @@ -43958,6 +44005,14 @@ Prefix: lv Macrolanguage: lv %% Type: extlang +Subtag: luh +Description: Leizhou Chinese +Added: 2024-12-12 +Preferred-Value: luh +Prefix: zh +Macrolanguage: zh +%% +Type: extlang Subtag: lvs Description: Standard Latvian Added: 2010-03-11 @@ -44393,6 +44448,14 @@ Prefix: ar Macrolanguage: ar %% Type: extlang +Subtag: sjc +Description: Shaojiang Chinese +Added: 2024-12-12 +Preferred-Value: sjc +Prefix: zh +Macrolanguage: zh +%% +Type: extlang Subtag: slf Description: Swiss-Italian Sign Language Added: 2009-07-29 @@ -44844,6 +44907,11 @@ Description: Bangla Added: 2005-10-16 %% Type: script +Subtag: Berf +Description: Beria Erfe +Added: 2025-02-06 +%% +Type: script Subtag: Bhks Description: Bhaiksuki Added: 2015-07-24 @@ -45132,6 +45200,12 @@ Description: Nyiakeng Puachue Hmong Added: 2017-08-13 %% Type: script +Subtag: Hntl +Description: Han (Traditional variant) with Latin (alias for Hant + + Latn) +Added: 2025-05-14 +%% +Type: script Subtag: Hrkt Description: Japanese syllabaries (alias for Hiragana + Katakana) Added: 2005-10-16 @@ -45636,6 +45710,12 @@ Description: Saurashtra Added: 2006-07-21 %% Type: script +Subtag: Seal +Description: Seal +Description: Small Seal +Added: 2025-05-14 +%% +Type: script Subtag: Sgnw Description: SignWriting Added: 2006-10-17 @@ -47919,6 +47999,12 @@ Comments: Written standard developed by Romanilha in 1853 and used by dóu Po, Escolo Gaston Febus, and others %% Type: variant +Subtag: hanoi +Description: The Hà Nội variant of Vietnamese +Added: 2025-03-10 +Prefix: vi +%% +Type: variant Subtag: hepburn Description: Hepburn romanization Added: 2009-10-01 @@ -47949,6 +48035,12 @@ Added: 2017-03-14 Prefix: eo %% Type: variant +Subtag: huett +Description: The Huế (province Thừa Thiên) variant of Vietnamese +Added: 2025-03-10 +Prefix: vi +%% +Type: variant Subtag: ijekavsk Description: Serbian with Ijekavian pronunciation Prefix: sr @@ -48024,6 +48116,13 @@ Prefix: sa Comments: Preferred tag is cls %% Type: variant +Subtag: leidentr +Description: Ancient Egyptian in Leiden Unified Transliteration +Added: 2025-02-06 +Prefix: egy +Comments: Recommended by the International Association of Egyptologists +%% +Type: variant Subtag: lemosin Description: Limousin Added: 2018-04-22 @@ -48068,6 +48167,19 @@ Comments: Russian orthography as established by the 1917/1918 orthographic reforms %% Type: variant +Subtag: mdcegyp +Description: Ancient Egyptian hieroglyphs encoded in Manuel de Codage +Added: 2025-02-06 +Prefix: egy +%% +Type: variant +Subtag: mdctrans +Description: Ancient Egyptian transliteration encoded in Manuel de + Codage +Added: 2025-02-06 +Prefix: egy +%% +Type: variant Subtag: metelko Description: Slovene in Metelko alphabet Added: 2012-06-27 @@ -48255,6 +48367,12 @@ Prefix: rm Comments: Supraregional Romansh written standard %% Type: variant +Subtag: saigon +Description: The Sài Gòn variant of Vietnamese +Added: 2025-03-10 +Prefix: vi +%% +Type: variant Subtag: scotland Description: Scottish Standard English Added: 2007-08-31 diff --git a/src/java.base/share/data/publicsuffixlist/VERSION b/src/java.base/share/data/publicsuffixlist/VERSION index 24f4407cc89..1e136d312da 100644 --- a/src/java.base/share/data/publicsuffixlist/VERSION +++ b/src/java.base/share/data/publicsuffixlist/VERSION @@ -1,2 +1,2 @@ -Github: https://raw.githubusercontent.com/publicsuffix/list/1cbd6e71a9b83620b1d0b11e49d3d9ff48c27e22/public_suffix_list.dat -Date: 2024-05-07 +Github: https://raw.githubusercontent.com/publicsuffix/list/823beb1425def931c8b0b170a6bc33b424c3f9b0/public_suffix_list.dat +Date: 2025-05-12 diff --git a/src/java.base/share/data/publicsuffixlist/public_suffix_list.dat b/src/java.base/share/data/publicsuffixlist/public_suffix_list.dat index 34733674ea0..6ebe2dfd632 100644 --- a/src/java.base/share/data/publicsuffixlist/public_suffix_list.dat +++ b/src/java.base/share/data/publicsuffixlist/public_suffix_list.dat @@ -14,40 +14,48 @@ ac com.ac edu.ac gov.ac -net.ac mil.ac +net.ac org.ac -// ad : https://en.wikipedia.org/wiki/.ad +// ad : https://www.iana.org/domains/root/db/ad.html +// Confirmed by Amadeu Abril i Abril (CORE) 2024-11-17 ad -nom.ad -// ae : https://tdra.gov.ae/en/aeda/ae-policies +// ae : https://www.iana.org/domains/root/db/ae.html ae +ac.ae co.ae +gov.ae +mil.ae net.ae org.ae sch.ae -ac.ae -gov.ae -mil.ae -// aero : see https://www.information.aero/index.php?id=66 +// aero : https://information.aero/registration/policies/dmp aero +// 2LDs +airline.aero +airport.aero +// 2LDs (currently not accepting registration, seemingly never have) +// As of 2024-07, these are marked as reserved for potential 3LD +// registrations (clause 11 "allocated subdomains" in the 2006 TLD +// policy), but the relevant industry partners have not opened them up +// for registration. Current status can be determined from the TLD's +// policy document: 2LDs that are open for registration must list +// their policy in the TLD's policy. Any 2LD without such a policy is +// not open for registrations. accident-investigation.aero accident-prevention.aero aerobatic.aero aeroclub.aero aerodrome.aero agents.aero -aircraft.aero -airline.aero -airport.aero air-surveillance.aero -airtraffic.aero air-traffic-control.aero +aircraft.aero +airtraffic.aero ambulance.aero -amusement.aero association.aero author.aero ballooning.aero @@ -78,6 +86,7 @@ exchange.aero express.aero federation.aero flight.aero +freight.aero fuel.aero gliding.aero government.aero @@ -92,6 +101,7 @@ leasing.aero logistics.aero magazine.aero maintenance.aero +marketplace.aero media.aero microlight.aero modelling.aero @@ -114,6 +124,7 @@ show.aero skydiving.aero software.aero student.aero +taxi.aero trader.aero trading.aero trainer.aero @@ -121,27 +132,27 @@ union.aero workinggroup.aero works.aero -// af : http://www.nic.af/help.jsp +// af : https://www.nic.af/domain-price af -gov.af com.af -org.af -net.af edu.af +gov.af +net.af +org.af // ag : http://www.nic.ag/prices.htm ag +co.ag com.ag -org.ag net.ag -co.ag nom.ag +org.ag // ai : http://nic.com.ai/ ai -off.ai com.ai net.ai +off.ai org.ai // al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31 @@ -154,6 +165,7 @@ net.al org.al // am : https://www.amnic.net/policy/en/Policy_EN.pdf +// Confirmed by ISOC AM 2024-11-18 am co.am com.am @@ -161,17 +173,20 @@ commune.am net.am org.am -// ao : https://en.wikipedia.org/wiki/.ao -// http://www.dns.ao/REGISTR.DOC +// ao : https://www.iana.org/domains/root/db/ao.html +// https://www.dns.ao/ao/ ao +co.ao ed.ao +edu.ao +gov.ao gv.ao +it.ao og.ao -co.ao +org.ao pb.ao -it.ao -// aq : https://en.wikipedia.org/wiki/.aq +// aq : https://www.iana.org/domains/root/db/aq.html aq // ar : https://nic.ar/es/nic-argentina/normativa @@ -188,51 +203,53 @@ musica.ar mutual.ar net.ar org.ar +seg.ar senasa.ar tur.ar -// arpa : https://en.wikipedia.org/wiki/.arpa +// arpa : https://www.iana.org/domains/root/db/arpa.html // Confirmed by registry 2008-06-18 arpa e164.arpa +home.arpa in-addr.arpa ip6.arpa iris.arpa uri.arpa urn.arpa -// as : https://en.wikipedia.org/wiki/.as +// as : https://www.iana.org/domains/root/db/as.html as gov.as -// asia : https://en.wikipedia.org/wiki/.asia +// asia : https://www.iana.org/domains/root/db/asia.html asia -// at : https://en.wikipedia.org/wiki/.at +// at : https://www.iana.org/domains/root/db/at.html // Confirmed by registry 2008-06-17 at ac.at +sth.ac.at co.at gv.at or.at -sth.ac.at -// au : https://en.wikipedia.org/wiki/.au -// http://www.auda.org.au/ +// au : https://www.iana.org/domains/root/db/au.html +// https://www.auda.org.au/ +// Confirmed by registry 2024-11-17 au // 2LDs +asn.au com.au -net.au -org.au edu.au gov.au -asn.au id.au +net.au +org.au // Historic 2LDs (closed to new registration, but sites still exist) -info.au conf.au oz.au -// CGDNs - http://www.cgdn.org.au/ +// CGDNs : https://www.auda.org.au/au-domain-names/the-different-au-domain-names/state-and-territory-domain-names/ act.au nsw.au nt.au @@ -252,9 +269,9 @@ sa.edu.au tas.edu.au vic.edu.au wa.edu.au -// act.gov.au Bug 984824 - Removed at request of Greg Tankard -// nsw.gov.au Bug 547985 - Removed at request of -// nt.gov.au Bug 940478 - Removed at request of Greg Connors +// act.gov.au - Bug 984824 - Removed at request of Greg Tankard +// nsw.gov.au - Bug 547985 - Removed at request of +// nt.gov.au - Bug 940478 - Removed at request of Greg Connors qld.gov.au sa.gov.au tas.gov.au @@ -264,29 +281,33 @@ wa.gov.au // education.tas.edu.au - Removed at the request of the Department of Education Tasmania schools.nsw.edu.au -// aw : https://en.wikipedia.org/wiki/.aw +// aw : https://www.iana.org/domains/root/db/aw.html aw com.aw -// ax : https://en.wikipedia.org/wiki/.ax +// ax : https://www.iana.org/domains/root/db/ax.html ax -// az : https://en.wikipedia.org/wiki/.az +// az : https://www.iana.org/domains/root/db/az.html +// Confirmed via https://whois.az/?page_id=10 2024-12-11 az +biz.az +co.az com.az -net.az -int.az -gov.az -org.az edu.az +gov.az info.az -pp.az +int.az mil.az name.az +net.az +org.az +pp.az +// No longer available for registration, however domains exist as of 2024-12-11 +// see https://whois.az/?page_id=783 pro.az -biz.az -// ba : http://nic.ba/users_data/files/pravilnik_o_registraciji.pdf +// ba : https://www.iana.org/domains/root/db/ba.html ba com.ba edu.ba @@ -295,7 +316,7 @@ mil.ba net.ba org.ba -// bb : https://en.wikipedia.org/wiki/.bb +// bb : https://www.iana.org/domains/root/db/bb.html bb biz.bb co.bb @@ -308,21 +329,31 @@ org.bb store.bb tv.bb -// bd : https://en.wikipedia.org/wiki/.bd +// bd : https://www.iana.org/domains/root/db/bd.html *.bd -// be : https://en.wikipedia.org/wiki/.be +// be : https://www.iana.org/domains/root/db/be.html // Confirmed by registry 2008-06-08 be ac.be -// bf : https://en.wikipedia.org/wiki/.bf +// bf : https://www.iana.org/domains/root/db/bf.html bf gov.bf -// bg : https://en.wikipedia.org/wiki/.bg +// bg : https://www.iana.org/domains/root/db/bg.html // https://www.register.bg/user/static/rules/en/index.html bg +0.bg +1.bg +2.bg +3.bg +4.bg +5.bg +6.bg +7.bg +8.bg +9.bg a.bg b.bg c.bg @@ -349,26 +380,16 @@ w.bg x.bg y.bg z.bg -0.bg -1.bg -2.bg -3.bg -4.bg -5.bg -6.bg -7.bg -8.bg -9.bg -// bh : https://en.wikipedia.org/wiki/.bh +// bh : https://www.iana.org/domains/root/db/bh.html bh com.bh edu.bh +gov.bh net.bh org.bh -gov.bh -// bi : https://en.wikipedia.org/wiki/.bi +// bi : https://www.iana.org/domains/root/db/bi.html // http://whois.nic.bi/ bi co.bi @@ -377,11 +398,11 @@ edu.bi or.bi org.bi -// biz : https://en.wikipedia.org/wiki/.biz +// biz : https://www.iana.org/domains/root/db/biz.html biz // bj : https://nic.bj/bj-suffixes.txt -// submitted by registry +// Submitted by registry bj africa.bj agro.bj @@ -399,12 +420,12 @@ money.bj net.bj org.bj ote.bj -resto.bj restaurant.bj +resto.bj tourism.bj univ.bj -// bm : http://www.bermudanic.bm/dnr-text.txt +// bm : https://www.bermudanic.bm/domain-registration/index.php bm com.bm edu.bm @@ -420,15 +441,16 @@ gov.bn net.bn org.bn -// bo : https://nic.bo/delegacion2015.php#h-1.10 +// bo : https://nic.bo +// Confirmed by registry 2024-11-19 bo com.bo edu.bo gob.bo int.bo -org.bo -net.bo mil.bo +net.bo +org.bo tv.bo web.bo // Social Domains @@ -454,9 +476,9 @@ natural.bo nombre.bo noticias.bo patria.bo +plurinacional.bo politica.bo profesional.bo -plurinacional.bo pueblo.bo revista.bo salud.bo @@ -484,6 +506,7 @@ ato.br b.br barueri.br belem.br +bet.br bhz.br bib.br bio.br @@ -571,6 +594,7 @@ joinville.br jor.br jus.br leg.br +leilao.br lel.br log.br londrina.br @@ -641,12 +665,12 @@ zlg.br // bs : http://www.nic.bs/rules.html bs com.bs -net.bs -org.bs edu.bs gov.bs +net.bs +org.bs -// bt : https://en.wikipedia.org/wiki/.bt +// bt : https://www.iana.org/domains/root/db/bt.html bt com.bt edu.bt @@ -658,14 +682,16 @@ org.bt // Submitted by registry bv -// bw : https://en.wikipedia.org/wiki/.bw -// http://www.gobin.info/domainname/bw.doc -// list of other 2nd level tlds ? +// bw : https://www.iana.org/domains/root/db/bw.html +// https://nic.net.bw/bw-name-structure bw +ac.bw co.bw +gov.bw +net.bw org.bw -// by : https://en.wikipedia.org/wiki/.by +// by : https://www.iana.org/domains/root/db/by.html // http://tld.by/rules_2006_en.html // list of other 2nd level tlds ? by @@ -675,20 +701,20 @@ mil.by // second-level domain, but it's being used as one (see www.google.com.by and // www.yahoo.com.by, for example), so we list it here for safety's sake. com.by - // http://hoster.by/ of.by -// bz : https://en.wikipedia.org/wiki/.bz +// bz : https://www.iana.org/domains/root/db/bz.html // http://www.belizenic.bz/ bz +co.bz com.bz -net.bz -org.bz edu.bz gov.bz +net.bz +org.bz -// ca : https://en.wikipedia.org/wiki/.ca +// ca : https://www.iana.org/domains/root/db/ca.html ca // ca geographical names ab.ca @@ -709,46 +735,43 @@ yk.ca // see also: http://registry.gc.ca/en/SubdomainFAQ gc.ca -// cat : https://en.wikipedia.org/wiki/.cat +// cat : https://www.iana.org/domains/root/db/cat.html cat -// cc : https://en.wikipedia.org/wiki/.cc +// cc : https://www.iana.org/domains/root/db/cc.html cc -// cd : https://en.wikipedia.org/wiki/.cd -// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1 +// cd : https://www.iana.org/domains/root/db/cd.html +// https://www.nic.cd cd gov.cd -// cf : https://en.wikipedia.org/wiki/.cf +// cf : https://www.iana.org/domains/root/db/cf.html cf -// cg : https://en.wikipedia.org/wiki/.cg +// cg : https://www.iana.org/domains/root/db/cg.html cg -// ch : https://en.wikipedia.org/wiki/.ch +// ch : https://www.iana.org/domains/root/db/ch.html ch -// ci : https://en.wikipedia.org/wiki/.ci -// http://www.nic.ci/index.php?page=charte +// ci : https://www.iana.org/domains/root/db/ci.html ci -org.ci -or.ci -com.ci +ac.ci +aéroport.ci +asso.ci co.ci -edu.ci +com.ci ed.ci -ac.ci -net.ci +edu.ci go.ci -asso.ci -aéroport.ci -int.ci -presse.ci -md.ci gouv.ci +int.ci +net.ci +or.ci +org.ci -// ck : https://en.wikipedia.org/wiki/.ck +// ck : https://www.iana.org/domains/root/db/ck.html *.ck !www.ck @@ -760,26 +783,26 @@ gob.cl gov.cl mil.cl -// cm : https://en.wikipedia.org/wiki/.cm plus bug 981927 +// cm : https://www.iana.org/domains/root/db/cm.html plus bug 981927 cm co.cm com.cm gov.cm net.cm -// cn : https://en.wikipedia.org/wiki/.cn +// cn : https://www.iana.org/domains/root/db/cn.html // Submitted by registry cn ac.cn com.cn edu.cn gov.cn +mil.cn net.cn org.cn -mil.cn 公司.cn -网络.cn 網絡.cn +网络.cn // cn geographic names ah.cn bj.cn @@ -787,18 +810,20 @@ cq.cn fj.cn gd.cn gs.cn -gz.cn gx.cn +gz.cn ha.cn hb.cn he.cn hi.cn +hk.cn hl.cn hn.cn jl.cn js.cn jx.cn ln.cn +mo.cn nm.cn nx.cn qh.cn @@ -808,38 +833,31 @@ sh.cn sn.cn sx.cn tj.cn +tw.cn xj.cn xz.cn yn.cn zj.cn -hk.cn -mo.cn -tw.cn -// co : https://en.wikipedia.org/wiki/.co -// Submitted by registry +// co : https://www.iana.org/domains/root/db/co.html +// https://www.cointernet.com.co/como-funciona-un-dominio-restringido +// Confirmed by registry 2024-11-18 co -arts.co com.co edu.co -firm.co gov.co -info.co -int.co mil.co net.co nom.co org.co -rec.co -web.co -// com : https://en.wikipedia.org/wiki/.com +// com : https://www.iana.org/domains/root/db/com.html com -// coop : https://en.wikipedia.org/wiki/.coop +// coop : https://www.iana.org/domains/root/db/coop.html coop -// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do +// cr : https://nic.cr/capitulo-1-registro-de-un-nombre-de-dominio/ cr ac.cr co.cr @@ -849,40 +867,45 @@ go.cr or.cr sa.cr -// cu : https://en.wikipedia.org/wiki/.cu +// cu : https://www.iana.org/domains/root/db/cu.html cu com.cu edu.cu -org.cu -net.cu -gov.cu +gob.cu inf.cu +nat.cu +net.cu +org.cu -// cv : https://en.wikipedia.org/wiki/.cv -// cv : http://www.dns.cv/tldcv_portal/do?com=DS;5446457100;111;+PAGE(4000018)+K-CAT-CODIGO(RDOM)+RCNT(100); <- registration rules +// cv : https://www.iana.org/domains/root/db/cv.html +// https://ola.cv/domain-extensions-under-cv/ +// Confirmed by registry 2024-11-26 cv com.cv edu.cv +id.cv int.cv +net.cv nome.cv org.cv +publ.cv -// cw : http://www.una.cw/cw_registry/ -// Confirmed by registry 2013-03-26 +// cw : https://www.uoc.cw/cw-registry +// Confirmed by registry 2024-11-19 cw com.cw edu.cw net.cw org.cw -// cx : https://en.wikipedia.org/wiki/.cx +// cx : https://www.iana.org/domains/root/db/cx.html // list of other 2nd level tlds ? cx gov.cx // cy : http://www.nic.cy/ -// Submitted by registry Panayiotou Fotia -// namespace policies URL https://www.nic.cy/portal//sites/default/files/symfonia_gia_eggrafi.pdf +// Submitted by Panayiotou Fotia +// https://nic.cy/wp-content/uploads/2024/01/Create-Request-for-domain-name-registration-1.pdf cy ac.cy biz.cy @@ -897,30 +920,33 @@ press.cy pro.cy tm.cy -// cz : https://en.wikipedia.org/wiki/.cz +// cz : https://www.iana.org/domains/root/db/cz.html cz -// de : https://en.wikipedia.org/wiki/.de +// de : https://www.iana.org/domains/root/db/de.html // Confirmed by registry (with technical // reservations) 2008-07-01 de -// dj : https://en.wikipedia.org/wiki/.dj +// dj : https://www.iana.org/domains/root/db/dj.html dj -// dk : https://en.wikipedia.org/wiki/.dk +// dk : https://www.iana.org/domains/root/db/dk.html // Confirmed by registry 2008-06-17 dk -// dm : https://en.wikipedia.org/wiki/.dm +// dm : https://www.iana.org/domains/root/db/dm.html +// https://nic.dm/policies/pdf/DMRulesandGuidelines2024v1.pdf +// Confirmed by registry 2024-11-19 dm +co.dm com.dm -net.dm -org.dm edu.dm gov.dm +net.dm +org.dm -// do : https://en.wikipedia.org/wiki/.do +// do : https://www.iana.org/domains/root/db/do.html do art.do com.do @@ -940,88 +966,93 @@ asso.dz com.dz edu.dz gov.dz -org.dz net.dz +org.dz pol.dz soc.dz tm.dz -// ec : http://www.nic.ec/reg/paso1.asp +// ec : https://www.nic.ec/ // Submitted by registry ec com.ec -info.ec -net.ec +edu.ec fin.ec +gob.ec +gov.ec +info.ec k12.ec med.ec -pro.ec -org.ec -edu.ec -gov.ec -gob.ec mil.ec +net.ec +org.ec +pro.ec -// edu : https://en.wikipedia.org/wiki/.edu +// edu : https://www.iana.org/domains/root/db/edu.html edu -// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B +// ee : https://www.internet.ee/domains/general-domains-and-procedure-for-registration-of-sub-domains-under-general-domains ee +aip.ee +com.ee edu.ee +fie.ee gov.ee -riik.ee lib.ee med.ee -com.ee -pri.ee -aip.ee org.ee -fie.ee +pri.ee +riik.ee -// eg : https://en.wikipedia.org/wiki/.eg +// eg : https://www.iana.org/domains/root/db/eg.html +// https://domain.eg/en/domain-rules/subdomain-names-types/ eg +ac.eg com.eg edu.eg eun.eg gov.eg +info.eg +me.eg mil.eg name.eg net.eg org.eg sci.eg +sport.eg +tv.eg -// er : https://en.wikipedia.org/wiki/.er +// er : https://www.iana.org/domains/root/db/er.html *.er -// es : https://www.nic.es/site_ingles/ingles/dominios/index.html +// es : https://www.dominios.es/en es com.es +edu.es +gob.es nom.es org.es -gob.es -edu.es -// et : https://en.wikipedia.org/wiki/.et +// et : https://www.iana.org/domains/root/db/et.html et +biz.et com.et -gov.et -org.et edu.et -biz.et -name.et +gov.et info.et +name.et net.et +org.et -// eu : https://en.wikipedia.org/wiki/.eu +// eu : https://www.iana.org/domains/root/db/eu.html eu -// fi : https://en.wikipedia.org/wiki/.fi +// fi : https://www.iana.org/domains/root/db/fi.html fi -// aland.fi : https://en.wikipedia.org/wiki/.ax +// aland.fi : https://www.iana.org/domains/root/db/ax.html // This domain is being phased out in favor of .ax. As there are still many // domains under aland.fi, we still keep it on the list until aland.fi is // completely removed. -// TODO: Check for updates (expected to be phased out around Q1/2009) aland.fi // fj : http://domains.fj/ @@ -1038,17 +1069,17 @@ net.fj org.fj pro.fj -// fk : https://en.wikipedia.org/wiki/.fk +// fk : https://www.iana.org/domains/root/db/fk.html *.fk -// fm : https://en.wikipedia.org/wiki/.fm +// fm : https://www.iana.org/domains/root/db/fm.html +fm com.fm edu.fm net.fm org.fm -fm -// fo : https://en.wikipedia.org/wiki/.fo +// fo : https://www.iana.org/domains/root/db/fo.html fo // fr : https://www.afnic.fr/ https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf @@ -1065,59 +1096,60 @@ cci.fr greta.fr huissier-justice.fr -// ga : https://en.wikipedia.org/wiki/.ga +// ga : https://www.iana.org/domains/root/db/ga.html ga // gb : This registry is effectively dormant // Submitted by registry gb -// gd : https://en.wikipedia.org/wiki/.gd +// gd : https://www.iana.org/domains/root/db/gd.html +gd edu.gd gov.gd -gd -// ge : http://www.nic.net.ge/policy_en.pdf +// ge : https://nic.ge/en/administrator/the-ge-domain-regulations +// Confirmed by registry 2024-11-20 ge com.ge edu.ge gov.ge -org.ge -mil.ge net.ge +org.ge pvt.ge +school.ge -// gf : https://en.wikipedia.org/wiki/.gf +// gf : https://www.iana.org/domains/root/db/gf.html gf -// gg : http://www.channelisles.net/register-domains/ +// gg : https://www.channelisles.net/register-1/register-direct // Confirmed by registry 2013-11-28 gg co.gg net.gg org.gg -// gh : https://en.wikipedia.org/wiki/.gh -// see also: http://www.nic.gh/reg_now.php +// gh : https://www.iana.org/domains/root/db/gh.html +// https://www.nic.gh/ // Although domains directly at second level are not possible at the moment, // they have been possible for some time and may come back. gh com.gh edu.gh gov.gh -org.gh mil.gh +org.gh // gi : http://www.nic.gi/rules.html gi com.gi -ltd.gi +edu.gi gov.gi +ltd.gi mod.gi -edu.gi org.gi -// gl : https://en.wikipedia.org/wiki/.gl +// gl : https://www.iana.org/domains/root/db/gl.html // http://nic.gl gl co.gl @@ -1136,34 +1168,34 @@ ac.gn com.gn edu.gn gov.gn -org.gn net.gn +org.gn -// gov : https://en.wikipedia.org/wiki/.gov +// gov : https://www.iana.org/domains/root/db/gov.html gov // gp : http://www.nic.gp/index.php?lang=en gp +asso.gp com.gp -net.gp -mobi.gp edu.gp +mobi.gp +net.gp org.gp -asso.gp -// gq : https://en.wikipedia.org/wiki/.gq +// gq : https://www.iana.org/domains/root/db/gq.html gq -// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html +// gr : https://www.iana.org/domains/root/db/gr.html // Submitted by registry gr com.gr edu.gr +gov.gr net.gr org.gr -gov.gr -// gs : https://en.wikipedia.org/wiki/.gs +// gs : https://www.iana.org/domains/root/db/gs.html gs // gt : https://www.gt/sitio/registration_policy.php?lang=en @@ -1189,11 +1221,11 @@ net.gu org.gu web.gu -// gw : https://en.wikipedia.org/wiki/.gw +// gw : https://www.iana.org/domains/root/db/gw.html // gw : https://nic.gw/regras/ gw -// gy : https://en.wikipedia.org/wiki/.gy +// gy : https://www.iana.org/domains/root/db/gy.html // http://registry.gy/ gy co.gy @@ -1212,97 +1244,97 @@ gov.hk idv.hk net.hk org.hk +个人.hk +個人.hk 公司.hk -教育.hk -敎育.hk 政府.hk -個人.hk -个人.hk +敎育.hk +教育.hk 箇人.hk +組織.hk +組织.hk +網絡.hk 網络.hk -网络.hk 组織.hk -網絡.hk -网絡.hk 组织.hk -組織.hk -組织.hk +网絡.hk +网络.hk -// hm : https://en.wikipedia.org/wiki/.hm +// hm : https://www.iana.org/domains/root/db/hm.html hm -// hn : http://www.nic.hn/politicas/ps02,,05.html +// hn : https://www.iana.org/domains/root/db/hn.html hn com.hn edu.hn -org.hn -net.hn -mil.hn gob.hn +mil.hn +net.hn +org.hn // hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf hr -iz.hr +com.hr from.hr +iz.hr name.hr -com.hr // ht : http://www.nic.ht/info/charte.cfm ht +adult.ht +art.ht +asso.ht com.ht -shop.ht +coop.ht +edu.ht firm.ht +gouv.ht info.ht -adult.ht +med.ht net.ht -pro.ht org.ht -med.ht -art.ht -coop.ht +perso.ht pol.ht -asso.ht -edu.ht +pro.ht rel.ht -gouv.ht -perso.ht +shop.ht -// hu : http://www.domain.hu/domain/English/sld.html +// hu : https://www.iana.org/domains/root/db/hu.html // Confirmed by registry 2008-06-12 hu -co.hu -info.hu -org.hu -priv.hu -sport.hu -tm.hu 2000.hu agrar.hu bolt.hu casino.hu city.hu +co.hu erotica.hu erotika.hu film.hu forum.hu games.hu hotel.hu +info.hu ingatlan.hu jogasz.hu konyvelo.hu lakas.hu media.hu news.hu +org.hu +priv.hu reklam.hu sex.hu shop.hu +sport.hu suli.hu szex.hu +tm.hu tozsde.hu utazas.hu video.hu -// id : https://pandi.id/en/domain/registration-requirements/ +// id : https://www.iana.org/domains/root/db/id.html id ac.id biz.id @@ -1317,13 +1349,13 @@ ponpes.id sch.id web.id -// ie : https://en.wikipedia.org/wiki/.ie +// ie : https://www.iana.org/domains/root/db/ie.html ie gov.ie -// il : http://www.isoc.org.il/domains/ -// see also: https://en.isoc.org.il/il-cctld/registration-rules -// ISOC-IL (operated by .il Registry) +// il : http://www.isoc.org.il/domains/ +// see also: https://en.isoc.org.il/il-cctld/registration-rules +// ISOC-IL (operated by .il Registry) il ac.il co.il @@ -1349,15 +1381,15 @@ org.il im ac.im co.im -com.im ltd.co.im +plc.co.im +com.im net.im org.im -plc.co.im tt.im tv.im -// in : https://en.wikipedia.org/wiki/.in +// in : https://www.iana.org/domains/root/db/in.html // see also: https://registry.in/policies // Please note, that nic.in is not an official eTLD, but used by most // government institutions. @@ -1404,27 +1436,33 @@ uk.in up.in us.in -// info : https://en.wikipedia.org/wiki/.info +// info : https://www.iana.org/domains/root/db/info.html info -// int : https://en.wikipedia.org/wiki/.int +// int : https://www.iana.org/domains/root/db/int.html // Confirmed by registry 2008-06-18 int eu.int // io : http://www.nic.io/rules.htm -// list of other 2nd level tlds ? io +co.io com.io +edu.io +gov.io +mil.io +net.io +nom.io +org.io // iq : http://www.cmc.iq/english/iq/iqregister1.htm iq -gov.iq +com.iq edu.iq +gov.iq mil.iq -com.iq -org.iq net.iq +org.iq // ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules // Also see http://www.nic.ir/Internationalized_Domain_Names @@ -1443,22 +1481,16 @@ sch.ir ايران.ir // is : http://www.isnic.is/domain/rules.php -// Confirmed by registry 2008-12-06 +// Confirmed by registry 2024-11-17 is -net.is -com.is -edu.is -gov.is -org.is -int.is - -// it : https://en.wikipedia.org/wiki/.it + +// it : https://www.iana.org/domains/root/db/it.html +// https://www.nic.it/ it -gov.it edu.it -// Reserved geo-names (regions and provinces): -// https://www.nic.it/sites/default/files/archivio/docs/Regulation_assignation_v7.1.pdf -// Regions +gov.it +// Regions (3.3.1) +// https://www.nic.it/en/manage-your-it/forms-and-docs -> "Assignment and Management of domain names" abr.it abruzzo.it aosta-valley.it @@ -1517,6 +1549,7 @@ trentin-sudtirol.it trentin-südtirol.it trentin-sued-tirol.it trentin-suedtirol.it +trentino.it trentino-a-adige.it trentino-aadige.it trentino-alto-adige.it @@ -1529,7 +1562,6 @@ trentino-sudtirol.it trentino-südtirol.it trentino-sued-tirol.it trentino-suedtirol.it -trentino.it trentinoa-adige.it trentinoaadige.it trentinoalto-adige.it @@ -1573,7 +1605,7 @@ vao.it vda.it ven.it veneto.it -// Provinces +// Provinces (3.3.2) ag.it agrigento.it al.it @@ -1601,10 +1633,10 @@ at.it av.it avellino.it ba.it +balsan.it balsan-sudtirol.it balsan-südtirol.it balsan-suedtirol.it -balsan.it bari.it barletta-trani-andria.it barlettatraniandria.it @@ -1618,21 +1650,21 @@ bl.it bn.it bo.it bologna.it -bolzano-altoadige.it bolzano.it +bolzano-altoadige.it +bozen.it bozen-sudtirol.it bozen-südtirol.it bozen-suedtirol.it -bozen.it br.it brescia.it brindisi.it bs.it bt.it +bulsan.it bulsan-sudtirol.it bulsan-südtirol.it bulsan-suedtirol.it -bulsan.it bz.it ca.it cagliari.it @@ -1734,9 +1766,9 @@ milano.it mn.it mo.it modena.it +monza.it monza-brianza.it monza-e-della-brianza.it -monza.it monzabrianza.it monzaebrianza.it monzaedellabrianza.it @@ -1815,8 +1847,8 @@ sondrio.it sp.it sr.it ss.it -suedtirol.it südtirol.it +suedtirol.it sv.it ta.it taranto.it @@ -1865,7 +1897,7 @@ vs.it vt.it vv.it -// je : http://www.channelisles.net/register-domains/ +// je : https://www.iana.org/domains/root/db/je.html // Confirmed by registry 2013-11-28 je co.je @@ -1875,23 +1907,30 @@ org.je // jm : http://www.com.jm/register.html *.jm -// jo : http://www.dns.jo/Registration_policy.aspx +// jo : https://www.dns.jo/JoFamily.aspx +// Confirmed by registry 2024-11-17 jo +agri.jo +ai.jo com.jo -org.jo -net.jo edu.jo -sch.jo +eng.jo +fm.jo gov.jo mil.jo -name.jo +net.jo +org.jo +per.jo +phd.jo +sch.jo +tv.jo -// jobs : https://en.wikipedia.org/wiki/.jobs +// jobs : https://www.iana.org/domains/root/db/jobs.html jobs -// jp : https://en.wikipedia.org/wiki/.jp +// jp : https://www.iana.org/domains/root/db/jp.html // http://jprs.co.jp/en/jpdomain.html -// Submitted by registry +// Confirmed by registry 2024-11-22 jp // jp organizational type names ac.jp @@ -1951,26 +1990,14 @@ wakayama.jp yamagata.jp yamaguchi.jp yamanashi.jp -栃木.jp -愛知.jp -愛媛.jp +三重.jp +京都.jp +佐賀.jp 兵庫.jp -熊本.jp -茨城.jp 北海道.jp 千葉.jp 和歌山.jp -長崎.jp -長野.jp -新潟.jp -青森.jp -静岡.jp -東京.jp -石川.jp 埼玉.jp -三重.jp -京都.jp -佐賀.jp 大分.jp 大阪.jp 奈良.jp @@ -1980,39 +2007,54 @@ yamanashi.jp 山口.jp 山形.jp 山梨.jp -岩手.jp 岐阜.jp 岡山.jp +岩手.jp 島根.jp 広島.jp 徳島.jp +愛媛.jp +愛知.jp +新潟.jp +東京.jp +栃木.jp 沖縄.jp 滋賀.jp +熊本.jp +石川.jp 神奈川.jp 福井.jp 福岡.jp 福島.jp 秋田.jp 群馬.jp +茨城.jp +長崎.jp +長野.jp +青森.jp +静岡.jp 香川.jp 高知.jp 鳥取.jp 鹿児島.jp // jp geographic type names // http://jprs.jp/doc/rule/saisoku-1.html +// 2024-11-22: JPRS confirmed that jp geographic type names no longer accept new registrations. +// Once all existing registrations expire (marking full discontinuation), these suffixes +// will be removed from the PSL. *.kawasaki.jp -*.kitakyushu.jp -*.kobe.jp -*.nagoya.jp -*.sapporo.jp -*.sendai.jp -*.yokohama.jp !city.kawasaki.jp +*.kitakyushu.jp !city.kitakyushu.jp +*.kobe.jp !city.kobe.jp +*.nagoya.jp !city.nagoya.jp +*.sapporo.jp !city.sapporo.jp +*.sendai.jp !city.sendai.jp +*.yokohama.jp !city.yokohama.jp // 4th level registration aisai.aichi.jp @@ -3703,56 +3745,56 @@ sc.ke // kg : http://www.domain.kg/dmn_n.html kg -org.kg -net.kg com.kg edu.kg gov.kg mil.kg +net.kg +org.kg // kh : http://www.mptc.gov.kh/dns_registration.htm *.kh -// ki : http://www.ki/dns/index.html +// ki : https://www.iana.org/domains/root/db/ki.html ki -edu.ki biz.ki -net.ki -org.ki +com.ki +edu.ki gov.ki info.ki -com.ki +net.ki +org.ki -// km : https://en.wikipedia.org/wiki/.km +// km : https://www.iana.org/domains/root/db/km.html // http://www.domaine.km/documents/charte.doc km -org.km -nom.km +ass.km +com.km +edu.km gov.km +mil.km +nom.km +org.km prd.km tm.km -edu.km -mil.km -ass.km -com.km // These are only mentioned as proposed suggestions at domaine.km, but -// https://en.wikipedia.org/wiki/.km says they're available for registration: -coop.km +// https://www.iana.org/domains/root/db/km.html says they're available for registration: asso.km -presse.km +coop.km +gouv.km medecin.km notaires.km pharmaciens.km +presse.km veterinaire.km -gouv.km -// kn : https://en.wikipedia.org/wiki/.kn +// kn : https://www.iana.org/domains/root/db/kn.html // http://www.dot.kn/domainRules.html kn -net.kn -org.kn edu.kn gov.kn +net.kn +org.kn // kp : http://www.kcce.kp/en_index.php kp @@ -3763,15 +3805,19 @@ org.kp rep.kp tra.kp -// kr : https://en.wikipedia.org/wiki/.kr -// see also: http://domain.nida.or.kr/eng/registration.jsp +// kr : https://www.iana.org/domains/root/db/kr.html +// see also: https://krnic.kisa.or.kr/jsp/infoboard/law/domBylawsReg.jsp kr ac.kr +ai.kr co.kr es.kr go.kr hs.kr +io.kr +it.kr kg.kr +me.kr mil.kr ms.kr ne.kr @@ -3816,29 +3862,29 @@ edu.ky net.ky org.ky -// kz : https://en.wikipedia.org/wiki/.kz +// kz : https://www.iana.org/domains/root/db/kz.html // see also: http://www.nic.kz/rules/index.jsp kz -org.kz +com.kz edu.kz -net.kz gov.kz mil.kz -com.kz +net.kz +org.kz -// la : https://en.wikipedia.org/wiki/.la +// la : https://www.iana.org/domains/root/db/la.html // Submitted by registry la -int.la -net.la -info.la +com.la edu.la gov.la -per.la -com.la +info.la +int.la +net.la org.la +per.la -// lb : https://en.wikipedia.org/wiki/.lb +// lb : https://www.iana.org/domains/root/db/lb.html // Submitted by registry lb com.lb @@ -3847,36 +3893,36 @@ gov.lb net.lb org.lb -// lc : https://en.wikipedia.org/wiki/.lc +// lc : https://www.iana.org/domains/root/db/lc.html // see also: http://www.nic.lc/rules.htm lc -com.lc -net.lc co.lc -org.lc +com.lc edu.lc gov.lc +net.lc +org.lc -// li : https://en.wikipedia.org/wiki/.li +// li : https://www.iana.org/domains/root/db/li.html li -// lk : https://www.nic.lk/index.php/domain-registration/lk-domain-naming-structure +// lk : https://www.iana.org/domains/root/db/lk.html lk -gov.lk -sch.lk -net.lk -int.lk +ac.lk +assn.lk com.lk -org.lk edu.lk +gov.lk +grp.lk +hotel.lk +int.lk +ltd.lk +net.lk ngo.lk +org.lk +sch.lk soc.lk web.lk -ltd.lk -assn.lk -grp.lk -hotel.lk -ac.lk // lr : http://psg.com/dns/lr/lr.txt // Submitted by registry @@ -3884,8 +3930,8 @@ lr com.lr edu.lr gov.lr -org.lr net.lr +org.lr // ls : http://www.nic.ls/ // Confirmed by registry @@ -3900,7 +3946,7 @@ net.ls org.ls sc.ls -// lt : https://en.wikipedia.org/wiki/.lt +// lt : https://www.iana.org/domains/root/db/lt.html lt // gov.lt : http://www.gov.lt/index_en.php gov.lt @@ -3908,131 +3954,136 @@ gov.lt // lu : http://www.dns.lu/en/ lu -// lv : http://www.nic.lv/DNS/En/generic.php +// lv : https://www.iana.org/domains/root/db/lv.html lv +asn.lv com.lv +conf.lv edu.lv gov.lv -org.lv -mil.lv id.lv +mil.lv net.lv -asn.lv -conf.lv +org.lv // ly : http://www.nic.ly/regulations.php ly com.ly -net.ly -gov.ly -plc.ly edu.ly -sch.ly +gov.ly +id.ly med.ly +net.ly org.ly -id.ly +plc.ly +sch.ly -// ma : https://en.wikipedia.org/wiki/.ma +// ma : https://www.iana.org/domains/root/db/ma.html // http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf ma +ac.ma co.ma -net.ma gov.ma +net.ma org.ma -ac.ma press.ma // mc : http://www.nic.mc/ mc -tm.mc asso.mc +tm.mc -// md : https://en.wikipedia.org/wiki/.md +// md : https://www.iana.org/domains/root/db/md.html md -// me : https://en.wikipedia.org/wiki/.me +// me : https://www.iana.org/domains/root/db/me.html me +ac.me co.me -net.me -org.me edu.me -ac.me gov.me its.me +net.me +org.me priv.me -// mg : http://nic.mg/nicmg/?page_id=39 +// mg : https://nic.mg mg -org.mg -nom.mg -gov.mg -prd.mg -tm.mg +co.mg +com.mg edu.mg +gov.mg mil.mg -com.mg -co.mg +nom.mg +org.mg +prd.mg -// mh : https://en.wikipedia.org/wiki/.mh +// mh : https://www.iana.org/domains/root/db/mh.html mh -// mil : https://en.wikipedia.org/wiki/.mil +// mil : https://www.iana.org/domains/root/db/mil.html mil -// mk : https://en.wikipedia.org/wiki/.mk +// mk : https://www.iana.org/domains/root/db/mk.html // see also: http://dns.marnet.net.mk/postapka.php mk com.mk -org.mk -net.mk edu.mk gov.mk inf.mk name.mk +net.mk +org.mk -// ml : http://www.gobin.info/domainname/ml-template.doc -// see also: https://en.wikipedia.org/wiki/.ml +// ml : https://www.iana.org/domains/root/db/ml.html +// Confirmed by Boubacar NDIAYE 2024-12-31 ml +ac.ml +art.ml +asso.ml com.ml edu.ml gouv.ml gov.ml +info.ml +inst.ml net.ml org.ml +pr.ml presse.ml -// mm : https://en.wikipedia.org/wiki/.mm +// mm : https://www.iana.org/domains/root/db/mm.html *.mm -// mn : https://en.wikipedia.org/wiki/.mn +// mn : https://www.iana.org/domains/root/db/mn.html mn -gov.mn edu.mn +gov.mn org.mn // mo : http://www.monic.net.mo/ mo com.mo -net.mo -org.mo edu.mo gov.mo +net.mo +org.mo -// mobi : https://en.wikipedia.org/wiki/.mobi +// mobi : https://www.iana.org/domains/root/db/mobi.html mobi // mp : http://www.dot.mp/ // Confirmed by registry 2008-06-17 mp -// mq : https://en.wikipedia.org/wiki/.mq +// mq : https://www.iana.org/domains/root/db/mq.html mq -// mr : https://en.wikipedia.org/wiki/.mr +// mr : https://www.iana.org/domains/root/db/mr.html mr gov.mr -// ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf +// ms : https://www.iana.org/domains/root/db/ms.html ms com.ms edu.ms @@ -4048,20 +4099,20 @@ edu.mt net.mt org.mt -// mu : https://en.wikipedia.org/wiki/.mu +// mu : https://www.iana.org/domains/root/db/mu.html mu -com.mu -net.mu -org.mu -gov.mu ac.mu co.mu +com.mu +gov.mu +net.mu or.mu +org.mu // museum : https://welcome.museum/wp-content/uploads/2018/05/20180525-Registration-Policy-MUSEUM-EN_VF-2.pdf https://welcome.museum/buy-your-dot-museum-2/ museum -// mv : https://en.wikipedia.org/wiki/.mv +// mv : https://www.iana.org/domains/root/db/mv.html // "mv" included because, contra Wikipedia, google.mv exists. mv aero.mv @@ -4089,7 +4140,6 @@ coop.mw edu.mw gov.mw int.mw -museum.mw net.mw org.mw @@ -4097,10 +4147,10 @@ org.mw // Submitted by registry mx com.mx -org.mx -gob.mx edu.mx +gob.mx net.mx +org.mx // my : http://www.mynic.my/ // Available strings: https://mynic.my/resources/domains/buying-a-domain/ @@ -4127,27 +4177,16 @@ net.mz org.mz // na : http://www.na-nic.com.na/ -// http://www.info.na/domain/ na -info.na -pro.na -name.na -school.na -or.na -dr.na -us.na -mx.na -ca.na -in.na -cc.na -tv.na -ws.na -mobi.na +alt.na co.na com.na +gov.na +net.na org.na -// name : has 2nd-level tlds, but there's no list of them +// name : http://www.nic.name/ +// Regarding 2LDs: https://github.com/publicsuffix/list/issues/2306 name // nc : http://www.cctld.nc/ @@ -4155,24 +4194,24 @@ nc asso.nc nom.nc -// ne : https://en.wikipedia.org/wiki/.ne +// ne : https://www.iana.org/domains/root/db/ne.html ne -// net : https://en.wikipedia.org/wiki/.net +// net : https://www.iana.org/domains/root/db/net.html net -// nf : https://en.wikipedia.org/wiki/.nf +// nf : https://www.iana.org/domains/root/db/nf.html nf -com.nf -net.nf -per.nf -rec.nf -web.nf arts.nf +com.nf firm.nf info.nf +net.nf other.nf +per.nf +rec.nf store.nf +web.nf // ng : http://www.nira.org.ng/index.php/join-us/register-ng-domain/189-nira-slds ng @@ -4204,9 +4243,8 @@ nom.ni org.ni web.ni -// nl : https://en.wikipedia.org/wiki/.nl -// https://www.sidn.nl/ -// ccTLD for the Netherlands +// nl : https://www.iana.org/domains/root/db/nl.html +// https://www.sidn.nl/ nl // no : https://www.norid.no/en/om-domenenavn/regelverk-for-no/ @@ -4217,18 +4255,18 @@ nl no // Norid category second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-c/ fhs.no -vgs.no -fylkesbibl.no folkebibl.no -museum.no +fylkesbibl.no idrett.no +museum.no priv.no +vgs.no // Norid category second-level domains managed by parties other than Norid : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-d/ -mil.no -stat.no dep.no -kommune.no herad.no +kommune.no +mil.no +stat.no // Norid geographical second level domains : https://www.norid.no/en/om-domenenavn/regelverk-for-no/vedlegg-b/ // counties aa.no @@ -4280,10 +4318,10 @@ akrehamn.no algard.no ålgård.no arna.no -brumunddal.no -bryne.no bronnoysund.no brønnøysund.no +brumunddal.no +bryne.no drobak.no drøbak.no egersund.no @@ -4327,27 +4365,32 @@ tananger.no tranby.no vossevangen.no // communities +aarborte.no +aejrie.no afjord.no åfjord.no agdenes.no +nes.akershus.no +aknoluokta.no +ákŋoluokta.no al.no ål.no +alaheadju.no +álaheadju.no alesund.no ålesund.no alstahaug.no alta.no áltá.no -alaheadju.no -álaheadju.no alvdal.no amli.no åmli.no amot.no åmot.no +andasuolo.no andebu.no andoy.no andøy.no -andasuolo.no ardal.no årdal.no aremark.no @@ -4357,9 +4400,9 @@ aseral.no åseral.no asker.no askim.no -askvoll.no askoy.no askøy.no +askvoll.no asnes.no åsnes.no audnedaln.no @@ -4372,27 +4415,37 @@ austevoll.no austrheim.no averoy.no averøy.no -balestrand.no -ballangen.no +badaddja.no +bådåddjå.no +bærum.no +bahcavuotna.no +báhcavuotna.no +bahccavuotna.no +báhccavuotna.no +baidar.no +báidár.no +bajddar.no +bájddar.no balat.no bálát.no +balestrand.no +ballangen.no balsfjord.no -bahccavuotna.no -báhccavuotna.no bamble.no bardu.no +barum.no +batsfjord.no +båtsfjord.no +bearalvahki.no +bearalváhki.no beardu.no beiarn.no -bajddar.no -bájddar.no -baidar.no -báidár.no berg.no bergen.no berlevag.no berlevåg.no -bearalvahki.no -bearalváhki.no +bievat.no +bievát.no bindal.no birkenes.no bjarkoy.no @@ -4401,36 +4454,32 @@ bjerkreim.no bjugn.no bodo.no bodø.no -badaddja.no -bådåddjå.no -budejju.no bokn.no +bomlo.no +bømlo.no bremanger.no bronnoy.no brønnøy.no +budejju.no +nes.buskerud.no bygland.no bykle.no -barum.no -bærum.no -bo.telemark.no -bø.telemark.no -bo.nordland.no -bø.nordland.no -bievat.no -bievát.no -bomlo.no -bømlo.no -batsfjord.no -båtsfjord.no -bahcavuotna.no -báhcavuotna.no +cahcesuolo.no +čáhcesuolo.no +davvenjarga.no +davvenjárga.no +davvesiida.no +deatnu.no +dielddanuorri.no +divtasvuodna.no +divttasvuotna.no +donna.no +dønna.no dovre.no drammen.no drangedal.no dyroy.no dyrøy.no -donna.no -dønna.no eid.no eidfjord.no eidsberg.no @@ -4442,14 +4491,12 @@ enebakk.no engerdal.no etne.no etnedal.no -evenes.no evenassi.no evenášši.no +evenes.no evje-og-hornnes.no farsund.no fauske.no -fuossko.no -fuoisku.no fedje.no fet.no finnoy.no @@ -4457,33 +4504,40 @@ finnøy.no fitjar.no fjaler.no fjell.no +fla.no +flå.no flakstad.no flatanger.no flekkefjord.no flesberg.no flora.no -fla.no -flå.no folldal.no +forde.no +førde.no forsand.no fosnes.no +fræna.no +frana.no frei.no frogn.no froland.no frosta.no -frana.no -fræna.no froya.no frøya.no +fuoisku.no +fuossko.no fusa.no fyresdal.no -forde.no -førde.no +gaivuotna.no +gáivuotna.no +galsa.no +gálsá.no gamvik.no gangaviika.no gáŋgaviika.no gaular.no gausdal.no +giehtavuoatna.no gildeskal.no gildeskål.no giske.no @@ -4501,38 +4555,37 @@ granvin.no gratangen.no grimstad.no grong.no -kraanghke.no -kråanghke.no grue.no gulen.no +guovdageaidnu.no +ha.no +hå.no +habmer.no +hábmer.no hadsel.no +hægebostad.no +hagebostad.no halden.no halsa.no hamar.no hamaroy.no -habmer.no -hábmer.no -hapmir.no -hápmir.no -hammerfest.no hammarfeasta.no hámmárfeasta.no +hammerfest.no +hapmir.no +hápmir.no haram.no hareid.no harstad.no hasvik.no -aknoluokta.no -ákŋoluokta.no hattfjelldal.no -aarborte.no haugesund.no +os.hedmark.no +valer.hedmark.no +våler.hedmark.no hemne.no hemnes.no hemsedal.no -heroy.more-og-romsdal.no -herøy.møre-og-romsdal.no -heroy.nordland.no -herøy.nordland.no hitra.no hjartdal.no hjelmeland.no @@ -4544,96 +4597,95 @@ hole.no holmestrand.no holtalen.no holtålen.no +os.hordaland.no hornindal.no horten.no -hurdal.no -hurum.no -hvaler.no -hyllestad.no -hagebostad.no -hægebostad.no hoyanger.no høyanger.no hoylandet.no høylandet.no -ha.no -hå.no +hurdal.no +hurum.no +hvaler.no +hyllestad.no ibestad.no inderoy.no inderøy.no iveland.no +ivgu.no jevnaker.no -jondal.no jolster.no jølster.no -karasjok.no +jondal.no +kafjord.no +kåfjord.no karasjohka.no kárášjohka.no +karasjok.no karlsoy.no -galsa.no -gálsá.no karmoy.no karmøy.no kautokeino.no -guovdageaidnu.no -klepp.no klabu.no klæbu.no +klepp.no kongsberg.no kongsvinger.no +kraanghke.no +kråanghke.no kragero.no kragerø.no kristiansand.no kristiansund.no krodsherad.no krødsherad.no +kvæfjord.no +kvænangen.no +kvafjord.no kvalsund.no -rahkkeravju.no -ráhkkerávju.no kvam.no +kvanangen.no kvinesdal.no kvinnherad.no kviteseid.no kvitsoy.no kvitsøy.no -kvafjord.no -kvæfjord.no -giehtavuoatna.no -kvanangen.no -kvænangen.no -navuotna.no -návuotna.no -kafjord.no -kåfjord.no -gaivuotna.no -gáivuotna.no +laakesvuemie.no +lærdal.no +lahppi.no +láhppi.no +lardal.no larvik.no -lavangen.no lavagis.no -loabat.no -loabát.no +lavangen.no +leangaviika.no +leaŋgaviika.no lebesby.no -davvesiida.no leikanger.no leirfjord.no leka.no leksvik.no lenvik.no -leangaviika.no -leaŋgaviika.no +lerdal.no lesja.no levanger.no lier.no lierne.no lillehammer.no lillesand.no -lindesnes.no lindas.no lindås.no +lindesnes.no +loabat.no +loabát.no +lodingen.no +lødingen.no lom.no loppa.no -lahppi.no -láhppi.no +lorenskog.no +lørenskog.no +loten.no +løten.no lund.no lunner.no luroy.no @@ -4641,25 +4693,19 @@ lurøy.no luster.no lyngdal.no lyngen.no -ivgu.no -lardal.no -lerdal.no -lærdal.no -lodingen.no -lødingen.no -lorenskog.no -lørenskog.no -loten.no -løten.no +malatvuopmi.no +málatvuopmi.no +malselv.no +målselv.no malvik.no -masoy.no -måsøy.no -muosat.no -muosát.no mandal.no marker.no marnardal.no masfjorden.no +masoy.no +måsøy.no +matta-varjjat.no +mátta-várjjat.no meland.no meldal.no melhus.no @@ -4667,39 +4713,39 @@ meloy.no meløy.no meraker.no meråker.no -moareke.no -moåreke.no midsund.no midtre-gauldal.no +moareke.no +moåreke.no modalen.no modum.no molde.no +heroy.more-og-romsdal.no +sande.more-og-romsdal.no +herøy.møre-og-romsdal.no +sande.møre-og-romsdal.no moskenes.no moss.no mosvik.no -malselv.no -målselv.no -malatvuopmi.no -málatvuopmi.no +muosat.no +muosát.no +naamesjevuemie.no +nååmesjevuemie.no +nærøy.no namdalseid.no -aejrie.no namsos.no namsskogan.no -naamesjevuemie.no -nååmesjevuemie.no -laakesvuemie.no nannestad.no -narvik.no +naroy.no narviika.no +narvik.no naustdal.no +navuotna.no +návuotna.no nedre-eiker.no -nes.akershus.no -nes.buskerud.no nesna.no nesodden.no nesseby.no -unjarga.no -unjárga.no nesset.no nissedal.no nittedal.no @@ -4708,21 +4754,20 @@ nord-fron.no nord-odal.no norddal.no nordkapp.no -davvenjarga.no -davvenjárga.no +bo.nordland.no +bø.nordland.no +heroy.nordland.no +herøy.nordland.no nordre-land.no nordreisa.no -raisa.no -ráisa.no nore-og-uvdal.no notodden.no -naroy.no -nærøy.no notteroy.no nøtterøy.no odda.no oksnes.no øksnes.no +omasvuotna.no oppdal.no oppegard.no oppegård.no @@ -4733,11 +4778,11 @@ orskog.no ørskog.no orsta.no ørsta.no -os.hedmark.no -os.hordaland.no osen.no osteroy.no osterøy.no +valer.ostfold.no +våler.østfold.no ostre-toten.no østre-toten.no overhalla.no @@ -4753,12 +4798,19 @@ porsanger.no porsangu.no porsáŋgu.no porsgrunn.no +rade.no +råde.no radoy.no radøy.no -rakkestad.no -rana.no -ruovat.no -randaberg.no +rælingen.no +rahkkeravju.no +ráhkkerávju.no +raisa.no +ráisa.no +rakkestad.no +ralingen.no +rana.no +randaberg.no rauma.no rendalen.no rennebu.no @@ -4768,16 +4820,14 @@ rindal.no ringebu.no ringerike.no ringsaker.no -rissa.no risor.no risør.no +rissa.no roan.no -rollag.no -rygge.no -ralingen.no -rælingen.no rodoy.no rødøy.no +rollag.no +romsa.no romskog.no rømskog.no roros.no @@ -4788,18 +4838,14 @@ royken.no røyken.no royrvik.no røyrvik.no -rade.no -råde.no +ruovat.no +rygge.no salangen.no -siellak.no -saltdal.no salat.no -sálát.no sálat.no +sálát.no +saltdal.no samnanger.no -sande.more-og-romsdal.no -sande.møre-og-romsdal.no -sande.vestfold.no sandefjord.no sandnes.no sandoy.no @@ -4811,39 +4857,60 @@ sel.no selbu.no selje.no seljord.no +siellak.no sigdal.no siljan.no sirdal.no +skanit.no +skánit.no +skanland.no +skånland.no skaun.no skedsmo.no ski.no skien.no -skiptvet.no -skjervoy.no -skjervøy.no skierva.no skiervá.no +skiptvet.no skjak.no skjåk.no +skjervoy.no +skjervøy.no skodje.no -skanland.no -skånland.no -skanit.no -skánit.no smola.no smøla.no -snillfjord.no +snaase.no +snåase.no snasa.no snåsa.no +snillfjord.no snoasa.no -snaase.no -snåase.no sogndal.no +sogne.no +søgne.no sokndal.no sola.no solund.no +somna.no +sømna.no +sondre-land.no +søndre-land.no songdalen.no +sor-aurdal.no +sør-aurdal.no +sor-fron.no +sør-fron.no +sor-odal.no +sør-odal.no +sor-varanger.no +sør-varanger.no +sorfold.no +sørfold.no +sorreisa.no +sørreisa.no sortland.no +sorum.no +sørum.no spydeberg.no stange.no stavanger.no @@ -4856,7 +4923,6 @@ stor-elvdal.no stord.no stordal.no storfjord.no -omasvuotna.no strand.no stranda.no stryn.no @@ -4868,72 +4934,55 @@ surnadal.no sveio.no svelvik.no sykkylven.no -sogne.no -søgne.no -somna.no -sømna.no -sondre-land.no -søndre-land.no -sor-aurdal.no -sør-aurdal.no -sor-fron.no -sør-fron.no -sor-odal.no -sør-odal.no -sor-varanger.no -sør-varanger.no -matta-varjjat.no -mátta-várjjat.no -sorfold.no -sørfold.no -sorreisa.no -sørreisa.no -sorum.no -sørum.no tana.no -deatnu.no +bo.telemark.no +bø.telemark.no time.no tingvoll.no tinn.no tjeldsund.no -dielddanuorri.no tjome.no tjøme.no tokke.no tolga.no +tonsberg.no +tønsberg.no torsken.no +træna.no +trana.no tranoy.no tranøy.no +troandin.no +trogstad.no +trøgstad.no +tromsa.no tromso.no tromsø.no -tromsa.no -romsa.no trondheim.no -troandin.no trysil.no -trana.no -træna.no -trogstad.no -trøgstad.no tvedestrand.no tydal.no tynset.no tysfjord.no -divtasvuodna.no -divttasvuotna.no tysnes.no -tysvar.no tysvær.no -tonsberg.no -tønsberg.no +tysvar.no ullensaker.no ullensvang.no ulvik.no +unjarga.no +unjárga.no utsira.no +vaapste.no vadso.no vadsø.no -cahcesuolo.no -čáhcesuolo.no +værøy.no +vaga.no +vågå.no +vagan.no +vågan.no +vagsoy.no +vågsøy.no vaksdal.no valle.no vang.no @@ -4942,8 +4991,8 @@ vardo.no vardø.no varggat.no várggát.no +varoy.no vefsn.no -vaapste.no vega.no vegarshei.no vegårshei.no @@ -4951,6 +5000,7 @@ vennesla.no verdal.no verran.no vestby.no +sande.vestfold.no vestnes.no vestre-slidre.no vestre-toten.no @@ -4960,21 +5010,9 @@ vevelstad.no vik.no vikna.no vindafjord.no +voagat.no volda.no voss.no -varoy.no -værøy.no -vagan.no -vågan.no -voagat.no -vagsoy.no -vågsøy.no -vaga.no -vågå.no -valer.ostfold.no -våler.østfold.no -valer.hedmark.no -våler.hedmark.no // np : http://www.mos.com.np/register.html *.np @@ -4983,17 +5021,17 @@ våler.hedmark.no // Submitted by registry nr biz.nr -info.nr -gov.nr +com.nr edu.nr -org.nr +gov.nr +info.nr net.nr -com.nr +org.nr -// nu : https://en.wikipedia.org/wiki/.nu +// nu : https://www.iana.org/domains/root/db/nu.html nu -// nz : https://en.wikipedia.org/wiki/.nz +// nz : https://www.iana.org/domains/root/db/nz.html // Submitted by registry nz ac.nz @@ -5006,14 +5044,14 @@ health.nz iwi.nz kiwi.nz maori.nz -mil.nz māori.nz +mil.nz net.nz org.nz parliament.nz school.nz -// om : https://en.wikipedia.org/wiki/.om +// om : https://www.iana.org/domains/root/db/om.html om co.om com.om @@ -5028,82 +5066,84 @@ pro.om // onion : https://tools.ietf.org/html/rfc7686 onion -// org : https://en.wikipedia.org/wiki/.org +// org : https://www.iana.org/domains/root/db/org.html org // pa : http://www.nic.pa/ // Some additional second level "domains" resolve directly as hostnames, such as // pannet.pa, so we add a rule for "pa". pa +abo.pa ac.pa -gob.pa com.pa -org.pa -sld.pa edu.pa -net.pa +gob.pa ing.pa -abo.pa med.pa +net.pa nom.pa +org.pa +sld.pa // pe : https://www.nic.pe/InformeFinalComision.pdf pe +com.pe edu.pe gob.pe -nom.pe mil.pe -org.pe -com.pe net.pe +nom.pe +org.pe // pf : http://www.gobin.info/domainname/formulaire-pf.pdf pf com.pf -org.pf edu.pf +org.pf -// pg : https://en.wikipedia.org/wiki/.pg +// pg : https://www.iana.org/domains/root/db/pg.html *.pg -// ph : http://www.domains.ph/FAQ2.asp +// ph : https://www.iana.org/domains/root/db/ph.html // Submitted by registry ph com.ph -net.ph -org.ph -gov.ph edu.ph -ngo.ph -mil.ph +gov.ph i.ph +mil.ph +net.ph +ngo.ph +org.ph -// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK +// pk : https://pk5.pknic.net.pk/pk5/msgNamepk.PK +// Contact Email: staff@pknic.net.pk pk +ac.pk +biz.pk com.pk -net.pk edu.pk -org.pk fam.pk -biz.pk -web.pk -gov.pk +gkp.pk gob.pk +gog.pk gok.pk -gon.pk gop.pk gos.pk -info.pk +gov.pk +net.pk +org.pk +web.pk -// pl http://www.dns.pl/english/index.html -// Submitted by registry +// pl : https://www.dns.pl/en/ +// Confirmed by registry 2024-11-18 pl com.pl net.pl org.pl -// pl functional domains (http://www.dns.pl/english/index.html) -aid.pl +// pl functional domains : https://www.dns.pl/en/list_of_functional_domain_names agro.pl +aid.pl atm.pl auto.pl biz.pl @@ -5112,8 +5152,8 @@ gmina.pl gsm.pl info.pl mail.pl -miasta.pl media.pl +miasta.pl mil.pl nieruchomosci.pl nom.pl @@ -5132,7 +5172,8 @@ tm.pl tourism.pl travel.pl turystyka.pl -// Government domains +// Government domains : https://www.dns.pl/informacje_o_rejestracji_domen_gov_pl +// In accordance with the .gov.pl Domain Name Regulations : https://www.dns.pl/regulamin_gov_pl gov.pl ap.gov.pl griw.gov.pl @@ -5189,7 +5230,7 @@ wuoz.gov.pl wzmiuw.gov.pl zp.gov.pl zpisdn.gov.pl -// pl regional domains (http://www.dns.pl/english/index.html) +// pl regional domains : https://www.dns.pl/en/list_of_regional_domain_names augustow.pl babia-gora.pl bedzin.pl @@ -5216,11 +5257,11 @@ jaworzno.pl jelenia-gora.pl jgora.pl kalisz.pl -kazimierz-dolny.pl karpacz.pl kartuzy.pl kaszuby.pl katowice.pl +kazimierz-dolny.pl kepno.pl ketrzyn.pl klodzko.pl @@ -5263,8 +5304,8 @@ pisz.pl podhale.pl podlasie.pl polkowice.pl -pomorze.pl pomorskie.pl +pomorze.pl prochowice.pl pruszkow.pl przeworsk.pl @@ -5275,11 +5316,11 @@ rybnik.pl rzeszow.pl sanok.pl sejny.pl +skoczow.pl slask.pl slupsk.pl sosnowiec.pl stalowa-wola.pl -skoczow.pl starachowice.pl stargard.pl suwalki.pl @@ -5313,33 +5354,33 @@ zgorzelec.pl // pm : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf pm -// pn : http://www.government.pn/PnRegistry/policies.htm +// pn : https://www.iana.org/domains/root/db/pn.html pn -gov.pn co.pn -org.pn edu.pn +gov.pn net.pn +org.pn -// post : https://en.wikipedia.org/wiki/.post +// post : https://www.iana.org/domains/root/db/post.html post // pr : http://www.nic.pr/index.asp?f=1 pr +biz.pr com.pr -net.pr -org.pr -gov.pr edu.pr -isla.pr -pro.pr -biz.pr +gov.pr info.pr +isla.pr name.pr -// these aren't mentioned on nic.pr, but on https://en.wikipedia.org/wiki/.pr +net.pr +org.pr +pro.pr +// these aren't mentioned on nic.pr, but on https://www.iana.org/domains/root/db/pr.html +ac.pr est.pr prof.pr -ac.pr // pro : http://registry.pro/get-pro pro @@ -5355,38 +5396,34 @@ law.pro med.pro recht.pro -// ps : https://en.wikipedia.org/wiki/.ps +// ps : https://www.iana.org/domains/root/db/ps.html // http://www.nic.ps/registration/policy.html#reg ps +com.ps edu.ps gov.ps -sec.ps -plo.ps -com.ps -org.ps net.ps +org.ps +plo.ps +sec.ps // pt : https://www.dns.pt/en/domain/pt-terms-and-conditions-registration-rules/ pt -net.pt -gov.pt -org.pt +com.pt edu.pt +gov.pt int.pt -publ.pt -com.pt +net.pt nome.pt +org.pt +publ.pt -// pw : https://en.wikipedia.org/wiki/.pw +// pw : https://www.iana.org/domains/root/db/pw.html +// Confirmed by registry in private correspondence with @dnsguru 2024-12-09 pw -co.pw -ne.pw -or.pw -ed.pw -go.pw -belau.pw - -// py : http://www.nic.py/pautas.html#seccion_9 +gov.pw + +// py : https://www.iana.org/domains/root/db/py.html // Submitted by registry py com.py @@ -5409,10 +5446,11 @@ org.qa sch.qa // re : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf +// Confirmed by registry 2024-11-18 re +// Closed for registration on 2013-03-15 but domains are still maintained asso.re com.re -nom.re // ro : http://www.rotld.ro/ ro @@ -5441,7 +5479,7 @@ org.rs // Submitted by George Georgievsky ru -// rw : https://www.ricta.org.rw/sites/default/files/resources/registry_registrar_contract_0.pdf +// rw : https://www.iana.org/domains/root/db/rw.html rw ac.rw co.rw @@ -5454,12 +5492,12 @@ org.rw // sa : http://www.nic.net.sa/ sa com.sa -net.sa -org.sa +edu.sa gov.sa med.sa +net.sa +org.sa pub.sa -edu.sa sch.sa // sb : http://www.sbnic.net.sb/ @@ -5474,25 +5512,26 @@ org.sb // sc : http://www.nic.sc/ sc com.sc +edu.sc gov.sc net.sc org.sc -edu.sc -// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm +// sd : https://www.iana.org/domains/root/db/sd.html // Submitted by registry sd com.sd -net.sd -org.sd edu.sd -med.sd -tv.sd gov.sd info.sd - -// se : https://en.wikipedia.org/wiki/.se -// Submitted by registry +med.sd +net.sd +org.sd +tv.sd + +// se : https://www.iana.org/domains/root/db/se.html +// https://data.internetstiftelsen.se/barred_domains_list.txt -> Second level domains & Sub-domains +// Confirmed by Registry Services 2024-11-20 se a.se ac.se @@ -5534,47 +5573,46 @@ x.se y.se z.se -// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines +// sg : https://www.sgnic.sg/domain-registration/sg-categories-rules +// Confirmed by registry 2024-11-19 sg com.sg +edu.sg +gov.sg net.sg org.sg -gov.sg -edu.sg -per.sg // sh : http://nic.sh/rules.htm sh com.sh -net.sh gov.sh -org.sh mil.sh +net.sh +org.sh -// si : https://en.wikipedia.org/wiki/.si +// si : https://www.iana.org/domains/root/db/si.html si // sj : No registrations at this time. // Submitted by registry sj -// sk : https://en.wikipedia.org/wiki/.sk -// list of 2nd level domains ? +// sk : https://www.iana.org/domains/root/db/sk.html sk // sl : http://www.nic.sl // Submitted by registry sl com.sl -net.sl edu.sl gov.sl +net.sl org.sl -// sm : https://en.wikipedia.org/wiki/.sm +// sm : https://www.iana.org/domains/root/db/sm.html sm -// sn : https://en.wikipedia.org/wiki/.sn +// sn : https://www.iana.org/domains/root/db/sn.html sn art.sn com.sn @@ -5593,13 +5631,14 @@ me.so net.so org.so -// sr : https://en.wikipedia.org/wiki/.sr +// sr : https://www.iana.org/domains/root/db/sr.html sr // ss : https://registry.nic.ss/ // Submitted by registry ss biz.ss +co.ss com.ss edu.ss gov.ss @@ -5622,10 +5661,10 @@ principe.st saotome.st store.st -// su : https://en.wikipedia.org/wiki/.su +// su : https://www.iana.org/domains/root/db/su.html su -// sv : http://www.svnet.org.sv/niveldos.pdf +// sv : https://www.iana.org/domains/root/db/sv.html sv com.sv edu.sv @@ -5633,46 +5672,45 @@ gob.sv org.sv red.sv -// sx : https://en.wikipedia.org/wiki/.sx +// sx : https://www.iana.org/domains/root/db/sx.html // Submitted by registry sx gov.sx -// sy : https://en.wikipedia.org/wiki/.sy -// see also: http://www.gobin.info/domainname/sy.doc +// sy : https://www.iana.org/domains/root/db/sy.html sy +com.sy edu.sy gov.sy -net.sy mil.sy -com.sy +net.sy org.sy -// sz : https://en.wikipedia.org/wiki/.sz +// sz : https://www.iana.org/domains/root/db/sz.html // http://www.sispa.org.sz/ sz -co.sz ac.sz +co.sz org.sz -// tc : https://en.wikipedia.org/wiki/.tc +// tc : https://www.iana.org/domains/root/db/tc.html tc -// td : https://en.wikipedia.org/wiki/.td +// td : https://www.iana.org/domains/root/db/td.html td -// tel: https://en.wikipedia.org/wiki/.tel +// tel : https://www.iana.org/domains/root/db/tel.html // http://www.telnic.org/ tel // tf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf tf -// tg : https://en.wikipedia.org/wiki/.tg +// tg : https://www.iana.org/domains/root/db/tg.html // http://www.nic.tg/ tg -// th : https://en.wikipedia.org/wiki/.th +// th : https://www.iana.org/domains/root/db/th.html // Submitted by registry th ac.th @@ -5701,23 +5739,24 @@ org.tj test.tj web.tj -// tk : https://en.wikipedia.org/wiki/.tk +// tk : https://www.iana.org/domains/root/db/tk.html tk -// tl : https://en.wikipedia.org/wiki/.tl +// tl : https://www.iana.org/domains/root/db/tl.html tl gov.tl -// tm : http://www.nic.tm/local.html +// tm : https://www.nic.tm/local.html +// Confirmed by registry 2024-11-19 tm -com.tm co.tm -org.tm -net.tm -nom.tm +com.tm +edu.tm gov.tm mil.tm -edu.tm +net.tm +nom.tm +org.tm // tn : http://www.registre.tn/fr/ // https://whois.ati.tn/ @@ -5736,15 +5775,15 @@ org.tn perso.tn tourism.tn -// to : https://en.wikipedia.org/wiki/.to +// to : https://www.iana.org/domains/root/db/to.html // Submitted by registry to com.to +edu.to gov.to +mil.to net.to org.to -edu.to -mil.to // tr : https://nic.tr/ // https://nic.tr/forms/eng/policies.pdf @@ -5760,9 +5799,9 @@ edu.tr gen.tr gov.tr info.tr -mil.tr k12.tr kep.tr +mil.tr name.tr net.tr org.tr @@ -5776,46 +5815,40 @@ nc.tr // Used by government agencies of Northern Cyprus gov.nc.tr -// tt : http://www.nic.tt/ +// tt : https://www.nic.tt/ +// Confirmed by registry 2024-11-19 tt +biz.tt co.tt com.tt -org.tt -net.tt -biz.tt +edu.tt +gov.tt info.tt -pro.tt -int.tt -coop.tt -jobs.tt -mobi.tt -travel.tt -museum.tt -aero.tt +mil.tt name.tt -gov.tt -edu.tt +net.tt +org.tt +pro.tt -// tv : https://en.wikipedia.org/wiki/.tv +// tv : https://www.iana.org/domains/root/db/tv.html // Not listing any 2LDs as reserved since none seem to exist in practice, // Wikipedia notwithstanding. tv -// tw : https://en.wikipedia.org/wiki/.tw +// tw : https://www.iana.org/domains/root/db/tw.html +// https://twnic.tw/dnservice_catag.php +// Confirmed by registry 2024-11-26 tw +club.tw +com.tw +ebiz.tw edu.tw +game.tw gov.tw +idv.tw mil.tw -com.tw net.tw org.tw -idv.tw -game.tw -ebiz.tw -club.tw -網路.tw -組織.tw -商業.tw // tz : http://www.tznic.or.tz/index.php/domains // Submitted by registry @@ -5920,17 +5953,23 @@ zp.ua zt.ua // ug : https://www.registry.co.ug/ +// https://www.registry.co.ug, https://whois.co.ug +// Confirmed by registry 2025-01-20 ug -co.ug -or.ug ac.ug -sc.ug +co.ug +com.ug +edu.ug go.ug +gov.ug +mil.ug ne.ug -com.ug +or.ug org.ug +sc.ug +us.ug -// uk : https://en.wikipedia.org/wiki/.uk +// uk : https://www.iana.org/domains/root/db/uk.html // Submitted by registry uk ac.uk @@ -5945,14 +5984,13 @@ plc.uk police.uk *.sch.uk -// us : https://en.wikipedia.org/wiki/.us +// us : https://www.iana.org/domains/root/db/us.html +// Confirmed via the .us zone file by William Harrison 2024-12-10 us dni.us -fed.us isa.us -kids.us nsn.us -// us geographic names +// Geographic Names ak.us al.us ar.us @@ -6001,9 +6039,9 @@ sd.us tn.us tx.us ut.us +va.us vi.us vt.us -va.us wa.us wi.us wv.us @@ -6026,7 +6064,7 @@ k12.dc.us k12.fl.us k12.ga.us k12.gu.us -// k12.hi.us Bug 614565 - Hawaii has a state-wide DOE login +// k12.hi.us - Bug 614565 - Hawaii has a state-wide DOE login k12.ia.us k12.id.us k12.il.us @@ -6043,7 +6081,7 @@ k12.mo.us k12.ms.us k12.mt.us k12.nc.us -// k12.nd.us Bug 1028347 - Removed at request of Travis Rosso +// k12.nd.us - Bug 1028347 - Removed at request of Travis Rosso k12.ne.us k12.nh.us k12.nj.us @@ -6055,28 +6093,36 @@ k12.ok.us k12.or.us k12.pa.us k12.pr.us -// k12.ri.us Removed at request of Kim Cournoyer +// k12.ri.us - Removed at request of Kim Cournoyer k12.sc.us -// k12.sd.us Bug 934131 - Removed at request of James Booze +// k12.sd.us - Bug 934131 - Removed at request of James Booze k12.tn.us k12.tx.us k12.ut.us +k12.va.us k12.vi.us k12.vt.us -k12.va.us k12.wa.us k12.wi.us -// k12.wv.us Bug 947705 - Removed at request of Verne Britton -k12.wy.us +// k12.wv.us - Bug 947705 - Removed at request of Verne Britton cc.ak.us +lib.ak.us cc.al.us +lib.al.us cc.ar.us +lib.ar.us cc.as.us +lib.as.us cc.az.us +lib.az.us cc.ca.us +lib.ca.us cc.co.us +lib.co.us cc.ct.us +lib.ct.us cc.dc.us +lib.dc.us cc.de.us cc.fl.us cc.ga.us @@ -6116,23 +6162,15 @@ cc.sd.us cc.tn.us cc.tx.us cc.ut.us +cc.va.us cc.vi.us cc.vt.us -cc.va.us cc.wa.us cc.wi.us cc.wv.us cc.wy.us -lib.ak.us -lib.al.us -lib.ar.us -lib.as.us -lib.az.us -lib.ca.us -lib.co.us -lib.ct.us -lib.dc.us -// lib.de.us Issue #243 - Moved to Private section at request of Ed Moore +k12.wy.us +// lib.de.us - Issue #243 - Moved to Private section at request of Ed Moore lib.fl.us lib.ga.us lib.gu.us @@ -6171,23 +6209,23 @@ lib.sd.us lib.tn.us lib.tx.us lib.ut.us +lib.va.us lib.vi.us lib.vt.us -lib.va.us lib.wa.us lib.wi.us -// lib.wv.us Bug 941670 - Removed at request of Larry W Arnold +// lib.wv.us - Bug 941670 - Removed at request of Larry W Arnold lib.wy.us // k12.ma.us contains school districts in Massachusetts. The 4LDs are -// managed independently except for private (PVT), charter (CHTR) and -// parochial (PAROCH) schools. Those are delegated directly to the -// 5LD operators. -pvt.k12.ma.us +// managed independently except for private (PVT), charter (CHTR) and +// parochial (PAROCH) schools. Those are delegated directly to the +// 5LD operators. chtr.k12.ma.us paroch.k12.ma.us +pvt.k12.ma.us // Merit Network, Inc. maintains the registry for =~ /(k12|cc|lib).mi.us/ and the following -// see also: http://domreg.merit.edu -// see also: whois -h whois.domreg.merit.edu help +// see also: https://domreg.merit.edu : domreg@merit.edu +// see also: whois -h whois.domreg.merit.edu help ann-arbor.mi.us cog.mi.us dst.mi.us @@ -6213,18 +6251,18 @@ com.uz net.uz org.uz -// va : https://en.wikipedia.org/wiki/.va +// va : https://www.iana.org/domains/root/db/va.html va -// vc : https://en.wikipedia.org/wiki/.vc +// vc : https://www.iana.org/domains/root/db/vc.html // Submitted by registry vc com.vc -net.vc -org.vc +edu.vc gov.vc mil.vc -edu.vc +net.vc +org.vc // ve : https://registro.nic.ve/ // Submitted by registry nic@nic.ve and nicve@conatel.gob.ve @@ -6235,6 +6273,7 @@ co.ve com.ve e12.ve edu.ve +emprende.ve firm.ve gob.ve gov.ve @@ -6250,13 +6289,12 @@ store.ve tec.ve web.ve -// vg : https://en.wikipedia.org/wiki/.vg +// vg : https://www.iana.org/domains/root/db/vg.html +// Confirmed by registry 2025-01-10 vg +edu.vg -// vi : http://www.nic.vi/newdomainform.htm -// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other -// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they -// are available for registration (which they do not seem to be). +// vi : https://www.iana.org/domains/root/db/vi.html vi co.vi com.vi @@ -6348,7 +6386,7 @@ vinhlong.vn vinhphuc.vn yenbai.vn -// vu : https://en.wikipedia.org/wiki/.vu +// vu : https://www.iana.org/domains/root/db/vu.html // http://www.vunic.vu/ vu com.vu @@ -6359,14 +6397,14 @@ org.vu // wf : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf wf -// ws : https://en.wikipedia.org/wiki/.ws +// ws : https://www.iana.org/domains/root/db/ws.html // http://samoanic.ws/index.dhtml ws com.ws +edu.ws +gov.ws net.ws org.ws -gov.ws -edu.ws // yt : https://www.afnic.fr/wp-media/uploads/2022/12/afnic-naming-policy-2023-01-01.pdf yt @@ -6401,12 +6439,12 @@ yt // xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN // CNNIC -// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +// https://www.cnnic.cn/11/192/index.html 中国 // xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN // CNNIC -// http://cnnic.cn/html/Dir/2005/10/11/3218.htm +// https://www.cnnic.com.cn/AU/MediaC/Announcement/201609/t20160905_54470.htm 中國 // xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ @@ -6439,12 +6477,12 @@ yt // Submitted by registry // https://www.hkirc.hk/content.jsp?id=30#!/34 香港 +個人.香港 公司.香港 -教育.香港 政府.香港 -個人.香港 -網絡.香港 +教育.香港 組織.香港 +網絡.香港 // xn--2scrj9c ("Bharat", Kannada) : IN // India @@ -6575,12 +6613,12 @@ yt // xn--90a3ac ("srb", Cyrillic) : RS // https://www.rnids.rs/en/domains/national-domains срб -пр.срб -орг.срб +ак.срб обр.срб од.срб +орг.срб +пр.срб упр.срб -ак.срб // xn--p1ai ("rf", Russian-Cyrillic) : RU // https://cctld.ru/files/pdf/docs/en/rules_ru-rf.pdf @@ -6595,7 +6633,7 @@ yt // http://www.nic.net.sa/ السعودية -// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant) : SA +// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant): SA السعودیة // xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA @@ -6623,11 +6661,11 @@ yt // xn--o3cw4h ("Thai", Thai) : TH // http://www.thnic.co.th ไทย -ศึกษา.ไทย -ธุรกิจ.ไทย -รัฐบาล.ไทย ทหาร.ไทย +ธุรกิจ.ไทย เน็ต.ไทย +รัฐบาล.ไทย +ศึกษา.ไทย องค์กร.ไทย // xn--pgbs0dh ("Tunisia", Arabic) : TN @@ -6635,7 +6673,7 @@ yt تونس // xn--kpry57d ("Taiwan", Chinese, Traditional) : TW -// http://www.twnic.net/english/dn/dn_07a.htm +// https://twnic.tw/dnservice_catag.php 台灣 // xn--kprw13d ("Taiwan", Chinese, Simplified) : TW @@ -6659,11 +6697,11 @@ ye com.ye edu.ye gov.ye -net.ye mil.ye +net.ye org.ye -// za : https://www.zadna.org.za/content/page/domain-information/ +// za : https://www.iana.org/domains/root/db/za.html ac.za agric.za alt.za @@ -6707,10 +6745,9 @@ gov.zw mil.zw org.zw - // newGTLDs -// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2024-05-04T15:12:50Z +// List of new gTLDs imported from https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 2025-04-30T15:19:32Z // This list is auto-generated, don't edit it manually. // aaa : American Automobile Association, Inc. // https://www.iana.org/domains/root/db/aaa.html @@ -6940,7 +6977,7 @@ art // https://www.iana.org/domains/root/db/arte.html arte -// asda : Wal-Mart Stores, Inc. +// asda : Asda Stores Limited // https://www.iana.org/domains/root/db/asda.html asda @@ -7092,10 +7129,6 @@ beauty // https://www.iana.org/domains/root/db/beer.html beer -// bentley : Bentley Motors Limited -// https://www.iana.org/domains/root/db/bentley.html -bentley - // berlin : dotBERLIN GmbH & Co. KG // https://www.iana.org/domains/root/db/berlin.html berlin @@ -7656,10 +7689,6 @@ cymru // https://www.iana.org/domains/root/db/cyou.html cyou -// dabur : Dabur India Limited -// https://www.iana.org/domains/root/db/dabur.html -dabur - // dad : Charleston Road Registry Inc. // https://www.iana.org/domains/root/db/dad.html dad @@ -8112,7 +8141,7 @@ forex // https://www.iana.org/domains/root/db/forsale.html forsale -// forum : Fegistry, LLC +// forum : Waterford Limited // https://www.iana.org/domains/root/db/forum.html forum @@ -8152,7 +8181,7 @@ ftr // https://www.iana.org/domains/root/db/fujitsu.html fujitsu -// fun : Radix Technologies Inc. +// fun : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/fun.html fun @@ -8392,11 +8421,11 @@ haus // https://www.iana.org/domains/root/db/hbo.html hbo -// hdfc : HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED +// hdfc : HDFC BANK LIMITED // https://www.iana.org/domains/root/db/hdfc.html hdfc -// hdfcbank : HDFC Bank Limited +// hdfcbank : HDFC BANK LIMITED // https://www.iana.org/domains/root/db/hdfcbank.html hdfcbank @@ -8484,7 +8513,7 @@ horse // https://www.iana.org/domains/root/db/hospital.html hospital -// host : Radix Technologies Inc. +// host : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/host.html host @@ -8724,10 +8753,6 @@ kddi // https://www.iana.org/domains/root/db/kerryhotels.html kerryhotels -// kerrylogistics : Kerry Trading Co. Limited -// https://www.iana.org/domains/root/db/kerrylogistics.html -kerrylogistics - // kerryproperties : Kerry Trading Co. Limited // https://www.iana.org/domains/root/db/kerryproperties.html kerryproperties @@ -8808,10 +8833,6 @@ lamborghini // https://www.iana.org/domains/root/db/lamer.html lamer -// lancaster : LANCASTER -// https://www.iana.org/domains/root/db/lancaster.html -lancaster - // land : Binky Moon, LLC // https://www.iana.org/domains/root/db/land.html land @@ -8924,10 +8945,6 @@ lincoln // https://www.iana.org/domains/root/db/link.html link -// lipsy : Lipsy Ltd -// https://www.iana.org/domains/root/db/lipsy.html -lipsy - // live : Dog Beach, LLC // https://www.iana.org/domains/root/db/live.html live @@ -8976,7 +8993,7 @@ lotte // https://www.iana.org/domains/root/db/lotto.html lotto -// love : Merchant Law Group LLP +// love : Waterford Limited // https://www.iana.org/domains/root/db/love.html love @@ -9024,7 +9041,7 @@ maison // https://www.iana.org/domains/root/db/makeup.html makeup -// man : MAN SE +// man : MAN Truck & Bus SE // https://www.iana.org/domains/root/db/man.html man @@ -9060,7 +9077,7 @@ marriott // https://www.iana.org/domains/root/db/marshalls.html marshalls -// mattel : Mattel Sites, Inc. +// mattel : Mattel IT Services, Inc. // https://www.iana.org/domains/root/db/mattel.html mattel @@ -9104,6 +9121,10 @@ men // https://www.iana.org/domains/root/db/menu.html menu +// merck : Merck Registry Holdings, Inc. +// https://www.iana.org/domains/root/db/merck.html +merck + // merckmsd : MSD Registry Holdings, Inc. // https://www.iana.org/domains/root/db/merckmsd.html merckmsd @@ -9228,10 +9249,6 @@ nab // https://www.iana.org/domains/root/db/nagoya.html nagoya -// natura : NATURA COSMÉTICOS S.A. -// https://www.iana.org/domains/root/db/natura.html -natura - // navy : Dog Beach, LLC // https://www.iana.org/domains/root/db/navy.html navy @@ -9320,7 +9337,7 @@ nissay // https://www.iana.org/domains/root/db/nokia.html nokia -// norton : NortonLifeLock Inc. +// norton : Gen Digital Inc. // https://www.iana.org/domains/root/db/norton.html norton @@ -9328,7 +9345,7 @@ norton // https://www.iana.org/domains/root/db/now.html now -// nowruz : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// nowruz // https://www.iana.org/domains/root/db/nowruz.html nowruz @@ -9396,7 +9413,7 @@ ong // https://www.iana.org/domains/root/db/onl.html onl -// online : Radix Technologies Inc. +// online : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/online.html online @@ -9452,7 +9469,7 @@ panasonic // https://www.iana.org/domains/root/db/paris.html paris -// pars : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// pars // https://www.iana.org/domains/root/db/pars.html pars @@ -9520,7 +9537,7 @@ physio // https://www.iana.org/domains/root/db/pics.html pics -// pictet : Pictet Europe S.A. +// pictet : Banque Pictet & Cie SA // https://www.iana.org/domains/root/db/pictet.html pictet @@ -9600,7 +9617,7 @@ pramerica // https://www.iana.org/domains/root/db/praxi.html praxi -// press : Radix Technologies Inc. +// press : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/press.html press @@ -9688,7 +9705,7 @@ realestate // https://www.iana.org/domains/root/db/realtor.html realtor -// realty : Internet Naming Company LLC +// realty : Waterford Limited // https://www.iana.org/domains/root/db/realty.html realty @@ -10004,15 +10021,11 @@ shangrila // https://www.iana.org/domains/root/db/sharp.html sharp -// shaw : Shaw Cablesystems G.P. -// https://www.iana.org/domains/root/db/shaw.html -shaw - // shell : Shell Information Technology International Inc // https://www.iana.org/domains/root/db/shell.html shell -// shia : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// shia // https://www.iana.org/domains/root/db/shia.html shia @@ -10052,7 +10065,7 @@ sina // https://www.iana.org/domains/root/db/singles.html singles -// site : Radix Technologies Inc. +// site : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/site.html site @@ -10064,7 +10077,7 @@ ski // https://www.iana.org/domains/root/db/skin.html skin -// sky : Sky International AG +// sky : Sky UK Limited // https://www.iana.org/domains/root/db/sky.html sky @@ -10132,7 +10145,7 @@ soy // https://www.iana.org/domains/root/db/spa.html spa -// space : Radix Technologies Inc. +// space : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/space.html space @@ -10184,7 +10197,7 @@ stockholm // https://www.iana.org/domains/root/db/storage.html storage -// store : Radix Technologies Inc. +// store : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/store.html store @@ -10288,7 +10301,7 @@ tax // https://www.iana.org/domains/root/db/taxi.html taxi -// tci : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// tci // https://www.iana.org/domains/root/db/tci.html tci @@ -10300,7 +10313,7 @@ tdk // https://www.iana.org/domains/root/db/team.html team -// tech : Radix Technologies Inc. +// tech : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/tech.html tech @@ -10484,7 +10497,7 @@ unicom // https://www.iana.org/domains/root/db/university.html university -// uno : Radix Technologies Inc. +// uno : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/uno.html uno @@ -10500,7 +10513,7 @@ ups // https://www.iana.org/domains/root/db/vacations.html vacations -// vana : Internet Naming Company LLC +// vana : D3 Registry LLC // https://www.iana.org/domains/root/db/vana.html vana @@ -10648,7 +10661,7 @@ webcam // https://www.iana.org/domains/root/db/weber.html weber -// website : Radix Technologies Inc. +// website : Radix Technologies Inc SEZC // https://www.iana.org/domains/root/db/website.html website @@ -10772,7 +10785,7 @@ xin // https://www.iana.org/domains/root/db/xn--3bst00m.html 集团 -// xn--3ds443g : TLD REGISTRY LIMITED OY +// xn--3ds443g : Beijing TLD Registry Technology Limited // https://www.iana.org/domains/root/db/xn--3ds443g.html 在线 @@ -10996,7 +11009,7 @@ xin // https://www.iana.org/domains/root/db/xn--mgbi4ecexp.html كاثوليك -// xn--mgbt3dhd : Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti. +// xn--mgbt3dhd // https://www.iana.org/domains/root/db/xn--mgbt3dhd.html همراه @@ -11128,7 +11141,7 @@ yahoo // https://www.iana.org/domains/root/db/yamaxun.html yamaxun -// yandex : Yandex Europe B.V. +// yandex : YANDEX, LLC // https://www.iana.org/domains/root/db/yandex.html yandex @@ -11180,12 +11193,29 @@ zone // https://www.iana.org/domains/root/db/zuerich.html zuerich - // ===END ICANN DOMAINS=== + // ===BEGIN PRIVATE DOMAINS=== + // (Note: these are in alphabetical order by company name) -// 12CHARS: https://12chars.com +// .KRD : https://nic.krd +co.krd +edu.krd + +// .pl domains (grandfathered) +art.pl +gliwice.pl +krakow.pl +poznan.pl +wroc.pl +zakopane.pl + +// .US +// Submitted by Ed Moore +lib.de.us + +// 12CHARS : https://12chars.com // Submitted by Kenny Niehage 12chars.dev 12chars.it @@ -11197,31 +11227,19 @@ cc.ua inf.ua ltd.ua -// 611coin : https://611project.org/ +// 611 blockchain domain name system : https://611project.net/ 611.to -// AAA workspace : https://aaa.vodka -// Submitted by Kirill Rezraf -aaa.vodka - // A2 Hosting // Submitted by Tyler Hall a2hosted.com cpserver.com -// Aaron Marais' Gitlab pages: https://lab.aaronleem.co.za -// Submitted by Aaron Marais -graphox.us - -// accesso Technology Group, plc. : https://accesso.com/ -// Submitted by accesso Team -*.devcdnaccesso.com - // Acorn Labs : https://acorn.io // Submitted by Craig Jellick *.on-acorn.io -// ActiveTrail: https://www.activetrail.biz/ +// ActiveTrail : https://www.activetrail.biz/ // Submitted by Ofer Kalaora activetrail.biz @@ -11229,6 +11247,13 @@ activetrail.biz // Submitted by Mark Terrel adaptable.app +// addr.tools : https://addr.tools/ +// Submitted by Brian Shea +myaddr.dev +myaddr.io +dyn.addr.tools +myaddr.tools + // Adobe : https://www.adobe.com/ // Submitted by Ian Boston and Lars Trieloff adobeaemcloud.com @@ -11245,6 +11270,10 @@ hlx3.page adobeio-static.net adobeioruntime.net +// Africa.com Web Solutions Ltd : https://registry.africa.com +// Submitted by Gavin Brown +africa.com + // Agnat sp. z o.o. : https://domena.pl // Submitted by Przemyslaw Plewa beep.pl @@ -11255,8 +11284,9 @@ airkitapps.com airkitapps-au.com airkitapps.eu -// Aiven: https://aiven.io/ -// Submitted by Etienne Stalmans +// Aiven : https://aiven.io/ +// Submitted by Aiven Security Team +aiven.app aivencloud.com // Akamai : https://www.akamai.com/ @@ -11286,11 +11316,15 @@ barsy.ca *.compute.estate *.alces.network +// Alibaba Cloud API Gateway +// Submitted by Alibaba Cloud Security +alibabacloudcs.com + // all-inkl.com : https://all-inkl.com // Submitted by Werner Kaltofen kasserver.com -// Altervista: https://www.altervista.org +// Altervista : https://www.altervista.org // Submitted by Carlo Cannas altervista.org @@ -11308,7 +11342,7 @@ myamaze.net // Amazon API Gateway // Submitted by AWS Security -// Reference: 9e37648f-a66c-4655-9ab1-5981f8737197 +// Reference: 6a4f5a95-8c7d-4077-a7af-9cf1abec0a53 execute-api.cn-north-1.amazonaws.com.cn execute-api.cn-northwest-1.amazonaws.com.cn execute-api.af-south-1.amazonaws.com @@ -11322,6 +11356,7 @@ execute-api.ap-southeast-1.amazonaws.com execute-api.ap-southeast-2.amazonaws.com execute-api.ap-southeast-3.amazonaws.com execute-api.ap-southeast-4.amazonaws.com +execute-api.ap-southeast-5.amazonaws.com execute-api.ca-central-1.amazonaws.com execute-api.ca-west-1.amazonaws.com execute-api.eu-central-1.amazonaws.com @@ -11350,8 +11385,9 @@ cloudfront.net // Amazon Cognito // Submitted by AWS Security -// Reference: 09588633-91fe-49d8-b4e7-ec36496d11f3 +// Reference: eb4652f0-20f0-43f5-b323-e6cc6ae02ad7 auth.af-south-1.amazoncognito.com +auth.ap-east-1.amazoncognito.com auth.ap-northeast-1.amazoncognito.com auth.ap-northeast-2.amazoncognito.com auth.ap-northeast-3.amazoncognito.com @@ -11361,7 +11397,9 @@ auth.ap-southeast-1.amazoncognito.com auth.ap-southeast-2.amazoncognito.com auth.ap-southeast-3.amazoncognito.com auth.ap-southeast-4.amazoncognito.com +auth.ap-southeast-5.amazoncognito.com auth.ca-central-1.amazoncognito.com +auth.ca-west-1.amazoncognito.com auth.eu-central-1.amazoncognito.com auth.eu-central-2.amazoncognito.com auth.eu-north-1.amazoncognito.com @@ -11378,6 +11416,7 @@ auth.us-east-1.amazoncognito.com auth-fips.us-east-1.amazoncognito.com auth.us-east-2.amazoncognito.com auth-fips.us-east-2.amazoncognito.com +auth-fips.us-gov-east-1.amazoncognito.com auth-fips.us-gov-west-1.amazoncognito.com auth.us-west-1.amazoncognito.com auth-fips.us-west-1.amazoncognito.com @@ -11387,9 +11426,9 @@ auth-fips.us-west-2.amazoncognito.com // Amazon EC2 // Submitted by Luke Wells // Reference: 4c38fa71-58ac-4768-99e5-689c1767e537 +*.compute.amazonaws.com.cn *.compute.amazonaws.com *.compute-1.amazonaws.com -*.compute.amazonaws.com.cn us-east-1.amazonaws.com // Amazon EMR @@ -11497,23 +11536,32 @@ emrstudio-prod.us-west-2.amazonaws.com // Amazon Managed Workflows for Apache Airflow // Submitted by AWS Security -// Reference: 87f24ece-a77e-40e8-bb4a-f6b74fe9f975 +// Reference: f5ea5d0a-ec6a-4f23-ac1c-553fbff13f5c *.cn-north-1.airflow.amazonaws.com.cn *.cn-northwest-1.airflow.amazonaws.com.cn *.af-south-1.airflow.amazonaws.com *.ap-east-1.airflow.amazonaws.com *.ap-northeast-1.airflow.amazonaws.com *.ap-northeast-2.airflow.amazonaws.com +*.ap-northeast-3.airflow.amazonaws.com *.ap-south-1.airflow.amazonaws.com +*.ap-south-2.airflow.amazonaws.com *.ap-southeast-1.airflow.amazonaws.com *.ap-southeast-2.airflow.amazonaws.com +*.ap-southeast-3.airflow.amazonaws.com +*.ap-southeast-4.airflow.amazonaws.com *.ca-central-1.airflow.amazonaws.com +*.ca-west-1.airflow.amazonaws.com *.eu-central-1.airflow.amazonaws.com +*.eu-central-2.airflow.amazonaws.com *.eu-north-1.airflow.amazonaws.com *.eu-south-1.airflow.amazonaws.com +*.eu-south-2.airflow.amazonaws.com *.eu-west-1.airflow.amazonaws.com *.eu-west-2.airflow.amazonaws.com *.eu-west-3.airflow.amazonaws.com +*.il-central-1.airflow.amazonaws.com +*.me-central-1.airflow.amazonaws.com *.me-south-1.airflow.amazonaws.com *.sa-east-1.airflow.amazonaws.com *.us-east-1.airflow.amazonaws.com @@ -11523,7 +11571,7 @@ emrstudio-prod.us-west-2.amazonaws.com // Amazon S3 // Submitted by AWS Security -// Reference: cd5c8b3a-67b7-4b40-9236-c87ce81a3d10 +// Reference: ada5c9df-55e1-4195-a1ce-732d6c81e357 s3.dualstack.cn-north-1.amazonaws.com.cn s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn s3-website.dualstack.cn-north-1.amazonaws.com.cn @@ -11581,6 +11629,7 @@ s3-object-lambda.ap-south-1.amazonaws.com s3-website.ap-south-1.amazonaws.com s3.dualstack.ap-south-2.amazonaws.com s3-accesspoint.dualstack.ap-south-2.amazonaws.com +s3-website.dualstack.ap-south-2.amazonaws.com s3.ap-south-2.amazonaws.com s3-accesspoint.ap-south-2.amazonaws.com s3-object-lambda.ap-south-2.amazonaws.com @@ -11601,16 +11650,26 @@ s3-object-lambda.ap-southeast-2.amazonaws.com s3-website.ap-southeast-2.amazonaws.com s3.dualstack.ap-southeast-3.amazonaws.com s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com +s3-website.dualstack.ap-southeast-3.amazonaws.com s3.ap-southeast-3.amazonaws.com s3-accesspoint.ap-southeast-3.amazonaws.com s3-object-lambda.ap-southeast-3.amazonaws.com s3-website.ap-southeast-3.amazonaws.com s3.dualstack.ap-southeast-4.amazonaws.com s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com +s3-website.dualstack.ap-southeast-4.amazonaws.com s3.ap-southeast-4.amazonaws.com s3-accesspoint.ap-southeast-4.amazonaws.com s3-object-lambda.ap-southeast-4.amazonaws.com s3-website.ap-southeast-4.amazonaws.com +s3.dualstack.ap-southeast-5.amazonaws.com +s3-accesspoint.dualstack.ap-southeast-5.amazonaws.com +s3-website.dualstack.ap-southeast-5.amazonaws.com +s3.ap-southeast-5.amazonaws.com +s3-accesspoint.ap-southeast-5.amazonaws.com +s3-deprecated.ap-southeast-5.amazonaws.com +s3-object-lambda.ap-southeast-5.amazonaws.com +s3-website.ap-southeast-5.amazonaws.com s3.dualstack.ca-central-1.amazonaws.com s3-accesspoint.dualstack.ca-central-1.amazonaws.com s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com @@ -11631,6 +11690,7 @@ s3.ca-west-1.amazonaws.com s3-accesspoint.ca-west-1.amazonaws.com s3-accesspoint-fips.ca-west-1.amazonaws.com s3-fips.ca-west-1.amazonaws.com +s3-object-lambda.ca-west-1.amazonaws.com s3-website.ca-west-1.amazonaws.com s3.dualstack.eu-central-1.amazonaws.com s3-accesspoint.dualstack.eu-central-1.amazonaws.com @@ -11641,6 +11701,7 @@ s3-object-lambda.eu-central-1.amazonaws.com s3-website.eu-central-1.amazonaws.com s3.dualstack.eu-central-2.amazonaws.com s3-accesspoint.dualstack.eu-central-2.amazonaws.com +s3-website.dualstack.eu-central-2.amazonaws.com s3.eu-central-2.amazonaws.com s3-accesspoint.eu-central-2.amazonaws.com s3-object-lambda.eu-central-2.amazonaws.com @@ -11660,6 +11721,7 @@ s3-object-lambda.eu-south-1.amazonaws.com s3-website.eu-south-1.amazonaws.com s3.dualstack.eu-south-2.amazonaws.com s3-accesspoint.dualstack.eu-south-2.amazonaws.com +s3-website.dualstack.eu-south-2.amazonaws.com s3.eu-south-2.amazonaws.com s3-accesspoint.eu-south-2.amazonaws.com s3-object-lambda.eu-south-2.amazonaws.com @@ -11687,12 +11749,14 @@ s3-object-lambda.eu-west-3.amazonaws.com s3-website.eu-west-3.amazonaws.com s3.dualstack.il-central-1.amazonaws.com s3-accesspoint.dualstack.il-central-1.amazonaws.com +s3-website.dualstack.il-central-1.amazonaws.com s3.il-central-1.amazonaws.com s3-accesspoint.il-central-1.amazonaws.com s3-object-lambda.il-central-1.amazonaws.com s3-website.il-central-1.amazonaws.com s3.dualstack.me-central-1.amazonaws.com s3-accesspoint.dualstack.me-central-1.amazonaws.com +s3-website.dualstack.me-central-1.amazonaws.com s3.me-central-1.amazonaws.com s3-accesspoint.me-central-1.amazonaws.com s3-object-lambda.me-central-1.amazonaws.com @@ -11761,6 +11825,7 @@ s3.dualstack.us-east-2.amazonaws.com s3-accesspoint.dualstack.us-east-2.amazonaws.com s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com s3-fips.dualstack.us-east-2.amazonaws.com +s3-website.dualstack.us-east-2.amazonaws.com s3.us-east-2.amazonaws.com s3-accesspoint.us-east-2.amazonaws.com s3-accesspoint-fips.us-east-2.amazonaws.com @@ -11875,7 +11940,7 @@ notebook.cn-northwest-1.sagemaker.com.cn // Amazon SageMaker Studio // Submitted by AWS Security -// Reference: 69c723d9-6e1a-4bff-a203-48eecd203183 +// Reference: 475f237e-ab88-4041-9f41-7cfccdf66aeb studio.af-south-1.sagemaker.aws studio.ap-east-1.sagemaker.aws studio.ap-northeast-1.sagemaker.aws @@ -11887,6 +11952,7 @@ studio.ap-southeast-2.sagemaker.aws studio.ap-southeast-3.sagemaker.aws studio.ca-central-1.sagemaker.aws studio.eu-central-1.sagemaker.aws +studio.eu-central-2.sagemaker.aws studio.eu-north-1.sagemaker.aws studio.eu-south-1.sagemaker.aws studio.eu-south-2.sagemaker.aws @@ -11908,6 +11974,11 @@ studio.us-west-2.sagemaker.aws studio.cn-north-1.sagemaker.com.cn studio.cn-northwest-1.sagemaker.com.cn +// Amazon SageMaker with MLflow +// Submited by: AWS Security +// Reference: c19f92b3-a82a-452d-8189-831b572eea7e +*.experiments.sagemaker.aws + // Analytics on AWS // Submitted by AWS Security // Reference: 955f9f40-a495-4e73-ae85-67b77ac9cadd @@ -11924,8 +11995,8 @@ analytics-gateway.us-west-2.amazonaws.com // AWS Amplify // Submitted by AWS Security -// Reference: 5ecce854-c033-4fc4-a755-1a9916d9a9bb -*.amplifyapp.com +// Reference: c35bed18-6f4f-424f-9298-5756f2f7d72b +amplifyapp.com // AWS App Runner // Submitted by AWS Security @@ -12054,6 +12125,19 @@ awsglobalaccelerator.com // Reference: 83385945-225f-416e-9aa0-ad0632bfdcee *.private.repost.aws +// AWS Transfer Family web apps +// Submitted by AWS Security +// Reference: 67e9cfe6-ac57-49c7-b197-6652711c8e8d +transfer-webapp.ap-northeast-1.on.aws +transfer-webapp.ap-southeast-1.on.aws +transfer-webapp.ap-southeast-2.on.aws +transfer-webapp.eu-central-1.on.aws +transfer-webapp.eu-north-1.on.aws +transfer-webapp.eu-west-1.on.aws +transfer-webapp.us-east-1.on.aws +transfer-webapp.us-east-2.on.aws +transfer-webapp.us-west-2.on.aws + // eero // Submitted by Yue Kang // Reference: 264afe70-f62c-4c02-8ab9-b5281ed24461 @@ -12062,16 +12146,11 @@ eero-stage.online // concludes Amazon -// Amune : https://amune.org/ -// Submitted by Team Amune -t3l3p0rt.net -tele.amune.org - // Apigee : https://apigee.com/ // Submitted by Apigee Security Team apigee.io -// Apis Networks: https://apisnetworks.com +// Apis Networks : https://apisnetworks.com // Submitted by Matt Saladna panel.dev @@ -12088,6 +12167,11 @@ appspaceusercontent.com // Submitted by Alexander Hochbaum appudo.net +// Appwrite : https://appwrite.io +// Submitted by Steven Nguyen +appwrite.global +*.appwrite.run + // Aptible : https://www.aptible.com/ // Submitted by Thomas Orozco on-aptible.com @@ -12096,6 +12180,10 @@ on-aptible.com // Submitted by Aki Ueno f5.si +// ArvanCloud EdgeCompute +// Submitted by ArvanCloud CDN +arvanedge.ir + // ASEINet : https://www.aseinet.com/ // Submitted by Asei SEKIGUCHI user.aseinet.ne.jp @@ -12125,10 +12213,6 @@ cdn.prod.atlassian-dev.net // Submitted by Lukas Reschke translated.page -// Autocode : https://autocode.com -// Submitted by Jacob Lee -autocode.dev - // AVM : https://avm.de // Submitted by Andreas Weise myfritz.link @@ -12143,7 +12227,7 @@ onavstack.net *.awdev.ca *.advisor.ws -// AZ.pl sp. z.o.o: https://az.pl +// AZ.pl sp. z.o.o : https://az.pl // Submitted by Krzysztof Wolski ecommerce-shop.pl @@ -12151,25 +12235,10 @@ ecommerce-shop.pl // Submitted by Olivier Benz b-data.io -// backplane : https://www.backplane.io -// Submitted by Anthony Voutas -backplaneapp.io - // Balena : https://www.balena.io // Submitted by Petros Angelatos balena-devices.com -// University of Banja Luka : https://unibl.org -// Domains for Republic of Srpska administrative entity. -// Submitted by Marko Ivanovic -rs.ba - -// Banzai Cloud -// Submitted by Janos Matyas -*.banzai.cloud -app.banzaicloud.io -*.backyards.banzaicloud.io - // BASE, Inc. : https://binc.jp // Submitted by Yuya NAGASAWA base.ec @@ -12195,14 +12264,6 @@ beagleboard.io // Submitted by Hazel Cora pages.gay -// BetaInABox -// Submitted by Adrian -betainabox.com - -// University of Bielsko-Biala regional domain: http://dns.bielsko.pl/ -// Submitted by Marcin -bielsko.pl - // BinaryLane : http://www.binarylane.com // Submitted by Nathan O'Sullivan bnr.la @@ -12219,6 +12280,10 @@ blackbaudcdn.net // Submitted by Luke Bratch of.je +// Block, Inc. : https://block.xyz +// Submitted by Jonathan Boice +square.site + // Blue Bite, LLC : https://bluebite.com // Submitted by Joshua Weiss bluebite.io @@ -12246,6 +12311,9 @@ square7.net // Brave : https://brave.com // Submitted by Andrea Brancaleoni +brave.app +*.s.brave.app +brave.io *.s.brave.io // Brendly : https://brendly.rs @@ -12257,6 +12325,16 @@ shop.brendly.rs // Submitted by Dave Tharp browsersafetymark.io +// BRS Media : https://brsmedia.com/ +// Submitted by Gavin Brown +radio.am +radio.fm + +// Bubble : https://bubble.io/ +// Submitted by Merlin Zhao +cdn.bubble.io +bubbleapps.io + // Bytemark Hosting : https://www.bytemark.co.uk // Submitted by Paul Cammish uk0.bigv.io @@ -12267,10 +12345,6 @@ vm.bytemark.co.uk // Submitted by Antonio Lain cafjs.com -// callidomus : https://www.callidomus.com/ -// Submitted by Marcus Popp -mycd.eu - // Canva Pty Ltd : https://canva.com/ // Submitted by Joel Aquilina canva-apps.cn @@ -12286,102 +12360,99 @@ carrd.co crd.co ju.mp -// CentralNic : http://www.centralnic.com/names/domains +// CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk +// Submitted by Jamie Tanna +api.gov.uk + +// CDN77.com : http://www.cdn77.com +// Submitted by Jan Krpes +cdn77-storage.com +rsc.contentproxy9.cz +r.cdn77.net +cdn77-ssl.net +c.cdn77.org +rsc.cdn77.org +ssl.origin.cdn77-secure.org + +// CentralNic : https://teaminternet.com/ // Submitted by registry -ae.org +za.bz br.com cn.com -com.de -com.se de.com eu.com -gb.net -hu.net -jp.net jpn.com mex.com ru.com sa.com -se.net uk.com -uk.net us.com -za.bz za.com +com.de +gb.net +hu.net +jp.net +se.net +uk.net +ae.org +com.se -// No longer operated by CentralNic, these entries should be adopted and/or removed by current operators -// Submitted by Gavin Brown -ar.com -hu.com -kr.com -no.com -qc.com -uy.com - -// Africa.com Web Solutions Ltd : https://registry.africa.com -// Submitted by Gavin Brown -africa.com +// Cityhost LLC : https://cityhost.ua +// Submitted by Maksym Rivtin +cx.ua -// iDOT Services Limited : http://www.domain.gr.com -// Submitted by Gavin Brown -gr.com +// Civilized Discourse Construction Kit, Inc. : https://www.discourse.org/ +// Submitted by Rishabh Nambiar & Michael Brown +discourse.group +discourse.team -// Radix FZC : http://domains.in.net -// Submitted by Gavin Brown -in.net -web.in +// Clerk : https://www.clerk.dev +// Submitted by Colin Sidoti +clerk.app +clerkstage.app +*.lcl.dev +*.lclstage.dev +*.stg.dev +*.stgstage.dev -// US REGISTRY LLC : http://us.org -// Submitted by Gavin Brown -us.org - -// co.com Registry, LLC : https://registry.co.com -// Submitted by Gavin Brown -co.com - -// Roar Domains LLC : https://roar.basketball/ -// Submitted by Gavin Brown -aus.basketball -nz.basketball - -// BRS Media : https://brsmedia.com/ -// Submitted by Gavin Brown -radio.am -radio.fm - -// c.la : http://www.c.la/ -c.la - -// certmgr.org : https://certmgr.org -// Submitted by B. Blechschmidt -certmgr.org - -// Cityhost LLC : https://cityhost.ua -// Submitted by Maksym Rivtin -cx.ua - -// Civilized Discourse Construction Kit, Inc. : https://www.discourse.org/ -// Submitted by Rishabh Nambiar & Michael Brown -discourse.group -discourse.team - -// Clever Cloud : https://www.clever-cloud.com/ -// Submitted by Quentin Adam -cleverapps.io - -// Clerk : https://www.clerk.dev -// Submitted by Colin Sidoti -clerk.app -clerkstage.app -*.lcl.dev -*.lclstage.dev -*.stg.dev -*.stgstage.dev +// Clever Cloud : https://www.clever-cloud.com/ +// Submitted by Quentin Adam +cleverapps.cc +*.services.clever-cloud.com +cleverapps.io +cleverapps.tech // ClickRising : https://clickrising.com/ // Submitted by Umut Gumeli clickrising.net +// Cloud DNS Ltd : http://www.cloudns.net +// Submitted by Aleksander Hristov & Boyan Peychev +cloudns.asia +cloudns.be +cloud-ip.biz +cloudns.biz +cloudns.cc +cloudns.ch +cloudns.cl +cloudns.club +dnsabr.com +ip-ddns.com +cloudns.cx +cloudns.eu +cloudns.in +cloudns.info +ddns-ip.net +dns-cloud.net +dns-dynamic.net +cloudns.nz +cloudns.org +ip-dynamic.org +cloudns.ph +cloudns.pro +cloudns.pw +cloudns.us + // Cloud66 : https://www.cloud66.com/ // Submitted by Khash Sajadi c66.me @@ -12396,10 +12467,9 @@ cloudaccess.host freesite.host cloudaccess.net -// cloudControl : https://www.cloudcontrol.com/ -// Submitted by Tobias Wilken -cloudcontrolled.com -cloudcontrolapp.com +// Cloudbees, Inc. : https://www.cloudbees.com/ +// Submitted by Mohideen Shajith +cloudbeesusercontent.io // Cloudera, Inc. : https://www.cloudera.com/ // Submitted by Kedarnath Waikar @@ -12413,64 +12483,38 @@ trycloudflare.com pages.dev r2.dev workers.dev +cloudflare.net +cdn.cloudflare.net +cdn.cloudflareanycast.net +cdn.cloudflarecn.net +cdn.cloudflareglobal.net // cloudscale.ch AG : https://www.cloudscale.ch/ // Submitted by Gaudenz Steinlin cust.cloudscale.ch objects.lpg.cloudscale.ch objects.rma.cloudscale.ch +lpg.objectstorage.ch +rma.objectstorage.ch // Clovyr : https://clovyr.io // Submitted by Patrick Nielsen wnext.app -// co.ca : http://registry.co.ca/ -co.ca +// CNPY : https://cnpy.gdn +// Submitted by Angelo Gladding +cnpy.gdn // Co & Co : https://co-co.nl/ // Submitted by Govert Versluis *.otap.co -// i-registry s.r.o. : http://www.i-registry.cz/ -// Submitted by Martin Semrad -co.cz - -// CDN77.com : http://www.cdn77.com -// Submitted by Jan Krpes -cdn77-storage.com -rsc.contentproxy9.cz -cdn77-ssl.net -r.cdn77.net -ssl.origin.cdn77-secure.org -c.cdn77.org -rsc.cdn77.org - -// Cloud DNS Ltd : http://www.cloudns.net -// Submitted by Aleksander Hristov & Boyan Peychev -cloudns.asia -cloudns.be -cloudns.biz -cloudns.cc -cloudns.ch -cloudns.cl -cloudns.club -dnsabr.com -cloudns.cx -cloudns.eu -cloudns.in -cloudns.info -dns-cloud.net -dns-dynamic.net -cloudns.nz -cloudns.org -cloudns.ph -cloudns.pro -cloudns.pw -cloudns.us +// co.ca : http://registry.co.ca/ +co.ca -// CNPY : https://cnpy.gdn -// Submitted by Angelo Gladding -cnpy.gdn +// co.com Registry, LLC : https://registry.co.com +// Submitted by Gavin Brown +co.com // Codeberg e. V. : https://codeberg.org // Submitted by Moritz Marquardt @@ -12485,13 +12529,23 @@ preview.csb.app co.nl co.no +// Cognition AI, Inc. : https://cognition.ai +// Submitted by Philip Papurt +*.devinapps.com + // Combell.com : https://www.combell.com // Submitted by Thomas Wouters webhosting.be hosting-cluster.nl +// Contentful GmbH : https://www.contentful.com +// Submitted by Contentful Developer Experience Team +ctfcloud.net + // Convex : https://convex.dev/ // Submitted by James Cowling +convex.app +convex.cloud convex.site // Coordination Center for TLD RU and XN--P1AI : https://cctld.ru/en/domains/domens_ru/reserved/ @@ -12501,13 +12555,12 @@ edu.ru gov.ru int.ru mil.ru -test.ru // COSIMO GmbH : http://www.cosimo.de // Submitted by Rene Marticke dyn.cosidns.de -dynamisches-dns.de dnsupdater.de +dynamisches-dns.de internet-dns.de l-o-g-i-n.de dynamic-dns.info @@ -12515,9 +12568,9 @@ feste-ip.net knx-server.net static-access.net -// cPanel L.L.C. : https://www.cpanel.net/ -// Submitted by Dustin Scherer -*.cprapid.com +// Craft Docs Ltd : https://www.craft.do/ +// Submitted by Zsombor Fuszenecker +craft.me // Craynic, s.r.o. : http://www.craynic.com/ // Submitted by Ales Krajnik @@ -12531,54 +12584,15 @@ on.crisp.email // Submitted by Andrew Cady *.cryptonomic.net -// Cupcake : https://cupcake.io/ -// Submitted by Jonathan Rudenberg -cupcake.is - -// Curv UG : https://curv-labs.de/ -// Submitted by Marvin Wiesner -curv.dev - -// Customer OCI - Oracle Dyn https://cloud.oracle.com/home https://dyn.com/dns/ -// Submitted by Gregory Drake -// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label -*.customer-oci.com -*.oci.customer-oci.com -*.ocp.customer-oci.com -*.ocs.customer-oci.com - -// Cyclic Software : https://www.cyclic.sh -// Submitted by Kam Lasater -cyclic.app -cyclic.cloud -cyclic-app.com -cyclic.co.in +// cyber_Folks S.A. : https://cyberfolks.pl +// Submitted by Bartlomiej Kida +cfolks.pl // cyon GmbH : https://www.cyon.ch/ // Submitted by Dominic Luechinger cyon.link cyon.site -// Danger Science Group: https://dangerscience.com/ -// Submitted by Skylar MacDonald -fnwk.site -folionetwork.site -platform0.app - -// Daplie, Inc : https://daplie.com -// Submitted by AJ ONeal -daplie.me -localhost.daplie.me - -// Datto, Inc. : https://www.datto.com/ -// Submitted by Philipp Heckel -dattolocal.com -dattorelay.com -dattoweb.com -mydatto.com -dattolocal.net -mydatto.net - // Dansk.net : http://www.dansk.net/ // Submitted by Anani Voule biz.dk @@ -12591,11 +12605,6 @@ store.dk // Submitted by Abel Boldu / DAppNode Team dyndns.dappnode.io -// dapps.earth : https://dapps.earth/ -// Submitted by Daniil Burdakov -*.dapps.earth -*.bzz.dapps.earth - // Dark, Inc. : https://darklang.com // Submitted by Paul Biggar builtwithdark.com @@ -12610,39 +12619,78 @@ instance.datadetect.com // Submitted by Richard Li edgestack.me -// DDNS5 : https://ddns5.com -// Submitted by Cameron Elliott -ddns5.com +// Datto, Inc. : https://www.datto.com/ +// Submitted by Philipp Heckel +dattolocal.com +dattorelay.com +dattoweb.com +mydatto.com +dattolocal.net +mydatto.net + +// ddnss.de : https://www.ddnss.de/ +// Submitted by Robert Niedziela +ddnss.de +dyn.ddnss.de +dyndns.ddnss.de +dyn-ip24.de +dyndns1.de +home-webserver.de +dyn.home-webserver.de +myhome-server.de +ddnss.org // Debian : https://www.debian.org/ // Submitted by Peter Palfrader / Debian Sysadmin Team debian.net +// Definima : http://www.definima.com/ +// Submitted by Maxence Bitterli +definima.io +definima.net + // Deno Land Inc : https://deno.com/ // Submitted by Luca Casonato deno.dev deno-staging.dev +deno.net // deSEC : https://desec.io/ // Submitted by Peter Thomassen dedyn.io -// Deta: https://www.deta.sh/ +// Deta : https://www.deta.sh/ // Submitted by Aavash Shrestha deta.app deta.dev -// Diher Solutions : https://diher.solutions -// Submitted by Didi Hermawan -*.rss.my.id -*.diher.solutions +// dhosting.pl Sp. z o.o. : https://dhosting.pl/ +// Submitted by Michal Kokoszkiewicz +dfirma.pl +dkonto.pl +you2.pl + +// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/ +// Submitted by Braxton Huggins +ondigitalocean.app + +// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/ +// Submitted by Robin H. Johnson +*.digitaloceanspaces.com + +// DigitalPlat : https://www.digitalplat.org/ +// Submitted by Edward Hsing +qzz.io +us.kg +xx.kg +dpdns.org // Discord Inc : https://discord.com // Submitted by Sahn Lam discordsays.com discordsez.com -// DNS Africa Ltd https://dns.business +// DNS Africa Ltd : https://dns.business // Submitted by Calvin Browne jozi.biz @@ -12667,32 +12715,44 @@ shoparena.pl // Submitted by Andrew Farmer dreamhosters.com +// Dreamyoungs, Inc. : https://durumis.com +// Submitted by Infra Team +durumis.com + // Drobo : http://www.drobo.com/ // Submitted by Ricardo Padilha mydrobo.com -// Drud Holdings, LLC. : https://www.drud.com/ -// Submitted by Kevin Bridges -drud.io -drud.us - // DuckDNS : http://www.duckdns.org/ // Submitted by Richard Harper duckdns.org -// Bip : https://bip.sh -// Submitted by Joel Kennedy -bip.sh - -// bitbridge.net : Submitted by Craig Welch, abeliidev@gmail.com -bitbridge.net - // dy.fi : http://dy.fi/ // Submitted by Heikki Hannikainen dy.fi tunk.org // DynDNS.com : http://www.dyndns.com/services/dns/dyndns/ +dyndns.biz +for-better.biz +for-more.biz +for-some.biz +for-the.biz +selfip.biz +webhop.biz +ftpaccess.cc +game-server.cc +myphotos.cc +scrapping.cc +blogdns.com +cechire.com +dnsalias.com +dnsdojo.com +doesntexist.com +dontexist.com +doomdns.com +dyn-o-saur.com +dynalias.com dyndns-at-home.com dyndns-at-work.com dyndns-blog.com @@ -12707,64 +12767,14 @@ dyndns-server.com dyndns-web.com dyndns-wiki.com dyndns-work.com -dyndns.biz -dyndns.info -dyndns.org -dyndns.tv -at-band-camp.net -ath.cx -barrel-of-knowledge.info -barrell-of-knowledge.info -better-than.tv -blogdns.com -blogdns.net -blogdns.org -blogsite.org -boldlygoingnowhere.org -broke-it.net -buyshouses.net -cechire.com -dnsalias.com -dnsalias.net -dnsalias.org -dnsdojo.com -dnsdojo.net -dnsdojo.org -does-it.net -doesntexist.com -doesntexist.org -dontexist.com -dontexist.net -dontexist.org -doomdns.com -doomdns.org -dvrdns.org -dyn-o-saur.com -dynalias.com -dynalias.net -dynalias.org -dynathome.net -dyndns.ws -endofinternet.net -endofinternet.org -endoftheinternet.org est-a-la-maison.com est-a-la-masion.com est-le-patron.com est-mon-blogueur.com -for-better.biz -for-more.biz -for-our.info -for-some.biz -for-the.biz -forgot.her.name -forgot.his.name from-ak.com from-al.com from-ar.com -from-az.net from-ca.com -from-co.net from-ct.com from-dc.com from-de.com @@ -12777,10 +12787,8 @@ from-il.com from-in.com from-ks.com from-ky.com -from-la.net from-ma.com from-md.com -from-me.org from-mi.com from-mn.com from-mo.com @@ -12793,7 +12801,6 @@ from-nh.com from-nj.com from-nm.com from-nv.com -from-ny.net from-oh.com from-ok.com from-or.com @@ -12811,45 +12818,18 @@ from-wa.com from-wi.com from-wv.com from-wy.com -ftpaccess.cc -fuettertdasnetz.de -game-host.org -game-server.cc getmyip.com -gets-it.net -go.dyndns.org gotdns.com -gotdns.org -groks-the.info -groks-this.info -ham-radio-op.net -here-for-more.info hobby-site.com -hobby-site.org -home.dyndns.org -homedns.org -homeftp.net -homeftp.org -homeip.net homelinux.com -homelinux.net -homelinux.org homeunix.com -homeunix.net -homeunix.org iamallama.com -in-the-band.net is-a-anarchist.com is-a-blogger.com is-a-bookkeeper.com -is-a-bruinsfan.org is-a-bulls-fan.com -is-a-candidate.org is-a-caterer.com -is-a-celticsfan.org is-a-chef.com -is-a-chef.net -is-a-chef.org is-a-conservative.com is-a-cpa.com is-a-cubicle-slave.com @@ -12858,31 +12838,25 @@ is-a-designer.com is-a-doctor.com is-a-financialadvisor.com is-a-geek.com -is-a-geek.net -is-a-geek.org is-a-green.com is-a-guru.com is-a-hard-worker.com is-a-hunter.com -is-a-knight.org is-a-landscaper.com is-a-lawyer.com is-a-liberal.com is-a-libertarian.com -is-a-linux-user.org is-a-llama.com is-a-musician.com is-a-nascarfan.com is-a-nurse.com is-a-painter.com -is-a-patsfan.org is-a-personaltrainer.com is-a-photographer.com is-a-player.com is-a-republican.com is-a-rockstar.com is-a-socialist.com -is-a-soxfan.org is-a-student.com is-a-teacher.com is-a-techie.com @@ -12894,117 +12868,150 @@ is-an-anarchist.com is-an-artist.com is-an-engineer.com is-an-entertainer.com -is-by.us is-certified.com -is-found.org is-gone.com is-into-anime.com is-into-cars.com is-into-cartoons.com is-into-games.com is-leet.com -is-lost.org is-not-certified.com -is-saved.org is-slick.com is-uberleet.com -is-very-bad.org -is-very-evil.org -is-very-good.org -is-very-nice.org -is-very-sweet.org is-with-theband.com isa-geek.com -isa-geek.net -isa-geek.org isa-hockeynut.com issmarterthanyou.com +likes-pie.com +likescandy.com +neat-url.com +saves-the-whales.com +selfip.com +sells-for-less.com +sells-for-u.com +servebbs.com +simple-url.com +space-to-rent.com +teaches-yoga.com +writesthisblog.com +ath.cx +fuettertdasnetz.de isteingeek.de istmein.de -kicks-ass.net -kicks-ass.org -knowsitall.info -land-4-sale.us lebtimnetz.de leitungsen.de -likes-pie.com -likescandy.com +traeumtgerade.de +barrel-of-knowledge.info +barrell-of-knowledge.info +dyndns.info +for-our.info +groks-the.info +groks-this.info +here-for-more.info +knowsitall.info +selfip.info +webhop.info +forgot.her.name +forgot.his.name +at-band-camp.net +blogdns.net +broke-it.net +buyshouses.net +dnsalias.net +dnsdojo.net +does-it.net +dontexist.net +dynalias.net +dynathome.net +endofinternet.net +from-az.net +from-co.net +from-la.net +from-ny.net +gets-it.net +ham-radio-op.net +homeftp.net +homeip.net +homelinux.net +homeunix.net +in-the-band.net +is-a-chef.net +is-a-geek.net +isa-geek.net +kicks-ass.net +office-on-the.net +podzone.net +scrapper-site.net +selfip.net +sells-it.net +servebbs.net +serveftp.net +thruhere.net +webhop.net merseine.nu mine.nu +shacknet.nu +blogdns.org +blogsite.org +boldlygoingnowhere.org +dnsalias.org +dnsdojo.org +doesntexist.org +dontexist.org +doomdns.org +dvrdns.org +dynalias.org +dyndns.org +go.dyndns.org +home.dyndns.org +endofinternet.org +endoftheinternet.org +from-me.org +game-host.org +gotdns.org +hobby-site.org +homedns.org +homeftp.org +homelinux.org +homeunix.org +is-a-bruinsfan.org +is-a-candidate.org +is-a-celticsfan.org +is-a-chef.org +is-a-geek.org +is-a-knight.org +is-a-linux-user.org +is-a-patsfan.org +is-a-soxfan.org +is-found.org +is-lost.org +is-saved.org +is-very-bad.org +is-very-evil.org +is-very-good.org +is-very-nice.org +is-very-sweet.org +isa-geek.org +kicks-ass.org misconfused.org -mypets.ws -myphotos.cc -neat-url.com -office-on-the.net -on-the-web.tv -podzone.net podzone.org readmyblog.org -saves-the-whales.com -scrapper-site.net -scrapping.cc -selfip.biz -selfip.com -selfip.info -selfip.net selfip.org -sells-for-less.com -sells-for-u.com -sells-it.net sellsyourhome.org -servebbs.com -servebbs.net servebbs.org -serveftp.net serveftp.org servegame.org -shacknet.nu -simple-url.com -space-to-rent.com stuff-4-sale.org -stuff-4-sale.us -teaches-yoga.com -thruhere.net -traeumtgerade.de -webhop.biz -webhop.info -webhop.net webhop.org +better-than.tv +dyndns.tv +on-the-web.tv worse-than.tv -writesthisblog.com - -// ddnss.de : https://www.ddnss.de/ -// Submitted by Robert Niedziela -ddnss.de -dyn.ddnss.de -dyndns.ddnss.de -dyndns1.de -dyn-ip24.de -home-webserver.de -dyn.home-webserver.de -myhome-server.de -ddnss.org - -// Definima : http://www.definima.com/ -// Submitted by Maxence Bitterli -definima.net -definima.io - -// DigitalOcean App Platform : https://www.digitalocean.com/products/app-platform/ -// Submitted by Braxton Huggins -ondigitalocean.app - -// DigitalOcean Spaces : https://www.digitalocean.com/products/spaces/ -// Submitted by Robin H. Johnson -*.digitaloceanspaces.com - -// DigitalPlat : https://www.digitalplat.org/ -// Submitted by Edward Hsing -us.kg - -// dnstrace.pro : https://dnstrace.pro/ -// Submitted by Chris Partridge -bci.dnstrace.pro +is-by.us +land-4-sale.us +stuff-4-sale.us +dyndns.ws +mypets.ws // Dynu.com : https://www.dynu.com/ // Submitted by Sue Ye @@ -13024,7 +13031,6 @@ freeddns.org mywire.org webredirect.org myddns.rocks -blogsite.xyz // dynv6 : https://dynv6.com // Submitted by Dominik Menke @@ -13043,6 +13049,14 @@ easypanel.host // Submitted by *.ewp.live +// eDirect Corp. : https://hosting.url.com.tw/ +// Submitted by C.S. chang +twmail.cc +twmail.net +twmail.org +mymailer.com.tw +url.tw + // Electromagnetic Field : https://www.emfcamp.org // Submitted by at.emf.camp @@ -13060,26 +13074,22 @@ elementor.cool // Submitted by Emmanuel Raviart en-root.fr -// Enalean SAS: https://www.enalean.com -// Submitted by Thomas Cottier +// Enalean SAS : https://www.enalean.com +// Submitted by Enalean Security Team mytuleap.com tuleap-partners.com -// Encoretivity AB: https://encore.dev -// Submitted by André Eriksson +// Encoretivity AB : https://encore.cloud +// Submitted by André Eriksson encr.app encoreapi.com - -// ECG Robotics, Inc: https://ecgrobotics.org -// Submitted by -onred.one -staging.onred.one +lp.dev // encoway GmbH : https://www.encoway.de // Submitted by Marcel Daus eu.encoway.cloud -// EU.org https://eu.org/ +// EU.org : https://eu.org/ // Submitted by Pierre Beyssac eu.org al.eu.org @@ -13115,7 +13125,6 @@ kr.eu.org lt.eu.org lu.eu.org lv.eu.org -mc.eu.org me.eu.org mk.eu.org mt.eu.org @@ -13125,10 +13134,8 @@ ng.eu.org nl.eu.org no.eu.org nz.eu.org -paris.eu.org pl.eu.org pt.eu.org -q-a.eu.org ro.eu.org ru.eu.org se.eu.org @@ -13153,13 +13160,15 @@ us-2.evennode.com us-3.evennode.com us-4.evennode.com -// eDirect Corp. : https://hosting.url.com.tw/ -// Submitted by C.S. chang -twmail.cc -twmail.net -twmail.org -mymailer.com.tw -url.tw +// Evervault : https://evervault.com +// Submitted by Hannah Neary +relay.evervault.app +relay.evervault.dev + +// Expo : https://expo.dev/ +// Submitted by James Ide +expo.app +staging.expo.app // Fabrica Technologies, Inc. : https://www.fabrica.dev/ // Submitted by Eric Jiang @@ -13251,8 +13260,6 @@ u.channelsdvr.net edgecompute.app fastly-edge.com fastly-terrarium.com -fastlylb.net -map.fastlylb.net freetls.fastly.net map.fastly.net a.prod.fastly.net @@ -13260,6 +13267,8 @@ global.prod.fastly.net a.ssl.fastly.net b.ssl.fastly.net global.ssl.fastly.net +fastlylb.net +map.fastlylb.net // Fastmail : https://www.fastmail.com/ // Submitted by Marc Bradshaw @@ -13273,74 +13282,68 @@ myfast.host fastvps.site myfast.space +// FearWorks Media Ltd. : https://fearworksmedia.co.uk +// Submitted by Keith Fairley +conn.uk +copro.uk +hosp.uk + // Fedora : https://fedoraproject.org/ -// submitted by Patrick Uiterwijk +// Submitted by Patrick Uiterwijk fedorainfracloud.org fedorapeople.org cloud.fedoraproject.org app.os.fedoraproject.org app.os.stg.fedoraproject.org -// FearWorks Media Ltd. : https://fearworksmedia.co.uk -// submitted by Keith Fairley -conn.uk -copro.uk -hosp.uk - // Fermax : https://fermax.com/ -// submitted by Koen Van Isterdael +// Submitted by Koen Van Isterdael mydobiss.com // FH Muenster : https://www.fh-muenster.de // Submitted by Robin Naundorf fh-muenster.io +// Figma : https://www.figma.com +// Submitted by Nick Frost +figma.site +preview.site + // Filegear Inc. : https://www.filegear.com // Submitted by Jason Zhu filegear.me -filegear-au.me -filegear-de.me -filegear-gb.me -filegear-ie.me -filegear-jp.me -filegear-sg.me // Firebase, Inc. // Submitted by Chris Raynor firebaseapp.com -// Firewebkit : https://www.firewebkit.com -// Submitted by Majid Qureshi -fireweb.app - -// FLAP : https://www.flap.cloud -// Submitted by Louis Chemineau -flap.id - // FlashDrive : https://flashdrive.io // Submitted by Eric Chan -onflashdrive.app fldrv.com +// Fleek Labs Inc : https://fleek.xyz +// Submitted by Parsa Ghadimi +on-fleek.app + // FlutterFlow : https://flutterflow.io // Submitted by Anton Emelyanov flutterflow.app -// fly.io: https://fly.io +// fly.io : https://fly.io // Submitted by Kurt Mackey fly.dev -edgeapp.net shw.io - -// Flynn : https://flynn.io -// Submitted by Jonathan Rudenberg -flynnhosting.net +edgeapp.net // Forgerock : https://www.forgerock.com // Submitted by Roderick Parr forgeblocks.com id.forgerock.io +// FoundryLabs, Inc : https://e2b.dev/ +// Submitted by Jiri Sveceny +e2b.app + // Framer : https://www.framer.com // Submitted by Koen Rouwhorst framer.ai @@ -13351,17 +13354,9 @@ framer.photos framer.website framer.wiki -// Frusky MEDIA&PR : https://www.frusky.de -// Submitted by Victor Pupynin -*.frusky.de - -// RavPage : https://www.ravpage.co.il -// Submitted by Roni Horowitz -ravpage.co.il - -// Frederik Braun https://frederik-braun.com +// Frederik Braun : https://frederik-braun.com // Submitted by Frederik Braun -0e.vc +*.0e.vc // Freebox : http://www.freebox.fr // Submitted by Romain Fliedel @@ -13380,11 +13375,15 @@ freedesktop.org // Submitted by Cadence freemyip.com +// Frusky MEDIA&PR : https://www.frusky.de +// Submitted by Victor Pupynin +*.frusky.de + // FunkFeuer - Verein zur Förderung freier Netze : https://www.funkfeuer.at // Submitted by Daniel A. Maierhofer wien.funkfeuer.at -// Future Versatile Group. :https://www.fvg-on.net/ +// Future Versatile Group. : https://www.fvg-on.net/ // T.Kabu daemon.asia dix.asia @@ -13419,6 +13418,8 @@ aliases121.com // GDS : https://www.gov.uk/service-manual/technology/managing-domain-names // Submitted by Stephen Ford +campaign.gov.uk +service.gov.uk independent-commission.uk independent-inquest.uk independent-inquiry.uk @@ -13426,12 +13427,6 @@ independent-panel.uk independent-review.uk public-inquiry.uk royal-commission.uk -campaign.gov.uk -service.gov.uk - -// CDDO : https://www.gov.uk/guidance/get-an-api-domain-on-govuk -// Submitted by Jamie Tanna -api.gov.uk // Gehirn Inc. : https://www.gehirn.co.jp/ // Submitted by Kohei YOSHIDA @@ -13442,16 +13437,9 @@ usercontent.jp // Submitted by Tom Klein gentapps.com gentlentapis.com -lab.ms cdn-edges.net -// Getlocalcert: https://www.getlocalcert.net -// Submitted by Robert Alexander -localcert.net -localhostcert.net -corpnet.work - -// GignoSystemJapan: http://gsj.bz +// GignoSystemJapan : http://gsj.bz // Submitted by GignoSystemJapan gsj.bz @@ -13461,11 +13449,11 @@ githubusercontent.com githubpreview.dev github.io -// GitLab, Inc. +// GitLab, Inc. : https://about.gitlab.com/ // Submitted by Alex Hanselka gitlab.io -// Gitplac.si - https://gitplac.si +// Gitplac.si : https://gitplac.si // Submitted by Aljaž Starc gitapp.si gitpage.si @@ -13597,35 +13585,23 @@ heteml.net // Submitted by Rohan Durrant graphic.design -// GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/ -// Submitted by Tom Whitwell -cloudapps.digital -london.cloudapps.digital - -// GOV.UK Pay : https://www.payments.service.gov.uk/ -// Submitted by Richard Baker -pymnt.uk - -// GlobeHosting, Inc. -// Submitted by Zoltan Egresi -ro.im - // GoIP DNS Services : http://www.goip.de // Submitted by Christian Poulter goip.de // Google, Inc. -// Submitted by Eduardo Vela +// Submitted by Shannon McCabe +*.hosted.app *.run.app web.app *.0emm.com appspot.com *.r.appspot.com +blogspot.com codespot.com googleapis.com googlecode.com pagespeedmobilizer.com -publishproxy.com withgoogle.com withyoutube.com *.gateway.dev @@ -13633,114 +13609,40 @@ cloud.goog translate.goog *.usercontent.goog cloudfunctions.net -blogspot.ae -blogspot.al -blogspot.am -blogspot.ba -blogspot.be -blogspot.bg -blogspot.bj -blogspot.ca -blogspot.cf -blogspot.ch -blogspot.cl -blogspot.co.at -blogspot.co.id -blogspot.co.il -blogspot.co.ke -blogspot.co.nz -blogspot.co.uk -blogspot.co.za -blogspot.com -blogspot.com.ar -blogspot.com.au -blogspot.com.br -blogspot.com.by -blogspot.com.co -blogspot.com.cy -blogspot.com.ee -blogspot.com.eg -blogspot.com.es -blogspot.com.mt -blogspot.com.ng -blogspot.com.tr -blogspot.com.uy -blogspot.cv -blogspot.cz -blogspot.de -blogspot.dk -blogspot.fi -blogspot.fr -blogspot.gr -blogspot.hk -blogspot.hr -blogspot.hu -blogspot.ie -blogspot.in -blogspot.is -blogspot.it -blogspot.jp -blogspot.kr -blogspot.li -blogspot.lt -blogspot.lu -blogspot.md -blogspot.mk -blogspot.mr -blogspot.mx -blogspot.my -blogspot.nl -blogspot.no -blogspot.pe -blogspot.pt -blogspot.qa -blogspot.re -blogspot.ro -blogspot.rs -blogspot.ru -blogspot.se -blogspot.sg -blogspot.si -blogspot.sk -blogspot.sn -blogspot.td -blogspot.tw -blogspot.ug -blogspot.vn // Goupile : https://goupile.fr // Submitted by Niels Martignene goupile.fr -// Government of the Netherlands: https://www.government.nl +// GOV.UK Pay : https://www.payments.service.gov.uk/ +// Submitted by Richard Baker +pymnt.uk + +// GOV.UK Platform as a Service : https://www.cloud.service.gov.uk/ +// Submitted by Tom Whitwell +cloudapps.digital +london.cloudapps.digital + +// Government of the Netherlands : https://www.government.nl // Submitted by gov.nl +// Grafana Labs : https://grafana.com/ +// Submitted by Platform Engineering +grafana-dev.net + // GrayJay Web Solutions Inc. : https://grayjaysports.ca // Submitted by Matt Yamkowy grayjayleagues.com -// Group 53, LLC : https://www.group53.com -// Submitted by Tyler Todd -awsmppl.com - // GünstigBestellen : https://günstigbestellen.de // Submitted by Furkan Akkoc günstigbestellen.de günstigliefern.de -// Hakaran group: http://hakaran.cz -// Submitted by Arseniy Sokolov -fin.ci -free.hr -caa.li -ua.rs -conf.se - -// Handshake : https://handshake.org -// Submitted by Mike Damm -hs.zone -hs.run +// Häkkinen.fi : https://www.häkkinen.fi/ +// Submitted by Eero Häkkinen +häkkinen.fi // Hashbang : https://hashbang.sh hashbang.sh @@ -13750,9 +13652,23 @@ hashbang.sh hasura.app hasura-app.io -// Heilbronn University of Applied Sciences - Faculty Informatics (GitLab Pages): https://www.hs-heilbronn.de -// Submitted by Richard Zowalla +// Hatena Co., Ltd. : https://hatena.co.jp +// Submitted by Masato Nakamura +hatenablog.com +hatenadiary.com +hateblo.jp +hatenablog.jp +hatenadiary.jp +hatenadiary.org + +// Heilbronn University of Applied Sciences - Faculty Informatics (GitLab Pages) : https://www.hs-heilbronn.de +// Submitted by Richard Zowalla pages.it.hs-heilbronn.de +pages-research.it.hs-heilbronn.de + +// HeiyuSpace : https://lazycat.cloud +// Submitted by Xia Bin +heiyu.space // Helio Networks : https://heliohost.org // Submitted by Ben Frede @@ -13764,9 +13680,13 @@ heliohost.us hepforge.org // Heroku : https://www.heroku.com/ -// Submitted by Tom Maher +// Submitted by Shumon Huque herokuapp.com -herokussl.com + +// Heyflow : https://www.heyflow.com +// Submitted by Mirko Nitschke +heyflow.page +heyflow.site // Hibernating Rhinos // Submitted by Oren Eini @@ -13775,7 +13695,7 @@ ravendb.community development.run ravendb.run -// home.pl S.A.: https://home.pl +// home.pl S.A. : https://home.pl // Submitted by Krzysztof Wolski homesklep.pl @@ -13785,58 +13705,66 @@ homesklep.pl *.id.pub *.kin.pub -// Hong Kong Productivity Council: https://www.hkpc.org/ -// Submitted by SECaaS Team -secaas.hk - // Hoplix : https://www.hoplix.com // Submitted by Danilo De Franco hoplix.shop - // HOSTBIP REGISTRY : https://www.hostbip.com/ // Submitted by Atanunu Igbunuroghene orx.biz biz.gl +biz.ng +co.biz.ng +dl.biz.ng +go.biz.ng +lg.biz.ng +on.biz.ng col.ng firm.ng gen.ng ltd.ng ngo.ng -edu.scot -sch.so +plc.ng -// HostFly : https://www.ie.ua -// Submitted by Bohdan Dub -ie.ua - -// HostyHosting (hostyhosting.com) +// HostyHosting : https://hostyhosting.com hostyhosting.io -// Häkkinen.fi -// Submitted by Eero Häkkinen -häkkinen.fi +// Hugging Face : https://huggingface.co +// Submitted by Eliott Coyac +hf.space +static.hf.space + +// Hypernode B.V. : https://www.hypernode.com/ +// Submitted by Cipriano Groenendal +hypernode.io + +// I-O DATA DEVICE, INC. : http://www.iodata.com/ +// Submitted by Yuji Minagawa +iobb.net + +// i-registry s.r.o. : http://www.i-registry.cz/ +// Submitted by Martin Semrad +co.cz // Ici la Lune : http://www.icilalune.com/ // Submitted by Simon Morvan *.moonscale.io moonscale.net +// iDOT Services Limited : http://www.domain.gr.com +// Submitted by Gavin Brown +gr.com + // iki.fi // Submitted by Hannu Aronsson iki.fi -// iliad italia: https://www.iliad.it +// iliad italia : https://www.iliad.it // Submitted by Marios Makassikis ibxos.it iliadboxos.it -// Impertrix Solutions : -// Submitted by Zhixiang Zhao -impertrixcdn.com -impertrix.com - -// Incsub, LLC: https://incsub.com/ +// Incsub, LLC : https://incsub.com/ // Submitted by Aaron Edwards smushcdn.com wphostedmail.com @@ -13851,12 +13779,16 @@ in-berlin.de in-brb.de in-butter.de in-dsl.de -in-dsl.net -in-dsl.org in-vpn.de +in-dsl.net in-vpn.net +in-dsl.org in-vpn.org +// Inferno Communications : https://inferno.co.uk +// Submitted by Connor McFarlane +oninferno.net + // info.at : http://www.info.at/ biz.at info.at @@ -13899,26 +13831,54 @@ to.leg.br // Submitted by Wolfgang Schwarz pixolino.com -// Internet-Pro, LLP: https://netangels.ru/ +// Internet-Pro, LLP : https://netangels.ru/ // Submitted by Vasiliy Sheredeko na4u.ru +// Inventor Services : https://inventor.gg/ +// Submitted by Inventor Team +botdash.app +botdash.dev +botdash.gg +botdash.net +botda.sh +botdash.xyz + +// IONOS SE : https://www.ionos.com/ +// IONOS Group SE : https://www.ionos-group.com/ +// Submitted by Henrik Willert +apps-1and1.com +live-website.com +apps-1and1.net +websitebuilder.online +app-ionos.space + // iopsys software solutions AB : https://iopsys.eu/ // Submitted by Roman Azarenko iopsys.se +// IPFS Project : https://ipfs.tech/ +// Submitted by Interplanetary Shipyard +*.inbrowser.dev +*.dweb.link +*.inbrowser.link + // IPiFony Systems, Inc. : https://www.ipifony.com/ // Submitted by Matthew Hardeman ipifony.net -// is-a.dev : https://www.is-a.dev -// Submitted by William Harrison -is-a.dev - // ir.md : https://nic.ir.md // Submitted by Ali Soizi ir.md +// is-a-good.dev : https://is-a-good.dev +// Submitted by William Harrison +is-a-good.dev + +// is-a.dev : https://is-a.dev +// Submitted by William Harrison +is-a.dev + // IServ GmbH : https://iserv.de // Submitted by Mario Hoberg iservschule.de @@ -13928,15 +13888,10 @@ schulserver.de test-iserv.de iserv.dev -// I-O DATA DEVICE, INC. : http://www.iodata.com/ -// Submitted by Yuji Minagawa -iobb.net - // Jelastic, Inc. : https://jelastic.com/ // Submitted by Ihor Kolodyuk mel.cloudlets.com.au cloud.interhostsolutions.be -mycloud.by alp1.ae.flow.ch appengine.flow.ch es-1.axarnet.cloud @@ -13958,7 +13913,6 @@ us.reclaim.cloud ch.trendhosting.cloud de.trendhosting.cloud jele.club -amscompute.com dopaas.com paas.hosted-by-previder.com rag-cloud.hosteur.com @@ -13966,10 +13920,8 @@ rag-cloud-ch.hosteur.com jcloud.ik-server.com jcloud-ver-jpc.ik-server.com demo.jelastic.com -kilatiron.com paas.massivegrid.com jed.wafaicloud.com -lon.wafaicloud.com ryd.wafaicloud.com j.scaleforce.com.cy jelastic.dogado.eu @@ -13981,18 +13933,14 @@ mircloud.host paas.beebyte.io sekd1.beebyteapp.io jele.io -cloud-fr1.unispace.io jc.neen.it -cloud.jelastic.open.tim.it jcloud.kz -upaas.kazteleport.kz cloudjiffy.net fra1-de.cloudjiffy.net west1-us.cloudjiffy.net jls-sto1.elastx.net jls-sto2.elastx.net jls-sto3.elastx.net -faststacks.net fr-1.paas.massivegrid.net lon-1.paas.massivegrid.net lon-2.paas.massivegrid.net @@ -14002,11 +13950,9 @@ sg-1.paas.massivegrid.net jelastic.saveincloud.net nordeste-idc.saveincloud.net j.scaleforce.net -jelastic.tsukaeru.net sdscloud.pl unicloud.pl mircloud.ru -jelastic.regruhosting.ru enscaled.sg jele.site jelastic.team @@ -14029,13 +13975,13 @@ jotelulu.cloud // JouwWeb B.V. : https://www.jouwweb.nl // Submitted by Camilo Sperberg -jouwweb.site webadorsite.com +jouwweb.site // Joyent : https://www.joyent.com/ // Submitted by Brian Bennett -*.triton.zone *.cns.joyent.com +*.triton.zone // JS.ORG : http://dns.js.org // Submitted by Stefan Keim @@ -14046,14 +13992,15 @@ js.org kaas.gg khplay.nl -// Kakao : https://www.kakaocorp.com/ -// Submitted by JaeYoong Lee -ktistory.com - // Kapsi : https://kapsi.fi // Submitted by Tomi Juntunen kapsi.fi +// Katholieke Universiteit Leuven : https://www.kuleuven.be +// Submitted by Abuse KU Leuven +ezproxy.kuleuven.be +kuleuven.cloud + // Keyweb AG : https://www.keyweb.de // Submitted by Martin Dannehl keymachine.de @@ -14067,27 +14014,22 @@ uni5.net // Submitted by Roy Keene knightpoint.systems -// KoobinEvent, SL: https://www.koobin.com +// KoobinEvent, SL : https://www.koobin.com // Submitted by Iván Oliva koobin.events +// Krellian Ltd. : https://krellian.com +// Submitted by Ben Francis +webthings.io +krellian.net + // KUROKU LTD : https://kuroku.ltd/ // Submitted by DisposaBoy oya.to -// Katholieke Universiteit Leuven: https://www.kuleuven.be -// Submitted by Abuse KU Leuven -kuleuven.cloud -ezproxy.kuleuven.be - -// .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf -co.krd -edu.krd - -// Krellian Ltd. : https://krellian.com -// Submitted by Ben Francis -krellian.net -webthings.io +// Laravel Holdings, Inc. : https://laravel.com +// Submitted by André Valentin +laravel.cloud // LCube - Professional hosting e.K. : https://www.lcube-webhosting.de // Submitted by Lars Laehn @@ -14101,9 +14043,14 @@ leadpages.co lpages.co lpusercontent.com -// Lelux.fi : https://lelux.fi/ -// Submitted by Lelux Admin -lelux.site +// Liara : https://liara.ir +// Submitted by Amirhossein Badinloo +liara.run +iran.liara.run + +// libp2p project : https://libp2p.io +// Submitted by Interplanetary Shipyard +libp2p.direct // Libre IT Ltd : https://libre.nz // Submitted by Tomas Maggio @@ -14119,10 +14066,10 @@ co.network co.place co.technology -// linkyard ldt: https://www.linkyard.ch/ +// linkyard ldt : https://www.linkyard.ch/ // Submitted by Mario Siegenthaler -linkyard.cloud linkyard-cloud.ch +linkyard.cloud // Linode : https://linode.com // Submitted by @@ -14135,13 +14082,32 @@ ip.linodeusercontent.com // Submitted by Victor Velchev we.bs +// Listen53 : https://www.l53.net +// Submitted by Gerry Keh +filegear-sg.me +ggff.net + // Localcert : https://localcert.dev // Submitted by Lann Martin *.user.localcert.dev -// localzone.xyz -// Submitted by Kenny Niehage -localzone.xyz +// LocalCert : https://localcert.net +// Submitted by William Harrison +localcert.net + +// Localtonet : https://localtonet.com/ +// Submitted by Burak Isleyici +localtonet.com +*.localto.net + +// Lodz University of Technology LODMAN regional domains : https://www.man.lodz.pl/dns +// Submitted by Piotr Wilk +lodz.pl +pabianice.pl +plock.pl +sieradz.pl +skierniewice.pl +zgierz.pl // Log'in Line : https://www.loginline.com/ // Submitted by Rémi Mach @@ -14151,13 +14117,18 @@ loginline.io loginline.services loginline.site +// Lõhmus Family, The : https://lohmus.me/ +// Submitted by Heiki Lõhmus +lohmus.me + // Lokalized : https://lokalized.nl // Submitted by Noah Taheij servers.run -// Lõhmus Family, The -// Submitted by Heiki Lõhmus -lohmus.me +// Lovable : https://lovable.dev +// Submitted by Fabian Hedin +lovable.app +lovableproject.com // LubMAN UMCS Sp. z o.o : https://lubman.pl/ // Submitted by Ireneusz Maliszewski @@ -14177,18 +14148,19 @@ lugs.org.uk // Lukanet Ltd : https://lukanet.com // Submitted by Anton Avramov barsy.bg -barsy.co.uk -barsyonline.co.uk +barsy.club barsycenter.com barsyonline.com -barsy.club barsy.de +barsy.dev barsy.eu +barsy.gr barsy.in barsy.info barsy.io barsy.me barsy.menu +barsyonline.menu barsy.mobi barsy.net barsy.online @@ -14196,42 +14168,51 @@ barsy.org barsy.pro barsy.pub barsy.ro +barsy.rs barsy.shop +barsyonline.shop barsy.site +barsy.store barsy.support barsy.uk +barsy.co.uk +barsyonline.co.uk + +// Luyani Inc. : https://luyani.com/ +// Submitted by Umut Gumeli +luyani.app +luyani.net // Magento Commerce // Submitted by Damien Tournoud *.magentosite.cloud -// May First - People Link : https://mayfirst.org/ -// Submitted by Jamie McClelland -mayfirst.info -mayfirst.org - // Mail.Ru Group : https://hb.cldmail.ru // Submitted by Ilya Zaretskiy hb.cldmail.ru -// Mail Transfer Platform : https://www.neupeer.com -// Submitted by Li Hui -cn.vu +// MathWorks : https://www.mathworks.com/ +// Submitted by Emily Reed +matlab.cloud +modelscape.com +mwcloudnonprod.com +polyspace.com + +// May First - People Link : https://mayfirst.org/ +// Submitted by Jamie McClelland +mayfirst.info +mayfirst.org -// Maze Play: https://www.mazeplay.com +// Maze Play : https://www.mazeplay.com // Submitted by Adam Humpherys mazeplay.com -// mcpe.me : https://mcpe.me -// Submitted by Noa Heyl -mcpe.me - // McHost : https://mchost.ru // Submitted by Evgeniy Subbotin mcdir.me mcdir.ru -mcpre.ru vps.mcdir.ru +mcpre.ru // Mediatech : https://mediatech.by // Submitted by Evgeniy Kozhuhovskiy @@ -14242,6 +14223,10 @@ mediatech.dev // Submitted by Michael Olson hra.health +// MedusaJS, Inc : https://medusajs.com/ +// Submitted by Stevche Radevski +medusajs.app + // Memset hosting : https://www.memset.com // Submitted by Tom Whitwell miniserver.com @@ -14257,12 +14242,9 @@ atmeta.com apps.fbsbx.com // MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ -// Submitted by Zdeněk Šustr +// Submitted by Zdeněk Šustr and Radim Janča *.cloud.metacentrum.cz custom.metacentrum.cz - -// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/ -// Submitted by Radim Janča flt.cloud.muni.cz usr.cloud.muni.cz @@ -14280,10 +14262,9 @@ co.pl // Microsoft Azure : https://home.azure *.azurecontainer.io azure-api.net +azure-mobile.net azureedge.net azurefd.net -azurewebsites.net -azure-mobile.net azurestaticapps.net 1.azurestaticapps.net 2.azurestaticapps.net @@ -14297,31 +14278,36 @@ eastasia.azurestaticapps.net eastus2.azurestaticapps.net westeurope.azurestaticapps.net westus2.azurestaticapps.net +azurewebsites.net cloudapp.net trafficmanager.net blob.core.windows.net servicebus.windows.net +// MikroTik : https://mikrotik.com +// Submitted by MikroTik SysAdmin Team +routingthecloud.com +sn.mynetname.net +routingthecloud.net +routingthecloud.org + // minion.systems : http://minion.systems // Submitted by Robert Böttinger csx.cc -// Mintere : https://mintere.com/ -// Submitted by Ben Aubin -mintere.site - -// MobileEducation, LLC : https://joinforte.com -// Submitted by Grayson Martin -forte.id +// Mittwald CM Service GmbH & Co. KG : https://mittwald.de +// Submitted by Marco Rieger +mydbserver.com +webspaceconfig.de +mittwald.info +mittwaldserver.info +typo3server.info +project.space // MODX Systems LLC : https://modx.com // Submitted by Elizabeth Southwell modx.dev -// Mozilla Corporation : https://mozilla.com -// Submitted by Ben Francis -mozilla-iot.org - // Mozilla Foundation : https://mozilla.org/ // Submitted by glob bmoattachments.org @@ -14335,8 +14321,8 @@ pp.ru // Mythic Beasts : https://www.mythic-beasts.com // Submitted by Paul Cammish hostedpi.com -customer.mythic-beasts.com caracal.mythic-beasts.com +customer.mythic-beasts.com fentiger.mythic-beasts.com lynx.mythic-beasts.com ocelot.mythic-beasts.com @@ -14355,6 +14341,15 @@ ui.nabu.casa // Net at Work Gmbh : https://www.netatwork.de // Submitted by Jan Jaeschke cloud.nospamproxy.com +o365.cloud.nospamproxy.com + +// Net libre : https://www.netlib.re +// Submitted by Philippe PITTOLI +netlib.re + +// Netfy Domains : https://netfy.domains +// Submitted by Suranga Ranasinghe +netfy.app // Netlify : https://www.netlify.com // Submitted by Jessica Parsons @@ -14364,6 +14359,14 @@ netlify.app // Submitted by Trung Tran 4u.com +// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ +// Submitted by Jeff Wheelhouse +nfshost.com + +// NFT.Storage : https://nft.storage/ +// Submitted by Vasco Santos or +ipfs.nftstorage.link + // NGO.US Registry : https://nic.ngo.us // Submitted by Alstra Solutions Ltd. Networking Team ngo.us @@ -14385,7 +14388,7 @@ us.ngrok.io ngrok.pizza ngrok.pro -// Nicolaus Copernicus University in Torun - MSK TORMAN (https://www.man.torun.pl) +// Nicolaus Copernicus University in Torun - MSK TORMAN : https://www.man.torun.pl torun.pl // Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/ @@ -14393,13 +14396,97 @@ torun.pl nh-serv.co.uk nimsite.uk -// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/ -// Submitted by Jeff Wheelhouse -nfshost.com +// No-IP.com : https://noip.com/ +// Submitted by Deven Reza +mmafan.biz +myftp.biz +no-ip.biz +no-ip.ca +fantasyleague.cc +gotdns.ch +3utilities.com +blogsyte.com +ciscofreak.com +damnserver.com +ddnsking.com +ditchyourip.com +dnsiskinky.com +dynns.com +geekgalaxy.com +health-carereform.com +homesecuritymac.com +homesecuritypc.com +myactivedirectory.com +mysecuritycamera.com +myvnc.com +net-freaks.com +onthewifi.com +point2this.com +quicksytes.com +securitytactics.com +servebeer.com +servecounterstrike.com +serveexchange.com +serveftp.com +servegame.com +servehalflife.com +servehttp.com +servehumour.com +serveirc.com +servemp3.com +servep2p.com +servepics.com +servequake.com +servesarcasm.com +stufftoread.com +unusualperson.com +workisboring.com +dvrcam.info +ilovecollege.info +no-ip.info +brasilia.me +ddns.me +dnsfor.me +hopto.me +loginto.me +noip.me +webhop.me +bounceme.net +ddns.net +eating-organic.net +mydissent.net +myeffect.net +mymediapc.net +mypsx.net +mysecuritycamera.net +nhlfan.net +no-ip.net +pgafan.net +privatizehealthinsurance.net +redirectme.net +serveblog.net +serveminecraft.net +sytes.net +cable-modem.org +collegefan.org +couchpotatofries.org +hopto.org +mlbfan.org +myftp.org +mysecuritycamera.org +nflfan.org +no-ip.org +read-books.org +ufcfan.org +zapto.org +no-ip.co.uk +golffan.us +noip.us +pointto.us -// NFT.Storage : https://nft.storage/ -// Submitted by Vasco Santos or -ipfs.nftstorage.link +// NodeArt : https://nodeart.io +// Submitted by Konstantin Nosov +stage.nodeart.io // Noop : https://noop.app // Submitted by Nathaniel Schweinberg @@ -14418,18 +14505,16 @@ noop.app // Submitted by Laurent Pellegrino noticeable.news +// Notion Labs, Inc : https://www.notion.so/ +// Submitted by Jess Yao +notion.site + // Now-DNS : https://now-dns.com // Submitted by Steve Russell dnsking.ch mypi.co -n4t.co -001www.com -ddnslive.com myiphost.com forumz.info -16-b.it -32-b.it -64-b.it soundcast.me tcp4.me dnsup.net @@ -14440,130 +14525,32 @@ vpndns.net dynserv.org now-dns.org x443.pw -now-dns.top ntdll.top freeddns.us -crafting.xyz -zapto.xyz // nsupdate.info : https://www.nsupdate.info/ // Submitted by Thomas Waldmann nsupdate.info nerdpol.ovh -// No-IP.com : https://noip.com/ -// Submitted by Deven Reza -blogsyte.com -brasilia.me -cable-modem.org -ciscofreak.com -collegefan.org -couchpotatofries.org -damnserver.com -ddns.me -ditchyourip.com -dnsfor.me -dnsiskinky.com -dvrcam.info -dynns.com -eating-organic.net -fantasyleague.cc -geekgalaxy.com -golffan.us -health-carereform.com -homesecuritymac.com -homesecuritypc.com -hopto.me -ilovecollege.info -loginto.me -mlbfan.org -mmafan.biz -myactivedirectory.com -mydissent.net -myeffect.net -mymediapc.net -mypsx.net -mysecuritycamera.com -mysecuritycamera.net -mysecuritycamera.org -net-freaks.com -nflfan.org -nhlfan.net -no-ip.ca -no-ip.co.uk -no-ip.net -noip.us -onthewifi.com -pgafan.net -point2this.com -pointto.us -privatizehealthinsurance.net -quicksytes.com -read-books.org -securitytactics.com -serveexchange.com -servehumour.com -servep2p.com -servesarcasm.com -stufftoread.com -ufcfan.org -unusualperson.com -workisboring.com -3utilities.com -bounceme.net -ddns.net -ddnsking.com -gotdns.ch -hopto.org -myftp.biz -myftp.org -myvnc.com -no-ip.biz -no-ip.info -no-ip.org -noip.me -redirectme.net -servebeer.com -serveblog.net -servecounterstrike.com -serveftp.com -servegame.com -servehalflife.com -servehttp.com -serveirc.com -serveminecraft.net -servemp3.com -servepics.com -servequake.com -sytes.net -webhop.me -zapto.org - -// NodeArt : https://nodeart.io -// Submitted by Konstantin Nosov -stage.nodeart.io - -// Nucleos Inc. : https://nucleos.com -// Submitted by Piotr Zduniak -pcloud.host - -// NYC.mn : http://www.information.nyc.mn -// Submitted by Matthew Brown +// NYC.mn : https://dot.nyc.mn/ +// Submitted by NYC.mn Subdomain Service nyc.mn // O3O.Foundation : https://o3o.foundation/ -// Submitted by the prvcy.page Registry Team +// Submitted by the prvcy.page Registry Team prvcy.page +// Obl.ong : https://obl.ong +// Submitted by Reese Armstrong +obl.ong + // Observable, Inc. : https://observablehq.com // Submitted by Mike Bostock +observablehq.cloud static.observableusercontent.com -// Octopodal Solutions, LLC. : https://ulterius.io/ -// Submitted by Andrew Sampson -cya.gg - -// OMG.LOL : +// OMG.LOL : https://omg.lol // Submitted by Adam Newbold omg.lol @@ -14571,38 +14558,39 @@ omg.lol // Submitted by Cole Estep cloudycluster.net -// OmniWe Limited: https://omniwe.com +// OmniWe Limited : https://omniwe.com // Submitted by Vicary Archangel omniwe.site -// One.com: https://www.one.com/ +// One.com : https://www.one.com/ // Submitted by Jacob Bunk Nielsen -123hjemmeside.dk -123hjemmeside.no -123homepage.it -123kotisivu.fi -123minsida.se -123miweb.es -123paginaweb.pt -123siteweb.fr 123webseite.at -123webseite.de 123website.be +simplesite.com.br 123website.ch +simplesite.com +123webseite.de +123hjemmeside.dk +123miweb.es +123kotisivu.fi +123siteweb.fr +simplesite.gr +123homepage.it 123website.lu 123website.nl +123hjemmeside.no service.one -simplesite.com -simplesite.com.br -simplesite.gr simplesite.pl +123paginaweb.pt +123minsida.se -// One Fold Media : http://www.onefoldmedia.com/ -// Submitted by Eddie Jones -nid.io +// ONID : https://get.onid.ca +// Submitted by ONID Engineering Team +onid.ca // Open Domains : https://open-domains.net // Submitted by William Harrison +is-a-fullstack.dev is-cool.dev is-not-a.dev localplayer.dev @@ -14616,7 +14604,13 @@ opensocial.site // Submitted by Sven Marnach opencraft.hosting -// OpenResearch GmbH: https://openresearch.com/ +// OpenHost : https://registry.openhost.uk +// Submitted by OpenHost Registry Team +16-b.it +32-b.it +64-b.it + +// OpenResearch GmbH : https://openresearch.com/ // Submitted by Philipp Schmid orsites.com @@ -14624,17 +14618,28 @@ orsites.com // Submitted by Yngve Pettersen operaunite.com +// Oracle Dyn : https://cloud.oracle.com/home https://dyn.com/dns/ +// Submitted by Gregory Drake +// Note: This is intended to also include customer-oci.com due to wildcards implicitly including the current label +*.customer-oci.com +*.oci.customer-oci.com +*.ocp.customer-oci.com +*.ocs.customer-oci.com +*.oraclecloudapps.com +*.oraclegovcloudapps.com +*.oraclegovcloudapps.uk + // Orange : https://www.orange.com // Submitted by Alexandre Linte tech.orange // OsSav Technology Ltd. : https://ossav.com/ -// TLD Nic: http://nic.can.re - TLD Whois Server: whois.can.re // Submitted by OsSav Technology Ltd. +// https://nic.can.re can.re -// Oursky Limited : https://authgear.com/, https://skygear.io/ -// Submitted by Authgear Team , Skygear Developer +// Oursky Limited : https://authgear.com/ +// Submitted by Authgear Team & Skygear Developer authgear-staging.com authgearapps.com skygearapp.com @@ -14643,12 +14648,12 @@ skygearapp.com // Submitted by Duarte Santos outsystemscloud.com -// OVHcloud: https://ovhcloud.com +// OVHcloud : https://ovhcloud.com // Submitted by Vincent Cassé -*.webpaas.ovh.net *.hosting.ovh.net +*.webpaas.ovh.net -// OwnProvider GmbH: http://www.ownprovider.com +// OwnProvider GmbH : http://www.ownprovider.com // Submitted by Jan Moennich ownprovider.com own.pm @@ -14669,38 +14674,31 @@ oy.lc // Submitted by Derek Myers pgfog.com -// Pagefront : https://www.pagefronthq.com/ -// Submitted by Jason Kriss -pagefrontapp.com - // PageXL : https://pagexl.com // Submitted by Yann Guichard pagexl.com +// Pantheon Systems, Inc. : https://pantheon.io/ +// Submitted by Gary Dylina +gotpantheon.com +pantheonsite.io + // Paywhirl, Inc : https://paywhirl.com/ // Submitted by Daniel Netzer *.paywhirl.com -// pcarrier.ca Software Inc: https://pcarrier.ca/ +// pcarrier.ca Software Inc : https://pcarrier.ca/ // Submitted by Pierre Carrier *.xmit.co xmit.dev +madethis.site srv.us gh.srv.us gl.srv.us -// .pl domains (grandfathered) -art.pl -gliwice.pl -krakow.pl -poznan.pl -wroc.pl -zakopane.pl - -// Pantheon Systems, Inc. : https://pantheon.io/ -// Submitted by Gary Dylina -pantheonsite.io -gotpantheon.com +// PE Ulyanov Kirill Sergeevich : https://airy.host +// Submitted by Kirill Ulyanov +lk3.ru // Peplink | Pepwave : http://peplink.com/ // Submitted by Steve Leung @@ -14710,10 +14708,6 @@ mypep.link // Submitted by Kenneth Van Alstyne perspecta.cloud -// PE Ulyanov Kirill Sergeevich : https://airy.host -// Submitted by Kirill Ulyanov -lk3.ru - // Planet-Work : https://www.planet-work.com/ // Submitted by Frédéric VANNIÈRE on-web.fr @@ -14728,26 +14722,15 @@ us.platform.sh *.platformsh.site *.tst.site -// Platter: https://platter.dev +// Platter : https://platter.dev // Submitted by Patrick Flor -platter-app.com platter-app.dev platterp.us -// Plesk : https://www.plesk.com/ -// Submitted by Anton Akhtyamov -pdns.page -plesk.page -pleskns.com - // Pley AB : https://www.pley.com/ // Submitted by Henning Pohl pley.games -// Port53 : https://port53.io/ -// Submitted by Maximilian Schieder -dyn53.io - // Porter : https://porter.run/ // Submitted by Rudraksh MK onporter.run @@ -14763,8 +14746,8 @@ pstmn.io mock.pstmn.io httpbin.org -//prequalifyme.today : https://prequalifyme.today -//Submitted by DeepakTiwari deepak@ivylead.io +// prequalifyme.today : https://prequalifyme.today +// Submitted by DeepakTiwari deepak@ivylead.io prequalifyme.today // prgmr.com : https://prgmr.com/ @@ -14775,64 +14758,37 @@ xen.prgmr.com // Submitted by registry priv.at -// Protocol Labs : https://protocol.ai/ -// Submitted by Michael Burns -*.dweb.link +// PROJECT ELIV : https://eliv.kr/ +// Submitted by PROJECT ELIV Domain Team +c01.kr +eliv-dns.kr +mmv.kr +vki.kr + +// project-study : https://project-study.com +// Submitted by yumenewa +dev.project-study.com // Protonet GmbH : http://protonet.io // Submitted by Martin Meier protonet.io -// Publication Presse Communication SARL : https://ppcom.fr -// Submitted by Yaacov Akiba Slama -chirurgiens-dentistes-en-france.fr -byen.site - -// pubtls.org: https://www.pubtls.org -// Submitted by Kor Nielsen -pubtls.org - -// PythonAnywhere LLP: https://www.pythonanywhere.com -// Submitted by Giles Thomas -pythonanywhere.com -eu.pythonanywhere.com - -// QOTO, Org. -// Submitted by Jeffrey Phillips Freeman -qoto.io - -// Qualifio : https://qualifio.com/ -// Submitted by Xavier De Cock -qualifioapp.com - -// Quality Unit: https://qualityunit.com -// Submitted by Vasyl Tsalko -ladesk.com - -// QuickBackend: https://www.quickbackend.com -// Submitted by Dani Biro -qbuser.com - -// Rad Web Hosting: https://radwebhosting.com -// Submitted by Scott Claeys -cloudsite.builders -myradweb.net -servername.us - -// Redgate Software: https://red-gate.com -// Submitted by Andrew Farries -instances.spawn.cc - -// Redstar Consultants : https://www.redstarconsultants.com/ -// Submitted by Jons Slemmer -instantcloud.cn +// Publication Presse Communication SARL : https://ppcom.fr +// Submitted by Yaacov Akiba Slama +chirurgiens-dentistes-en-france.fr +byen.site -// Russian Academy of Sciences -// Submitted by Tech Support -ras.ru +// pubtls.org : https://www.pubtls.org +// Submitted by Kor Nielsen +pubtls.org + +// PythonAnywhere LLP : https://www.pythonanywhere.com +// Submitted by Giles Thomas +pythonanywhere.com +eu.pythonanywhere.com // QA2 -// Submitted by Daniel Dent (https://www.danieldent.com/) +// Submitted by Daniel Dent : https://www.danieldent.com/ qa2.com // QCX @@ -14849,6 +14805,22 @@ mycloudnas.com mynascloud.com myqnapcloud.com +// QOTO, Org. +// Submitted by Jeffrey Phillips Freeman +qoto.io + +// Qualifio : https://qualifio.com/ +// Submitted by Xavier De Cock +qualifioapp.com + +// Quality Unit : https://qualityunit.com +// Submitted by Vasyl Tsalko +ladesk.com + +// QuickBackend : https://www.quickbackend.com +// Submitted by Dani Biro +qbuser.com + // Quip : https://quip.com // Submitted by Patrick Linehan *.quipelements.com @@ -14863,28 +14835,49 @@ vaporcloud.io rackmaze.com rackmaze.net -// Rakuten Games, Inc : https://dev.viberplay.io -// Submitted by Joshua Zhang -g.vbrplsbx.io +// Rad Web Hosting : https://radwebhosting.com +// Submitted by Scott Claeys +cloudsite.builders +myradweb.net +servername.us + +// Radix FZC : http://domains.in.net +// Submitted by Gavin Brown +web.in +in.net + +// Raidboxes GmbH : https://raidboxes.de +// Submitted by Auke Tembrink +myrdbx.io +site.rb-hosting.io // Rancher Labs, Inc : https://rancher.com // Submitted by Vincent Fiduccia -*.on-k3s.io *.on-rancher.cloud +*.on-k3s.io *.on-rio.io +// RavPage : https://www.ravpage.co.il +// Submitted by Roni Horowitz +ravpage.co.il + // Read The Docs, Inc : https://www.readthedocs.org // Submitted by David Fischer +readthedocs-hosted.com readthedocs.io // Red Hat, Inc. OpenShift : https://openshift.redhat.com/ // Submitted by Tim Kramer rhcloud.com +// Redgate Software : https://red-gate.com +// Submitted by Andrew Farries +instances.spawn.cc + // Render : https://render.com // Submitted by Anurag Goel -app.render.com onrender.com +app.render.com // Repl.it : https://repl.it // Submitted by Lincoln Bergeson @@ -14932,11 +14925,6 @@ devices.resinstaging.io // Submitted by Chris Kastorff hzc.io -// Revitalised Limited : http://www.revitalised.co.uk -// Submitted by Jack Price -wellbeingzone.eu -wellbeingzone.co.uk - // Rico Developments Limited : https://adimo.co // Submitted by Colin Brown adimo.co.uk @@ -14945,6 +14933,16 @@ adimo.co.uk // Submitted by Micah Anderson itcouldbewor.se +// Roar Domains LLC : https://roar.basketball/ +// Submitted by Gavin Brown +aus.basketball +nz.basketball + +// ROBOT PAYMENT INC. : https://www.robotpayment.co.jp/ +// Submitted by Kentaro Takamori +subsc-pay.com +subsc-pay.net + // Rochester Institute of Technology : http://www.rit.edu/ // Submitted by Jennifer Herting git-pages.rit.edu @@ -14953,7 +14951,13 @@ git-pages.rit.edu // Submitted by Neil Hanlon rocky.page -// Rusnames Limited: http://rusnames.ru/ +// Ruhr University Bochum : https://www.ruhr-uni-bochum.de/ +// Submitted by Andreas Jobs +rub.de +ruhr-uni-bochum.de +io.noc.ruhr-uni-bochum.de + +// Rusnames Limited : http://rusnames.ru/ // Submitted by Sergey Zotov биз.рус ком.рус @@ -14966,6 +14970,14 @@ rocky.page спб.рус я.рус +// Russian Academy of Sciences +// Submitted by Tech Support +ras.ru + +// Sakura Frp : https://www.natfrp.com +// Submitted by Bobo Liu +nyat.app + // SAKURA Internet Inc. : https://www.sakura.ad.jp/ // Submitted by Internet Service Department 180r.com @@ -15016,12 +15028,20 @@ x0.to from.tv sakura.tv -// Salesforce.com, Inc. https://salesforce.com/ -// Submitted by Michael Biven and Aaron Romeo +// Salesforce.com, Inc. : https://salesforce.com/ +// Submitted by Salesforce Public Suffix List Team *.builder.code.com *.dev-builder.code.com *.stg-builder.code.com *.001.test.code-builder-stg.platform.salesforce.com +*.d.crm.dev +*.w.crm.dev +*.wa.crm.dev +*.wb.crm.dev +*.wc.crm.dev +*.wd.crm.dev +*.we.crm.dev +*.wf.crm.dev // Sandstorm Development Group, Inc. : https://sandcats.io/ // Submitted by Asheesh Laroia @@ -15029,8 +15049,8 @@ sandcats.io // SBE network solutions GmbH : https://www.sbe.de/ // Submitted by Norman Meilick -logoip.de logoip.com +logoip.de // Scaleway : https://www.scaleway.com/ // Submitted by Rémy Léone @@ -15067,7 +15087,7 @@ dedibox.fr // Submitted by Hanno Böck schokokeks.net -// Scottish Government: https://www.gov.scot +// Scottish Government : https://www.gov.scot // Submitted by Martin Ellis gov.scot service.gov.scot @@ -15101,17 +15121,17 @@ seidat.net // Submitted by Yuriy Romadin sellfy.store +// Sendmsg : https://www.sendmsg.co.il +// Submitted by Assaf Stern +minisite.ms + // Senseering GmbH : https://www.senseering.de // Submitted by Felix Mönckemeyer senseering.net -// Sendmsg: https://www.sendmsg.co.il -// Submitted by Assaf Stern -minisite.ms - -// Service Magnet : https://myservicemagnet.com -// Submitted by Dave Sanders -magnet.page +// Servebolt AS : https://servebolt.com +// Submitted by Daniel Kjeserud +servebolt.cloud // Service Online LLC : http://drs.ua/ // Submitted by Serhii Bulakh @@ -15119,19 +15139,14 @@ biz.ua co.ua pp.ua +// Shanghai Accounting Society : https://www.sasf.org.cn +// Submitted by Information Administration +as.sh.cn + // Sheezy.Art : https://sheezy.art // Submitted by Nyoom sheezy.games -// Shift Crypto AG : https://shiftcrypto.ch -// Submitted by alex -shiftcrypto.dev -shiftcrypto.io - -// ShiftEdit : https://shiftedit.net/ -// Submitted by Adam Jimenez -shiftedit.io - // Shopblocks : http://www.shopblocks.com/ // Submitted by Alex Bowers myshopblocks.com @@ -15146,6 +15161,7 @@ shopitsite.com // shopware AG : https://shopware.com // Submitted by Jens Küper +shopware.shop shopware.store // Siemens Mobility GmbH @@ -15164,13 +15180,11 @@ vipsinaapp.com // Submitted by Skylar Challand siteleaf.net -// Skyhat : http://www.skyhat.io -// Submitted by Shante Adam -bounty-full.com -alpha.bounty-full.com -beta.bounty-full.com +// Small Technology Foundation : https://small-tech.org +// Submitted by Aral Balkan +small-web.org -// Smallregistry by Promopixel SARL: https://www.smallregistry.net +// Smallregistry by Promopixel SARL : https://www.smallregistry.net // Former AFNIC's SLDs // Submitted by Jérôme Lipowicz aeroport.fr @@ -15184,10 +15198,6 @@ pharmacien.fr port.fr veterinaire.fr -// Small Technology Foundation : https://small-tech.org -// Submitted by Aral Balkan -small-web.org - // Smoove.io : https://www.smoove.io/ // Submitted by Dan Kozak vp4.me @@ -15203,65 +15213,28 @@ streamlitapp.com // Submitted by Ian Streeter try-snowplow.com -// SourceHut : https://sourcehut.org -// Submitted by Drew DeVault -srht.site - -// StackBlitz : https://stackblitz.com -// Submitted by Dominic Elm -w-corp-staticblitz.com -w-credentialless-staticblitz.com -w-staticblitz.com - -// Stackhero : https://www.stackhero.io -// Submitted by Adrien Gillon -stackhero-network.com - -// STACKIT : https://www.stackit.de/en/ -// Submitted by STACKIT-DNS Team (Simon Stier) -runs.onstackit.cloud -stackit.gg -stackit.rocks -stackit.run -stackit.zone - -// Staclar : https://staclar.com -// Submitted by Q Misell -musician.io -// Submitted by Matthias Merkel -novecore.site - -// staticland : https://static.land -// Submitted by Seth Vincent -static.land -dev.static.land -sites.static.land - -// Storebase : https://www.storebase.io -// Submitted by Tony Schirmer -storebase.store - -// Strategic System Consulting (eApps Hosting): https://www.eapps.com/ -// Submitted by Alex Oancea -vps-host.net -atl.jelastic.vps-host.net -njs.jelastic.vps-host.net -ric.jelastic.vps-host.net +// Software Consulting Michal Zalewski : https://www.mafelo.com +// Submitted by Michal Zalewski +mafelo.net // Sony Interactive Entertainment LLC : https://sie.com/ // Submitted by David Coles playstation-cloud.com +// SourceHut : https://sourcehut.org +// Submitted by Drew DeVault +srht.site + // SourceLair PC : https://www.sourcelair.com // Submitted by Antonis Kalipetis apps.lair.io *.stolos.io -// SpaceKit : https://www.spacekit.io/ -// Submitted by Reza Akhavan -spacekit.io +// SparrowHost : https://sparrowhost.in/ +// Submitted by Anant Pandey +ind.mom -// SpeedPartner GmbH: https://www.speedpartner.de/ +// SpeedPartner GmbH : https://www.speedpartner.de/ // Submitted by Stefan Neufeind customer.speedpartner.de @@ -15287,6 +15260,30 @@ myspreadshop.pl myspreadshop.se myspreadshop.co.uk +// StackBlitz : https://stackblitz.com +// Submitted by Dominic Elm +w-corp-staticblitz.com +w-credentialless-staticblitz.com +w-staticblitz.com + +// Stackhero : https://www.stackhero.io +// Submitted by Adrien Gillon +stackhero-network.com + +// STACKIT GmbH & Co. KG : https://www.stackit.de/en/ +// Submitted by STACKIT-DNS Team (Simon Stier) +runs.onstackit.cloud +stackit.gg +stackit.rocks +stackit.run +stackit.zone + +// Staclar : https://staclar.com +// Submitted by Q Misell +// Submitted by Matthias Merkel +musician.io +novecore.site + // Standard Library : https://stdlib.com // Submitted by Jacob Lee api.stdlib.com @@ -15304,6 +15301,15 @@ researched.cx tests.cx surveys.so +// Storacha Network : https://storacha.network +// Submitted by Alan Shaw +ipfs.storacha.link +ipfs.w3s.link + +// Storebase : https://www.storebase.io +// Submitted by Tony Schirmer +storebase.store + // Storipress : https://storipress.com // Submitted by Benno Liu storipress.app @@ -15312,22 +15318,34 @@ storipress.app // Submitted by Philip Hutchins storj.farm +// Strapi : https://strapi.io/ +// Submitted by Florent Baldino +strapiapp.com +media.strapiapp.com + +// Strategic System Consulting (eApps Hosting) : https://www.eapps.com/ +// Submitted by Alex Oancea +vps-host.net +atl.jelastic.vps-host.net +njs.jelastic.vps-host.net +ric.jelastic.vps-host.net + // Streak : https://streak.com // Submitted by Blake Kadatz streak-link.com streaklinks.com streakusercontent.com -// Studenten Net Twente : http://www.snt.utwente.nl/ -// Submitted by Silke Hofstra -utwente.io - // Student-Run Computing Facility : https://www.srcf.net/ // Submitted by Edwin Balani soc.srcf.net user.srcf.net -// Sub 6 Limited: http://www.sub6.com +// Studenten Net Twente : http://www.snt.utwente.nl/ +// Submitted by Silke Hofstra +utwente.io + +// Sub 6 Limited : http://www.sub6.com // Submitted by Dan Miller temp-dns.com @@ -15336,12 +15354,6 @@ temp-dns.com supabase.co supabase.in supabase.net -su.paba.se - -// Symfony, SAS : https://symfony.com/ -// Submitted by Fabien Potencier -*.s5y.io -*.sensiosite.cloud // Syncloud : https://syncloud.org // Submitted by Boris Rybalkin @@ -15363,33 +15375,41 @@ dsmynas.net familyds.net dsmynas.org familyds.org -vpnplus.to direct.quickconnect.to +vpnplus.to // Tabit Technologies Ltd. : https://tabit.cloud/ // Submitted by Oren Agiv -tabitorder.co.il -mytabit.co.il mytabit.com +mytabit.co.il +tabitorder.co.il // TAIFUN Software AG : http://taifun-software.de // Submitted by Bjoern Henke taifun-dns.de // Tailscale Inc. : https://www.tailscale.com -// Submitted by David Anderson -beta.tailscale.net +// Submitted by David Anderson ts.net *.c.ts.net -// TASK geographical domains (www.task.gda.pl/uslugi/dns) +// TASK geographical domains : https://task.gda.pl/en/services/for-entrepreneurs/ gda.pl gdansk.pl gdynia.pl med.pl sopot.pl -// team.blue https://team.blue +// Tave Creative Corp : https://tave.com/ +// Submitted by Adrian Ziemkowski +taveusercontent.com + +// tawk.to, Inc : https://www.tawk.to +// Submitted by tawk.to developer team +p.tawk.email +p.tawkto.email + +// team.blue : https://team.blue // Submitted by Cedric Dubois site.tb-hosting.com @@ -15411,11 +15431,11 @@ telebit.io reservd.com thingdustdata.com cust.dev.thingdust.io +reservd.dev.thingdust.io cust.disrec.thingdust.io +reservd.disrec.thingdust.io cust.prod.thingdust.io cust.testing.thingdust.io -reservd.dev.thingdust.io -reservd.disrec.thingdust.io reservd.testing.thingdust.io // ticket i/O GmbH : https://ticket.io @@ -15429,13 +15449,12 @@ azimuth.network tlon.network // Tor Project, Inc. : https://torproject.org -// Submitted by Antoine Beaupré torproject.net pages.torproject.net // TownNews.com : http://www.townnews.com // Submitted by Dustin Ward -bloxcms.com townnews-staging.com // TrafficPlex GmbH : https://www.trafficplex.de/ @@ -15461,14 +15480,11 @@ webspace.rocks lima.zone // TransIP : https://www.transip.nl -// Submitted by Rory Breuk +// Submitted by Rory Breuk and Cedric Dubois *.transurl.be *.transurl.eu -*.transurl.nl - -// TransIP: https://www.transip.nl -// Submitted by Cedric Dubois site.transip.me +*.transurl.nl // TuxFamily : http://tuxfamily.org // Submitted by TuxFamily administrators @@ -15477,8 +15493,6 @@ tuxfamily.org // TwoDNS : https://www.twodns.de/ // Submitted by TwoDNS-Support dd-dns.de -diskstation.eu -diskstation.org dray-dns.de draydns.de dyn-vpn.de @@ -15489,26 +15503,28 @@ my-wan.de syno-ds.de synology-diskstation.de synology-ds.de +diskstation.eu +diskstation.org // Typedream : https://typedream.com // Submitted by Putri Karunia typedream.app // Typeform : https://www.typeform.com -// Submitted by Sergi Ferriz +// Submitted by Typeform pro.typeform.com // Uberspace : https://uberspace.de // Submitted by Moritz Werner -uber.space *.uberspace.de +uber.space // UDR Limited : http://www.udr.hk.com // Submitted by registry hk.com -hk.org -ltd.hk inc.hk +ltd.hk +hk.org // UK Intis Telecom LTD : https://it.com // Submitted by ITComdomains @@ -15518,6 +15534,15 @@ it.com // Submitted by Simon Højberg unison-services.cloud +// United Gameserver GmbH : https://united-gameserver.de +// Submitted by Stefan Schwarz +virtual-user.de +virtualuser.de + +// United States Writing Corporation : https://uswriting.co +// Submitted by Andrew Sampson +obj.ag + // UNIVERSAL DOMAIN REGISTRY : https://www.udr.org.yt/ // see also: whois -h whois.udr.org.yt help // Submitted by Atanunu Igbunuroghene @@ -15527,50 +15552,57 @@ biz.wf sch.wf org.yt -// United Gameserver GmbH : https://united-gameserver.de -// Submitted by Stefan Schwarz -virtualuser.de -virtual-user.de +// University of Banja Luka : https://unibl.org +// Domains for Republic of Srpska administrative entity. +// Submitted by Marko Ivanovic +rs.ba -// Upli : https://upli.io -// Submitted by Lenny Bakkalian -upli.io +// University of Bielsko-Biala regional domain : http://dns.bielsko.pl/ +// Submitted by Marcin +bielsko.pl // urown.net : https://urown.net // Submitted by Hostmaster urown.cloud dnsupdate.info -// .US -// Submitted by Ed Moore -lib.de.us +// US REGISTRY LLC : http://us.org +// Submitted by Gavin Brown +us.org -// VeryPositive SIA : http://very.lv -// Submitted by Danko Aleksejevs -2038.io +// V.UA Domain Administrator : https://domain.v.ua/ +// Submitted by Serhii Rostilo +v.ua + +// Val Town, Inc : https://val.town/ +// Submitted by Tom MacWright +val.run +web.val.run // Vercel, Inc : https://vercel.com/ -// Submitted by Connor Davis +// Submitted by Max Leiter vercel.app +v0.build vercel.dev +vusercontent.net now.sh -// Viprinet Europe GmbH : http://www.viprinet.com -// Submitted by Simon Kissel -router.management +// VeryPositive SIA : http://very.lv +// Submitted by Danko Aleksejevs +2038.io // Virtual-Info : https://www.virtual-info.info/ // Submitted by Adnan RIHAN v-info.info -// Voorloper.com: https://voorloper.com +// Viva Republica, Inc. : https://toss.im/ +// Submitted by Deus Team +deus-canvas.com + +// Voorloper.com : https://voorloper.com // Submitted by Nathan van Bakel voorloper.cloud -// V.UA Domain Administrator : https://domain.v.ua/ -// Submitted by Serhii Rostilo -v.ua - // Vultr Objects : https://www.vultr.com/products/object-storage/ // Submitted by Niels Maumenee *.vultrobjects.com @@ -15584,46 +15616,72 @@ wafflecell.com webflow.io webflowtest.io -// WebHare bv: https://www.webhare.com/ +// WebHare bv : https://www.webhare.com/ // Submitted by Arnold Hendriks *.webhare.dev -// WebHotelier Technologies Ltd: https://www.webhotelier.net/ +// WebHotelier Technologies Ltd : https://www.webhotelier.net/ // Submitted by Apostolos Tsakpinis -reserve-online.net -reserve-online.com bookonline.app hotelwithflight.com +reserve-online.com +reserve-online.net + +// WebPros International, LLC : https://webpros.com/ +// Submitted by Nicolas Rochelemagne +cprapid.com +pleskns.com +wp2.host +pdns.page +plesk.page +cpanel.site +wpsquared.site -// WebWaddle Ltd: https://webwaddle.com/ +// WebWaddle Ltd : https://webwaddle.com/ // Submitted by Merlin Glander *.wadl.top -// WeDeploy by Liferay, Inc. : https://www.wedeploy.com -// Submitted by Henrique Vicente -wedeploy.io -wedeploy.me -wedeploy.sh - // Western Digital Technologies, Inc : https://www.wdc.com // Submitted by Jung Jin remotewd.com +// Whatbox Inc. : https://whatbox.ca/ +// Submitted by Anthony Ryan +box.ca + // WIARD Enterprises : https://wiardweb.com // Submitted by Kidd Hustle pages.wiardweb.com // Wikimedia Labs : https://wikitech.wikimedia.org // Submitted by Arturo Borrero Gonzalez -wmflabs.org toolforge.org wmcloud.org +wmflabs.org + +// William Harrison : https://wharrison.com.au +// Submitted by William Harrison +wdh.app +hrsn.dev + +// Windsurf : https://windsurf.com +// Submitted by Douglas Chen +windsurf.app +windsurf.build // WISP : https://wisp.gg // Submitted by Stepan Fedotov panel.gg daemon.panel.gg +// Wix.com, Inc. : https://www.wix.com +// Submitted by Shahar Talmi / Alon Kochba +wixsite.com +wixstudio.com +editorx.io +wixstudio.io +wix.run + // Wizard Zines : https://wizardzines.com // Submitted by Julia Evans messwithdns.com @@ -15649,14 +15707,7 @@ weeklylottery.org.uk wpenginepowered.com js.wpenginepowered.com -// Wix.com, Inc. : https://www.wix.com -// Submitted by Shahar Talmi -wixsite.com -editorx.io -wixstudio.io -wix.run - -// XenonCloud GbR: https://xenoncloud.net +// XenonCloud GbR : https://xenoncloud.net // Submitted by Julian Uphoff half.host @@ -15672,7 +15723,7 @@ cistron.nl demon.nl xs4all.space -// Yandex.Cloud LLC: https://cloud.yandex.com +// Yandex.Cloud LLC : https://cloud.yandex.com // Submitted by Alexander Lodin yandexcloud.net storage.yandexcloud.net @@ -15686,16 +15737,6 @@ official.academy // Submitted by Stefano Rivera yolasite.com -// Yombo : https://yombo.net -// Submitted by Mitch Schwenk -ybo.faith -yombo.me -homelink.one -ybo.party -ybo.review -ybo.science -ybo.trade - // Yunohost : https://yunohost.org // Submitted by Valentin Grimaud ynh.fr @@ -15711,6 +15752,14 @@ za.org // Submitted by Julian Alker zap.cloud +// Zeabur : https://zeabur.com/ +// Submitted by Zeabur Team +zeabur.app + +// Zerops : https://zerops.io/ +// Submitted by Zerops Team +*.zerops.app + // Zine EOOD : https://zine.bg/ // Submitted by Martin Angelov bss.design @@ -15721,4 +15770,8 @@ basicserver.io virtualserver.io enterprisecloud.nu +// Zone.ID: https://zone.id +// Submitted by Gx1.org +zone.id + // ===END PRIVATE DOMAINS=== diff --git a/src/java.base/share/legal/public_suffix.md b/src/java.base/share/legal/public_suffix.md index 02481558af6..26ab8a69a23 100644 --- a/src/java.base/share/legal/public_suffix.md +++ b/src/java.base/share/legal/public_suffix.md @@ -11,7 +11,7 @@ If you do not wish to use the Public Suffix List, you may remove the The Source Code of this file is available under the Mozilla Public License, v. 2.0 and is located at -https://raw.githubusercontent.com/publicsuffix/list/1cbd6e71a9b83620b1d0b11e49d3d9ff48c27e22/public_suffix_list.dat. +https://raw.githubusercontent.com/publicsuffix/list/823beb1425def931c8b0b170a6bc33b424c3f9b0/public_suffix_list.dat. If a copy of the MPL was not distributed with this file, you can obtain one at https://mozilla.org/MPL/2.0/. diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 987dbf64159..bb010e6e1c7 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2701,7 +2701,12 @@ Java HotSpot VM. > `-XX:ParallelGCThreads=2` `-XX:+ParallelRefProcEnabled` -: Enables parallel reference processing. By default, this option is disabled. +: Enables parallel reference processing. By default, collectors employing multiple + threads perform parallel reference processing if the number of parallel threads + to use is larger than one. + The option is available only when the throughput or G1 garbage collector is used + (`-XX:+UseParallelGC` or `-XX:+UseG1GC`). Other collectors employing multiple + threads always perform reference processing in parallel. `-XX:+PrintAdaptiveSizePolicy` : Enables printing of information about adaptive-generation sizing. By @@ -3995,8 +4000,8 @@ partially or completely disabled, leading to lower performance. can be used, but the "archived module graph" feature will be disabled. This can lead to increased start-up time. -To diagnose problems with the above options, you can add `-Xlog:cds` to the application's VM -arguments. For example, if `--add-modules jdk.jconcole` was specified during archive creation +To diagnose problems with the AOT options, you can add `-Xlog:aot` to the application's VM +arguments. For example, if `--add-modules jdk.jconsole` was specified during archive creation and `--add-modules jdk.incubator.vector` is specified during runtime, the following messages will be logged: @@ -4045,31 +4050,66 @@ The deployment of the AOT cache is divided into three phases: The AOT cache can be used with the following command-line options: -`-XX:AOTCache:=`*cachefile* +`-XX:AOTCache=`*cachefile* : Specifies the location of the AOT cache. The standard extension for *cachefile* is `.aot`. - If `-XX:AOTCache` is specified but `-XX:AOTMode` is not specified, - then `AOTMode` will be given the value of `auto`. + This option cannot be used together with `-XX:AOTCacheOutput`. -`-XX:AOTConfiguration:=`*configfile* + This option is compatible with `AOTMode` settings of `on`, `create`, or `auto` (the default). + The *cachefile* is read in AOT modes `on` and `auto`, and is ignored by mode `off`. + The *cachefile* is written by AOT mode `create`. In that case, this option is + equivalent to `-XX:AOTCacheOutput=`*cachefile*. + +`-XX:AOTCacheOutput=`*cachefile* +: Specifies the location of the AOT cache to write. The standard extension for *cachefile* is `.aot`. + This option cannot be used together with `-XX:AOTCache`. + + This option is compatible with `AOTMode` settings of `record`, `create`, or `auto` (the default). + +`-XX:AOTConfiguration=`*configfile* : Specifies the AOT Configuration file for the JVM to write to or read from. - This option can be used only with `-XX:AOTMode=record` and `-XX:AOTMode=create`. The standard extension for *configfile* is `.aotconfig`. -`-XX:+AOTMode:=`*mode* -: *mode* must be one of the following: `off`, `record`, `create`, `auto`, or `on`. + This option is compatible with `AOTMode` settings of `record`, `create`, or `auto` (the default). + The *configfile* is read by AOT mode `create`, and written by the other applicable modes. + If the AOT mode is `auto`, then `AOTCacheOutput` must also be present. -- `off`: no AOT cache is used. +`-XX:AOTMode=`*mode* +: Specifies the AOT Mode for this run. + *mode* must be one of the following: `auto`, `off`, `record`, `create`, or `on`. -- `record`: Execute the application in the Training phase. - `-XX:AOTConfiguration=`*configfile* must be specified. The JVM gathers - statistical data and stores them into *configfile*. +- `auto`: This AOT mode is the default, and takes effect if no `-XX:AOTMode` option + is present. It automatically sets the AOT mode to `record`, `on`, or `off`, as follows: + - If `-XX:AOTCacheOutput=`*cachefile* is specified, the AOT mode is changed to `record` + (a training run, with a subsequent `create` operation). + - Otherwise, if an AOT cache can be loaded, the AOT mode is changed to `on` (a production run). + - Otherwise, the AOT mode is changed to `off` (a production run with no AOT cache). -- `create`: Perform the Assembly phase. `-XX:AOTConfiguration=`*configfile* - and `-XX:AOTCache=`*cachefile* must be specified. The JVM reads the statistical - data from *configfile* and writes the optimization artifacts into *cachefile*. +- `off`: No AOT cache is used. + Other AOT command line options are ignored. + +- `record`: Execute the application in the training phase. + At least one of `-XX:AOTConfiguration=`*configfile* and/or + `-XX:AOTCacheOutput=`*cachefile* must be specified. + If `-XX:AOTConfiguration=`*configfile* is specified, the JVM gathers + statistical data and stores them into *configfile*. + If `-XX:AOTConfiguration=`*configfile* is not specified, the JVM uses + a temporary file name, which may be the string `AOTCacheOutput+".config"`, + or else a fresh implementation-dependent temporary file name. + If `-XX:AOTCacheOutput=`*cachefile* is specified, a second JVM process is launched + to perform the Assembly phase to write the optimization artifacts into *cachefile*. + + Extra JVM options can be passed to the second JVM process using the environment + variable `JDK_AOT_VM_OPTIONS`, with the same format as the environment variable + `JAVA_TOOL_OPTIONS`, which is + [defined by JVMTI](https://docs.oracle.com/en/java/javase/24/docs/specs/jvmti.html#tooloptions). + +- `create`: Perform the Assembly phase. `-XX:AOTConfiguration=`*configfile* must be + specified. + The JVM reads history and statistics + from *configfile* and writes the optimization artifacts into *cachefile*. Note that the application itself is not executed in this phase. -- `auto` or `on`: These modes should be used in the Production phase. +- `on`: Execute the application in the Production phase. If `-XX:AOTCache=`*cachefile* is specified, the JVM tries to load *cachefile* as the AOT cache. Otherwise, the JVM tries to load a *default CDS archive* from the JDK installation directory as the AOT cache. @@ -4086,14 +4126,14 @@ The AOT cache can be used with the following command-line options: Since the AOT cache is an optimization feature, there's no guarantee that it will be compatible with all possible JVM options. See [JEP 483](https://openjdk.org/jeps/483), section **Consistency of training and subsequent runs** for a representative - list of scenarios that may be incompatible with the AOT cache for JDK 24. + list of scenarios that may be incompatible with the AOT cache. These scenarios usually involve arbitrary modification of classes for diagnostic purposes and are typically not relevant for production environments. When the AOT cache fails to load: - - If `AOTMode` is `auto`, the JVM will continue execution without using the + - If `AOTMode` was originally `auto`, the JVM will continue execution without using the AOT cache. This is the recommended mode for production environments, especially when you may not have complete control of the command-line (e.g., your application's launch script may allow users to inject options to the command-line). @@ -4103,7 +4143,7 @@ The AOT cache can be used with the following command-line options: - If `AOTMode` is `on`, the JVM will print an error message and exit immediately. This mode should be used only as a "fail-fast" debugging aid to check if your command-line options are compatible with the AOT cache. An alternative is to run your application with - `-XX:AOTMode=auto -Xlog:cds` to see if the AOT cache can be used or not. + `-XX:AOTMode=auto -Xlog:aot` to see if the AOT cache can be used or not. `-XX:+AOTClassLinking` : If this option is enabled, the JVM will perform more advanced optimizations (such @@ -4120,6 +4160,16 @@ The AOT cache can be used with the following command-line options: When `-XX:AOTMode` *is not used* in the command-line, `AOTClassLinking` is disabled by default to provide full compatibility with traditional CDS options such as `-Xshare:dump. +The first occurrence of the special sequence `%p` in `*configfile* and `*cachefile* is replaced +with the process ID of the JVM process launched in the command-line, and likewise the +first occurrence of `%t` is replace by the JVM's startup timestamp. +(After replacement there must be no further occurrences of `%p` or `%t`, to prevent +problems with sub-processes.) For example: + +> `java -XX:AOTConfiguration=foo%p.aotconfig -XX:AOTCacheOutput=foo%p.aot -cp foo.jar Foo` + +will create two files: `foopid123.aotconfig` and `foopid123.aot`, where `123` is the +process ID of the JVM that has executed the application `Foo`. ## Performance Tuning Examples diff --git a/src/java.base/share/native/libjava/System.c b/src/java.base/share/native/libjava/System.c index b1feaf3dff7..725c1e30227 100644 --- a/src/java.base/share/native/libjava/System.c +++ b/src/java.base/share/native/libjava/System.c @@ -154,6 +154,7 @@ Java_jdk_internal_util_SystemProps_00024Raw_platformProperties(JNIEnv *env, jcla PUTPROP(propArray, _sun_jnu_encoding_NDX, sprops->sun_jnu_encoding); /* encodings for standard streams, may be NULL */ + PUTPROP(propArray, _stdin_encoding_NDX, sprops->stdin_encoding); PUTPROP(propArray, _stdout_encoding_NDX, sprops->stdout_encoding); PUTPROP(propArray, _stderr_encoding_NDX, sprops->stderr_encoding); diff --git a/src/java.base/share/native/libjava/ThreadSnapshot.c b/src/java.base/share/native/libjava/ThreadSnapshot.c new file mode 100644 index 00000000000..feea629f4c7 --- /dev/null +++ b/src/java.base/share/native/libjava/ThreadSnapshot.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jni.h" +#include "jvm.h" + +#include "jdk_internal_vm_ThreadSnapshot.h" + + +JNIEXPORT jobject JNICALL +Java_jdk_internal_vm_ThreadSnapshot_create(JNIEnv *env, jclass cls, jobject thread) +{ + return JVM_CreateThreadSnapshot(env, thread); +} diff --git a/src/java.base/share/native/libjava/java_props.h b/src/java.base/share/native/libjava/java_props.h index 95fb6d9e7f9..774a7435e54 100644 --- a/src/java.base/share/native/libjava/java_props.h +++ b/src/java.base/share/native/libjava/java_props.h @@ -65,6 +65,7 @@ typedef struct { char *display_variant; char *encoding; /* always set non-NULL by platform code */ char *sun_jnu_encoding; /* always set non-NULL by platform code */ + char *stdin_encoding; char *stdout_encoding; char *stderr_encoding; diff --git a/src/java.base/share/native/libjava/ub.h b/src/java.base/share/native/libjava/ub.h index d6e0cac3bea..3019e672694 100644 --- a/src/java.base/share/native/libjava/ub.h +++ b/src/java.base/share/native/libjava/ub.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2024 SAP SE. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,10 @@ * following function or method. */ #ifdef UNDEFINED_BEHAVIOR_SANITIZER -#if defined(__clang__) || defined(__GNUC__) +#if defined(__clang__) +#define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined","float-divide-by-zero"))) +#endif +#if defined(__GNUC__) && !defined(__clang__) #define ATTRIBUTE_NO_UBSAN __attribute__((no_sanitize("undefined"))) #endif #endif diff --git a/src/java.base/share/native/libnet/net_util.c b/src/java.base/share/native/libnet/net_util.c index a198152563a..9c0f14b0d90 100644 --- a/src/java.base/share/native/libnet/net_util.c +++ b/src/java.base/share/native/libnet/net_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,9 +86,36 @@ DEF_JNI_OnLoad(JavaVM *vm, void *reserved) /* check if SO_REUSEPORT is supported on this platform */ REUSEPORT_available = reuseport_supported(IPv6_available); + return JNI_VERSION_1_2; } +static int enhancedExceptionsInitialized = 0; +static int enhancedExceptionsAllowed = -1; + +#define CHECK_NULL_THROW_ERROR(X) \ + if (X == NULL) { \ + JNU_ThrowByName(env, "java/lang/InternalError", \ + "can't initialize enhanced exceptions"); \ + return -1; \ + } + +int getEnhancedExceptionsAllowed(JNIEnv *env) { + jclass cls; + jfieldID fid; + + if (enhancedExceptionsInitialized) { + return enhancedExceptionsAllowed; + } + cls = (*env)->FindClass(env, "jdk/internal/util/Exceptions"); + CHECK_NULL_THROW_ERROR(cls); + fid = (*env)->GetStaticFieldID(env, cls, "enhancedNonSocketExceptionText", "Z"); + CHECK_NULL_THROW_ERROR(fid); + enhancedExceptionsAllowed = (*env)->GetStaticBooleanField(env, cls, fid); + enhancedExceptionsInitialized = 1; + return enhancedExceptionsAllowed; +} + static int initialized = 0; JNIEXPORT void JNICALL initInetAddressIDs(JNIEnv *env) { diff --git a/src/java.base/share/native/libnet/net_util.h b/src/java.base/share/native/libnet/net_util.h index a1fa9571821..89537a7f47d 100644 --- a/src/java.base/share/native/libnet/net_util.h +++ b/src/java.base/share/native/libnet/net_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -183,4 +183,6 @@ int lookupCharacteristicsToAddressFamily(int characteristics); int addressesInSystemOrder(int characteristics); +int getEnhancedExceptionsAllowed(JNIEnv *env); + #endif /* NET_UTILS_H */ diff --git a/src/java.base/share/native/libsyslookup/syslookup.c b/src/java.base/share/native/libsyslookup/syslookup.c index b1f543bfdb7..fa7ddca4156 100644 --- a/src/java.base/share/native/libsyslookup/syslookup.c +++ b/src/java.base/share/native/libsyslookup/syslookup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,10 @@ // Adding at least one #include removes unwanted warnings on some platforms. #include +#include "jni_util.h" + +DEF_STATIC_JNI_OnLoad + // Simple dummy function so this library appears as a normal library to tooling. char* syslookup() { return "syslookup"; diff --git a/src/java.base/unix/classes/java/lang/ProcessImpl.java b/src/java.base/unix/classes/java/lang/ProcessImpl.java index 7b5d27f1cc1..390a4f28477 100644 --- a/src/java.base/unix/classes/java/lang/ProcessImpl.java +++ b/src/java.base/unix/classes/java/lang/ProcessImpl.java @@ -100,16 +100,26 @@ private static LaunchMechanism launchMechanism() { // Should be value of a LaunchMechanism enum LaunchMechanism lm = LaunchMechanism.valueOf(s.toUpperCase(Locale.ROOT)); switch (OperatingSystem.current()) { - case LINUX: - return lm; // All options are valid for Linux + case LINUX: { + // All options are valid for Linux, but VFORK is deprecated and results + // in a warning + if (lm == LaunchMechanism.VFORK) { + System.err.println("VFORK MODE DEPRECATED"); + System.err.println(""" + The VFORK launch mechanism has been deprecated for being dangerous. + It will be removed in a future java version. Either remove the + jdk.lang.Process.launchMechanism property (preferred) or use FORK mode + instead (-Djdk.lang.Process.launchMechanism=FORK). + """); + } + return lm; + } case AIX: case MACOS: if (lm != LaunchMechanism.VFORK) { return lm; // All but VFORK are valid } break; - case WINDOWS: - // fall through to throw to Error } } catch (IllegalArgumentException e) { } diff --git a/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java b/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java index a466331de93..2f633ad711d 100644 --- a/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java +++ b/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ public final class ResolverConfigurationImpl extends ResolverConfiguration { // Lock helds whilst loading configuration or checking - private static Object lock = new Object(); + private static final Object lock = new Object(); // Time of last refresh. private static long lastRefresh = -1; diff --git a/src/java.base/unix/classes/sun/net/www/protocol/file/Handler.java b/src/java.base/unix/classes/sun/net/www/protocol/file/Handler.java index efde6a809e9..81f898afc39 100644 --- a/src/java.base/unix/classes/sun/net/www/protocol/file/Handler.java +++ b/src/java.base/unix/classes/sun/net/www/protocol/file/Handler.java @@ -72,6 +72,7 @@ public URLConnection openConnection(URL u, Proxy p) /* If you reach here, it implies that you have a hostname so attempt an ftp connection. */ + FileURLConnection.requireFtpFallbackEnabled(); URLConnection uc; URL ru; diff --git a/src/java.base/unix/classes/sun/nio/ch/FileKey.java b/src/java.base/unix/classes/sun/nio/ch/FileKey.java index 119abe4a3b5..f08d92dc06b 100644 --- a/src/java.base/unix/classes/sun/nio/ch/FileKey.java +++ b/src/java.base/unix/classes/sun/nio/ch/FileKey.java @@ -49,8 +49,7 @@ public static FileKey create(FileDescriptor fd) throws IOException { @Override public int hashCode() { - return (int)(st_dev ^ (st_dev >>> 32)) + - (int)(st_ino ^ (st_ino >>> 32)); + return Long.hashCode(st_dev) + Long.hashCode(st_ino); } @Override diff --git a/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java index b9c099ef92f..5e75e3b2486 100644 --- a/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java +++ b/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,9 +32,10 @@ import java.io.IOException; import java.io.FileDescriptor; +import jdk.internal.util.Exceptions; + import sun.net.ConnectionResetException; import sun.net.NetHooks; -import sun.net.util.SocketExceptions; /** * Unix implementation of AsynchronousSocketChannel @@ -264,7 +265,7 @@ private void finishConnect(boolean mayInvokeDirect) { if (e != null) { if (e instanceof IOException) { var isa = (InetSocketAddress)pendingRemote; - e = SocketExceptions.of((IOException)e, isa); + e = Exceptions.ioException((IOException)e, isa); } // close channel if connection cannot be established try { @@ -355,7 +356,7 @@ Future implConnect(SocketAddress remote, // close channel if connect fails if (e != null) { if (e instanceof IOException) { - e = SocketExceptions.of((IOException)e, isa); + e = Exceptions.ioException((IOException)e, isa); } try { close(); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java index aadef1ea50f..a84a1b4547c 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java @@ -48,10 +48,12 @@ static class Basic extends AbstractBasicFileAttributeView { @Override public BasicFileAttributes readAttributes() throws IOException { try { - UnixFileAttributes attrs = - UnixFileAttributes.get(file, followLinks); + UnixFileAttributes attrs = UnixFileAttributes.get(file, followLinks); return attrs.asBasicFileAttributes(); } catch (UnixException x) { + if (x.errno() == ENOTDIR) { + x.setError(ENOENT); + } x.rethrowAsIOException(file); return null; // keep compiler happy } @@ -209,6 +211,9 @@ public UnixFileAttributes readAttributes() throws IOException { try { return UnixFileAttributes.get(file, followLinks); } catch (UnixException x) { + if (x.errno() == ENOTDIR) { + x.setError(ENOENT); + } x.rethrowAsIOException(file); return null; // keep compiler happy } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java index 2a036d22aed..6fc86b66735 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,7 @@ import java.nio.file.attribute.PosixFileAttributes; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.UserPrincipal; -import java.util.HashSet; +import java.util.EnumSet; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -239,7 +239,7 @@ public GroupPrincipal group() { @Override public Set permissions() { int bits = (st_mode & UnixConstants.S_IAMB); - HashSet perms = new HashSet<>(); + EnumSet perms = EnumSet.noneOf(PosixFilePermission.class); if ((bits & UnixConstants.S_IRUSR) > 0) perms.add(PosixFilePermission.OWNER_READ); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileKey.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileKey.java index 29b1325f3e6..60c7e2a96f8 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileKey.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileKey.java @@ -40,8 +40,7 @@ class UnixFileKey { @Override public int hashCode() { - return (int)(st_dev ^ (st_dev >>> 32)) + - (int)(st_ino ^ (st_ino >>> 32)); + return Long.hashCode(st_dev) + Long.hashCode(st_ino); } @Override diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java index 4311cd6c646..1d16af23460 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java @@ -241,7 +241,7 @@ public boolean equals(Object ob) { @Override public int hashCode() { - return (int)(dev ^ (dev >>> 32)) ^ Arrays.hashCode(entry.dir()); + return Long.hashCode(dev) ^ Arrays.hashCode(entry.dir()); } @Override diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java index 51ed4211fff..7a2bd71388d 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -839,6 +839,9 @@ void move(UnixPath source, UnixPath target, CopyOption... options) new UnixException(errno).rethrowAsIOException(source); } } catch (UnixException x) { + if (x.errno() == ENOTDIR) { + x.setError(ENOENT); + } x.rethrowAsIOException(source); } @@ -951,6 +954,9 @@ void copy(final UnixPath source, try { sourceAttrs = UnixFileAttributes.get(source, flags.followLinks); } catch (UnixException x) { + if (x.errno() == ENOTDIR) { + x.setError(ENOENT); + } x.rethrowAsIOException(source); } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java index ed846354ea0..beb9a1af41b 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java @@ -322,8 +322,12 @@ public void checkAccess(Path obj, AccessMode... modes) throws IOException { mode |= X_OK; } int errno = access(file, mode); - if (errno != 0) + if (errno != 0) { + if (errno == ENOTDIR) { + errno = ENOENT; + } new UnixException(errno).rethrowAsIOException(file); + } } @Override diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java index 046f843371d..09611f23298 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -347,6 +347,18 @@ static void fchmod(int fd, int mode) throws UnixException { } private static native void fchmod0(int fd, int mode) throws UnixException; + /** + * fchmodat(int fd, const char *path, mode_t mode, int flag) + */ + static void fchmodat(int fd, UnixPath path, int mode, int flag) + throws UnixException { + try (NativeBuffer buffer = copyToNativeBuffer(path)) { + fchmodat0(fd, buffer.address(), mode, flag); + } + } + private static native void fchmodat0(int fd, long pathAddress, int mode, int flag) + throws UnixException; + /** * futimens(int fildes, const struct timespec times[2]) */ @@ -558,6 +570,14 @@ static boolean xattrSupported() { return (capabilities & SUPPORTS_XATTR) != 0; } + /** + * Supports fchmodat with AT_SYMLINK_NOFOLLOW flag + */ + static boolean fchmodatNoFollowSupported() { + return fchmodatNoFollowSupported0(); + } + private static native boolean fchmodatNoFollowSupported0(); + private static native int init(); static { jdk.internal.loader.BootLoader.loadLibrary("nio"); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index e2f52e701cb..5dfc73f57aa 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,7 +126,7 @@ private static String normalize(String input, int len, int off) { private static byte[] encode(UnixFileSystem fs, String input) { input = fs.normalizeNativePath(input); try { - return JLA.getBytesNoRepl(input, Util.jnuEncoding()); + return JLA.uncheckedGetBytesNoRepl(input, Util.jnuEncoding()); } catch (CharacterCodingException cce) { throw new InvalidPathException(input, "Malformed input or input contains unmappable characters"); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java b/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java index ce04f49a9e2..5c0693870e6 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -158,7 +158,7 @@ public SeekableByteChannel newByteChannel(Path obj, * Deletes file/directory in this directory. Works in a race-free manner * when invoked with flags. */ - private void implDelete(Path obj, boolean haveFlags, int flags) + private void implDelete(Path obj, int flags) throws IOException { UnixPath file = getName(obj); @@ -168,20 +168,6 @@ private void implDelete(Path obj, boolean haveFlags, int flags) if (!ds.isOpen()) throw new ClosedDirectoryStreamException(); - if (!haveFlags) { - // need file attribute to know if file is directory. This creates - // a race in that the file may be replaced by a directory or a - // directory replaced by a file between the time we query the - // file type and unlink it. - UnixFileAttributes attrs = null; - try { - attrs = UnixFileAttributes.get(dfd, file, false); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } - flags = (attrs.isDirectory()) ? AT_REMOVEDIR : 0; - } - try { unlinkat(dfd, file.asByteArray(), flags); } catch (UnixException x) { @@ -199,12 +185,12 @@ private void implDelete(Path obj, boolean haveFlags, int flags) @Override public void deleteFile(Path file) throws IOException { - implDelete(file, true, 0); + implDelete(file, 0); } @Override public void deleteDirectory(Path dir) throws IOException { - implDelete(dir, true, AT_REMOVEDIR); + implDelete(dir, AT_REMOVEDIR); } /** @@ -428,15 +414,24 @@ public void setPermissions(Set perms) if (!ds.isOpen()) throw new ClosedDirectoryStreamException(); - int fd = (file == null) ? dfd : open(); - try { - fchmod(fd, UnixFileModeAttribute.toUnixMode(perms)); - } catch (UnixException x) { - x.rethrowAsIOException(file); - } finally { - if (file != null && fd >= 0) - UnixNativeDispatcher.close(fd, e-> null); + int mode = UnixFileModeAttribute.toUnixMode(perms); + if (file == null) + fchmod(dfd, mode); + else if (followLinks) + fchmodat(dfd, file, mode, 0); + else if (fchmodatNoFollowSupported()) + fchmodat(dfd, file, mode, AT_SYMLINK_NOFOLLOW); + else { + int fd = open(); + try { + fchmod(fd, mode); + } finally { + if (fd >= 0) + UnixNativeDispatcher.close(fd, e-> null); + } } + } catch (UnixException x) { + x.rethrowAsIOException(file); } finally { ds.readLock().unlock(); } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java b/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java index d2295ce3cc5..1214ba85568 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java @@ -166,10 +166,10 @@ public int read(String name, ByteBuffer dst) throws IOException { assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); - if (dst instanceof sun.nio.ch.DirectBuffer ddst) { + if (dst.isDirect()) { NIO_ACCESS.acquireSession(dst); try { - long address = ddst.address() + pos; + long address = NIO_ACCESS.getBufferAddress(dst) + pos; int n = read(name, address, rem); dst.position(pos + n); return n; @@ -225,10 +225,10 @@ public int write(String name, ByteBuffer src) throws IOException { assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); - if (src instanceof sun.nio.ch.DirectBuffer buf) { + if (src.isDirect()) { NIO_ACCESS.acquireSession(src); try { - long address = buf.address() + pos; + long address = NIO_ACCESS.getBufferAddress(src) + pos; write(name, address, rem); src.position(pos + rem); return rem; diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java b/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java index f50dea108b0..b1e7b7cbcc4 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,9 @@ import java.io.IOException; import static sun.nio.fs.UnixNativeDispatcher.*; +import static jdk.internal.util.Exceptions.filterUserName; +import static jdk.internal.util.Exceptions.formatMsg; + /** * Unix implementation of java.nio.file.attribute.UserPrincipal */ @@ -132,18 +135,19 @@ public static Group fromGid(int gid) { private static int lookupName(String name, boolean isGroup) throws IOException { - int id; + int id = -1; try { id = (isGroup) ? getgrnam(name) : getpwnam(name); } catch (UnixException x) { - throw new IOException(name + ": " + x.errorString()); + throw new IOException(formatMsg("%s " + x.errorString(), + filterUserName(name).suffixWith(": "))); } if (id == -1) { // lookup failed, allow input to be uid or gid try { id = Integer.parseInt(name); } catch (NumberFormatException ignore) { - throw new UserPrincipalNotFoundException(name); + throw new UserPrincipalNotFoundException(formatMsg("%s", filterUserName(name))); } } return id; diff --git a/src/java.base/unix/native/jspawnhelper/jspawnhelper.c b/src/java.base/unix/native/jspawnhelper/jspawnhelper.c index de85d917811..071be59504d 100644 --- a/src/java.base/unix/native/jspawnhelper/jspawnhelper.c +++ b/src/java.base/unix/native/jspawnhelper/jspawnhelper.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -145,7 +144,6 @@ int main(int argc, char *argv[]) { struct stat buf; /* argv[1] contains the fd number to read all the child info */ int r, fdinr, fdinw, fdout; - sigset_t unblock_signals; #ifdef DEBUG jtregSimulateCrash(0, 4); @@ -173,10 +171,6 @@ int main(int argc, char *argv[]) { shutItDown(); } - // Reset any mask signals from parent - sigemptyset(&unblock_signals); - sigprocmask(SIG_SETMASK, &unblock_signals, NULL); - // Close the writing end of the pipe we use for reading from the parent. // We have to do this before we start reading from the parent to avoid // blocking in the case the parent exits before we finished reading from it. diff --git a/src/java.base/unix/native/libjava/ProcessImpl_md.c b/src/java.base/unix/native/libjava/ProcessImpl_md.c index fc97eb187eb..1d0c8d21d37 100644 --- a/src/java.base/unix/native/libjava/ProcessImpl_md.c +++ b/src/java.base/unix/native/libjava/ProcessImpl_md.c @@ -317,12 +317,23 @@ releaseBytes(JNIEnv *env, jbyteArray arr, const char* parr) (*env)->ReleaseByteArrayElements(env, arr, (jbyte*) parr, JNI_ABORT); } -#define IOE_FORMAT "error=%d, %s" +#define IOE_FORMAT "%s, error: %d (%s) %s" + +#define SPAWN_HELPER_INTERNAL_ERROR_MSG "\n" \ + "Possible reasons:\n" \ + " - Spawn helper ran into JDK version mismatch\n" \ + " - Spawn helper ran into unexpected internal error\n" \ + " - Spawn helper was terminated by another process\n" \ + "Possible solutions:\n" \ + " - Restart JVM, especially after in-place JDK updates\n" \ + " - Check system logs for JDK-related errors\n" \ + " - Re-install JDK to fix permission/versioning problems\n" \ + " - Switch to legacy launch mechanism with -Djdk.lang.Process.launchMechanism=FORK\n" static void -throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) +throwIOExceptionImpl(JNIEnv *env, int errnum, const char *externalDetail, const char *internalDetail) { - const char *detail = defaultDetail; + const char *errorDetail; char *errmsg; size_t fmtsize; char tmpbuf[1024]; @@ -330,16 +341,22 @@ throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) if (errnum != 0) { int ret = getErrorString(errnum, tmpbuf, sizeof(tmpbuf)); - if (ret != EINVAL) - detail = tmpbuf; + if (ret != EINVAL) { + errorDetail = tmpbuf; + } else { + errorDetail = "unknown"; + } + } else { + errorDetail = "none"; } + /* ASCII Decimal representation uses 2.4 times as many bits as binary. */ - fmtsize = sizeof(IOE_FORMAT) + strlen(detail) + 3 * sizeof(errnum); + fmtsize = sizeof(IOE_FORMAT) + strlen(externalDetail) + 3 * sizeof(errnum) + strlen(errorDetail) + strlen(internalDetail) + 1; errmsg = NEW(char, fmtsize); if (errmsg == NULL) return; - snprintf(errmsg, fmtsize, IOE_FORMAT, errnum, detail); + snprintf(errmsg, fmtsize, IOE_FORMAT, externalDetail, errnum, errorDetail, internalDetail); s = JNU_NewStringPlatform(env, errmsg); if (s != NULL) { jobject x = JNU_NewObjectByName(env, "java/io/IOException", @@ -350,14 +367,38 @@ throwIOException(JNIEnv *env, int errnum, const char *defaultDetail) free(errmsg); } +/** + * Throws IOException that signifies an internal error, e.g. spawn helper failure. + */ +static void +throwInternalIOException(JNIEnv *env, int errnum, const char *externalDetail, int mode) +{ + switch (mode) { + case MODE_POSIX_SPAWN: + throwIOExceptionImpl(env, errnum, externalDetail, SPAWN_HELPER_INTERNAL_ERROR_MSG); + break; + default: + throwIOExceptionImpl(env, errnum, externalDetail, ""); + } +} + +/** + * Throws IOException that signifies a normal error. + */ +static void +throwIOException(JNIEnv *env, int errnum, const char *externalDetail) +{ + throwIOExceptionImpl(env, errnum, externalDetail, ""); +} + /** * Throws an IOException with a message composed from the result of waitpid status. */ -static void throwExitCause(JNIEnv *env, int pid, int status) { +static void throwExitCause(JNIEnv *env, int pid, int status, int mode) { char ebuf[128]; if (WIFEXITED(status)) { snprintf(ebuf, sizeof ebuf, - "Failed to exec spawn helper: pid: %d, exit value: %d", + "Failed to exec spawn helper: pid: %d, exit code: %d", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { snprintf(ebuf, sizeof ebuf, @@ -368,7 +409,7 @@ static void throwExitCause(JNIEnv *env, int pid, int status) { "Failed to exec spawn helper: pid: %d, status: 0x%08x", pid, status); } - throwIOException(env, 0, ebuf); + throwInternalIOException(env, 0, ebuf, mode); } #ifdef DEBUG_PROCESS @@ -691,7 +732,7 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, (fds[2] == -1 && pipe(err) < 0) || (pipe(childenv) < 0) || (pipe(fail) < 0)) { - throwIOException(env, errno, "Bad file descriptor"); + throwInternalIOException(env, errno, "Bad file descriptor", c->mode); goto Catch; } c->fds[0] = fds[0]; @@ -725,13 +766,13 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, if (resultPid < 0) { switch (c->mode) { case MODE_VFORK: - throwIOException(env, errno, "vfork failed"); + throwInternalIOException(env, errno, "vfork failed", c->mode); break; case MODE_FORK: - throwIOException(env, errno, "fork failed"); + throwInternalIOException(env, errno, "fork failed", c->mode); break; case MODE_POSIX_SPAWN: - throwIOException(env, errno, "posix_spawn failed"); + throwInternalIOException(env, errno, "posix_spawn failed", c->mode); break; } goto Catch; @@ -745,20 +786,21 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, { int tmpStatus = 0; int p = waitpid(resultPid, &tmpStatus, 0); - throwExitCause(env, p, tmpStatus); + throwExitCause(env, p, tmpStatus, c->mode); goto Catch; } case sizeof(errnum): if (errnum != CHILD_IS_ALIVE) { /* This can happen if the spawn helper encounters an error * before or during the handshake with the parent. */ - throwIOException(env, 0, "Bad code from spawn helper " - "(Failed to exec spawn helper)"); + throwInternalIOException(env, 0, + "Bad code from spawn helper (Failed to exec spawn helper)", + c->mode); goto Catch; } break; default: - throwIOException(env, errno, "Read failed"); + throwInternalIOException(env, errno, "Read failed", c->mode); goto Catch; } } @@ -770,7 +812,7 @@ Java_java_lang_ProcessImpl_forkAndExec(JNIEnv *env, throwIOException(env, errnum, "Exec failed"); goto Catch; default: - throwIOException(env, errno, "Read failed"); + throwInternalIOException(env, errno, "Read failed", c->mode); goto Catch; } diff --git a/src/java.base/unix/native/libjava/childproc.c b/src/java.base/unix/native/libjava/childproc.c index 1543e269223..7a21b86565f 100644 --- a/src/java.base/unix/native/libjava/childproc.c +++ b/src/java.base/unix/native/libjava/childproc.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -405,6 +406,13 @@ childProcess(void *arg) if (p->pdir != NULL && chdir(p->pdir) < 0) goto WhyCantJohnnyExec; + // Reset any mask signals from parent, but not in VFORK mode + if (p->mode != MODE_VFORK) { + sigset_t unblock_signals; + sigemptyset(&unblock_signals); + sigprocmask(SIG_SETMASK, &unblock_signals, NULL); + } + if (fcntl(FAIL_FILENO, F_SETFD, FD_CLOEXEC) == -1) goto WhyCantJohnnyExec; diff --git a/src/java.base/unix/native/libjava/java_props_md.c b/src/java.base/unix/native/libjava/java_props_md.c index 6db307088b0..1d5435d5229 100644 --- a/src/java.base/unix/native/libjava/java_props_md.c +++ b/src/java.base/unix/native/libjava/java_props_md.c @@ -464,6 +464,9 @@ GetJavaProperties(JNIEnv *env) sprops.sun_jnu_encoding = sprops.encoding; #endif + if (isatty(STDIN_FILENO) == 1) { + sprops.stdin_encoding = sprops.encoding; + } if (isatty(STDOUT_FILENO) == 1) { sprops.stdout_encoding = sprops.encoding; } diff --git a/src/java.base/unix/native/libjava/locale_str.h b/src/java.base/unix/native/libjava/locale_str.h index 4d85b88ffb7..ea1a8c8fd47 100644 --- a/src/java.base/unix/native/libjava/locale_str.h +++ b/src/java.base/unix/native/libjava/locale_str.h @@ -87,7 +87,7 @@ "zh", "zh_CN", #ifdef __linux__ "bokmal", "nb_NO", - "bokm\xE5l", "nb_NO", + "bokmål", "nb_NO", "catalan", "ca_ES", "croatian", "hr_HR", "czech", "cs_CZ", @@ -98,7 +98,7 @@ "eesti", "et_EE", "estonian", "et_EE", "finnish", "fi_FI", - "fran\xE7\x61is", "fr_FR", + "français", "fr_FR", "french", "fr_FR", "galego", "gl_ES", "galician", "gl_ES", @@ -162,7 +162,7 @@ static char *language_names[] = { "deutsch", "de", "dutch", "nl", "finnish", "fi", - "fran\xE7\x61is", "fr", + "français", "fr", "french", "fr", "german", "de", "greek", "el", diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c index 1713d0a8ccd..d50130d188b 100644 --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -184,23 +184,36 @@ void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, { int size; char *buf; - const char *format = "%s: %s"; const char *error_string = gai_strerror(gai_error); if (error_string == NULL) error_string = "unknown error"; + int enhancedExceptions = getEnhancedExceptionsAllowed(env); + + if (enhancedExceptions) { + size = strlen(hostname); + } else { + size = 0; + } + size += strlen(error_string) + 3; - size = strlen(format) + strlen(hostname) + strlen(error_string) + 2; buf = (char *) malloc(size); if (buf) { jstring s; - snprintf(buf, size, format, hostname, error_string); - s = JNU_NewStringPlatform(env, buf); - if (s != NULL) { - jobject x = JNU_NewObjectByName(env, + int n; + if (enhancedExceptions) { + n = snprintf(buf, size, "%s: %s", hostname, error_string); + } else { + n = snprintf(buf, size, " %s", error_string); + } + if (n >= 0) { + s = JNU_NewStringPlatform(env, buf); + if (s != NULL) { + jobject x = JNU_NewObjectByName(env, "java/net/UnknownHostException", "(Ljava/lang/String;)V", s); - if (x != NULL) - (*env)->Throw(env, x); + if (x != NULL) + (*env)->Throw(env, x); + } } free(buf); } diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c index 578c38a3b2f..98445c93731 100644 --- a/src/java.base/unix/native/libnio/ch/Net.c +++ b/src/java.base/unix/native/libnio/ch/Net.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -671,6 +671,16 @@ Java_sun_nio_ch_Net_joinOrDrop4(JNIEnv *env, jobject this, jboolean join, jobjec n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); } #endif +#ifdef _AIX + // workaround AIX bug where IP_ADD_MEMBERSHIP fails intermittently + if (n < 0 && errno == EAGAIN) { + int countdown = 3; + while (n < 0 && errno == EAGAIN && countdown > 0) { + n = setsockopt(fdval(env,fdo), IPPROTO_IP, opt, optval, optlen); + countdown--; + } + } +#endif if (n < 0) { if (join && (errno == ENOPROTOOPT || errno == EOPNOTSUPP)) diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index fefaac94b48..fbf996886ae 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -398,6 +398,16 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) return capabilities; } +JNIEXPORT jboolean JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fchmodatNoFollowSupported0(JNIEnv* env, jclass this) { +#if defined(__linux__) + // Linux recognizes but does not support the AT_SYMLINK_NOFOLLOW flag + return JNI_FALSE; +#else + return JNI_TRUE; +#endif +} + JNIEXPORT jbyteArray JNICALL Java_sun_nio_fs_UnixNativeDispatcher_getcwd(JNIEnv* env, jclass this) { jbyteArray result = NULL; @@ -797,6 +807,19 @@ Java_sun_nio_fs_UnixNativeDispatcher_fchmod0(JNIEnv* env, jclass this, jint file } } +JNIEXPORT void JNICALL +Java_sun_nio_fs_UnixNativeDispatcher_fchmodat0(JNIEnv* env, jclass this, + jint fd, jlong pathAddress, jint mode, jint flag) +{ + int err; + const char* path = (const char*)jlong_to_ptr(pathAddress); + + RESTARTABLE(fchmodat((int)fd, path, (mode_t)mode, (int)flag), err); + if (err == -1) { + throwUnixException(env, errno); + } +} + JNIEXPORT void JNICALL Java_sun_nio_fs_UnixNativeDispatcher_chown0(JNIEnv* env, jclass this, jlong pathAddress, jint uid, jint gid) diff --git a/src/java.base/windows/classes/java/io/WinNTFileSystem.java b/src/java.base/windows/classes/java/io/WinNTFileSystem.java index 3f383187517..e053f7f004c 100644 --- a/src/java.base/windows/classes/java/io/WinNTFileSystem.java +++ b/src/java.base/windows/classes/java/io/WinNTFileSystem.java @@ -41,6 +41,9 @@ final class WinNTFileSystem extends FileSystem { private static final String LONG_PATH_PREFIX = "\\\\?\\"; + private static final boolean ALLOW_DELETE_READ_ONLY_FILES = + Boolean.getBoolean("jdk.io.File.allowDeleteReadOnlyFiles"); + private final char slash; private final char altSlash; private final char semicolon; @@ -362,27 +365,28 @@ public boolean isAbsolute(File f) { @Override public boolean isInvalid(File f) { - if (f.getPath().indexOf('\u0000') >= 0) + final String pathname = f.getPath(); + + // Invalid if the pathname string contains a null character or if + // any name in the pathname's name sequence ends with a space + if (pathname.indexOf('\u0000') >= 0 || pathname.endsWith(" ") + || pathname.contains(" \\")) return true; + // The remaining checks are irrelevant for alternate data streams (ADS) if (ENABLE_ADS) return false; - // Invalid if there is a ":" at a position greater than 1, or if there + // Invalid if there is a ":" at a position other than 1, or if there // is a ":" at position 1 and the first character is not a letter - String pathname = f.getPath(); int lastColon = pathname.lastIndexOf(":"); + if (lastColon >= 0 && + (lastColon != 1 || !isLetter(pathname.charAt(0)))) + return true; - // Valid if there is no ":" present or if the last ":" present is - // at index 1 and the first character is a latter - if (lastColon < 0 || - (lastColon == 1 && isLetter(pathname.charAt(0)))) - return false; - - // Invalid if path creation fails - Path path = null; + // Invalid if the path string cannot be converted to a Path try { - path = sun.nio.fs.DefaultFileSystemProvider.theFileSystem().getPath(pathname); + Path path = sun.nio.fs.DefaultFileSystemProvider.theFileSystem().getPath(pathname); return false; } catch (InvalidPathException ignored) { } @@ -565,9 +569,9 @@ public boolean setReadOnly(File f) { @Override public boolean delete(File f) { - return delete0(f); + return delete0(f, ALLOW_DELETE_READ_ONLY_FILES); } - private native boolean delete0(File f); + private native boolean delete0(File f, boolean allowDeleteReadOnlyFiles); @Override public boolean rename(File f1, File f2) { diff --git a/src/java.base/windows/classes/sun/net/www/protocol/file/Handler.java b/src/java.base/windows/classes/sun/net/www/protocol/file/Handler.java index 38ad16267e7..0cd32e600e9 100644 --- a/src/java.base/windows/classes/sun/net/www/protocol/file/Handler.java +++ b/src/java.base/windows/classes/sun/net/www/protocol/file/Handler.java @@ -88,6 +88,7 @@ public URLConnection openConnection(URL url, Proxy p) /* * Now attempt an ftp connection. */ + FileURLConnection.requireFtpFallbackEnabled(); URLConnection uc; URL newurl; diff --git a/src/java.base/windows/classes/sun/net/www/protocol/file/UNCFileURLConnection.java b/src/java.base/windows/classes/sun/net/www/protocol/file/UNCFileURLConnection.java index d5a510d8f31..0a86d3942f3 100644 --- a/src/java.base/windows/classes/sun/net/www/protocol/file/UNCFileURLConnection.java +++ b/src/java.base/windows/classes/sun/net/www/protocol/file/UNCFileURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ final class UNCFileURLConnection extends FileURLConnection { @Override @SuppressWarnings("removal") + @Deprecated(since = "25", forRemoval = true) public Permission getPermission() { Permission perm = permission; if (perm == null) { diff --git a/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java b/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java index f8b5fab4316..36065f040a0 100644 --- a/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/WindowsAsynchronousSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,9 @@ import java.net.*; import java.util.concurrent.*; import java.io.IOException; +import jdk.internal.util.Exceptions; import jdk.internal.invoke.MhUtil; import jdk.internal.misc.Unsafe; -import sun.net.util.SocketExceptions; /** * Windows implementation of AsynchronousSocketChannel using overlapped I/O. @@ -253,7 +253,7 @@ public void run() { if (exc != null) { closeChannel(); - exc = SocketExceptions.of(toIOException(exc), remote); + exc = Exceptions.ioException(toIOException(exc), remote); result.setFailure(exc); } Invoker.invoke(result); @@ -280,7 +280,7 @@ public void completed(int bytesTransferred, boolean canInvokeDirect) { if (exc != null) { closeChannel(); IOException ee = toIOException(exc); - ee = SocketExceptions.of(ee, remote); + ee = Exceptions.ioException(ee, remote); result.setFailure(ee); } @@ -296,12 +296,12 @@ public void completed(int bytesTransferred, boolean canInvokeDirect) { */ @Override public void failed(int error, IOException x) { - x = SocketExceptions.of(x, remote); + x = Exceptions.ioException(x, remote); if (isOpen()) { closeChannel(); result.setFailure(x); } else { - x = SocketExceptions.of(new AsynchronousCloseException(), remote); + x = Exceptions.ioException(new AsynchronousCloseException(), remote); result.setFailure(x); } Invoker.invoke(result); diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsSecurity.java b/src/java.base/windows/classes/sun/nio/fs/WindowsSecurity.java index 9bcd800e13c..47d8045c00b 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsSecurity.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsSecurity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package sun.nio.fs; -import jdk.internal.vm.Continuation; import jdk.internal.vm.ContinuationSupport; import static sun.nio.fs.WindowsNativeDispatcher.*; @@ -106,9 +105,7 @@ static Privilege enablePrivilege(String priv) { final boolean needToRevert = elevated; // prevent yielding with privileges - if (ContinuationSupport.isSupported()) - Continuation.pin(); - + ContinuationSupport.pinIfSupported(); return () -> { try { if (token != 0L) { @@ -126,8 +123,7 @@ else if (needToRevert) } } finally { LocalFree(pLuid); - if (ContinuationSupport.isSupported()) - Continuation.unpin(); + ContinuationSupport.unpinIfSupported(); } }; } diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java b/src/java.base/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java index da3460592f4..8c3dfa5546e 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsSecurityDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,8 @@ import static sun.nio.fs.WindowsNativeDispatcher.*; import static sun.nio.fs.WindowsConstants.*; +import static jdk.internal.util.Exceptions.filterUserName; +import static jdk.internal.util.Exceptions.formatMsg; /** * A SecurityDescriptor for use when setting a file's ACL or creating a file @@ -136,8 +138,8 @@ private WindowsSecurityDescriptor(List acl) throws IOException { Math.max(SIZEOF_ACCESS_ALLOWED_ACE, SIZEOF_ACCESS_DENIED_ACE); } catch (WindowsException x) { - throw new IOException("Failed to get SID for " + user.getName() - + ": " + x.errorString()); + throw new IOException(formatMsg("Failed to get SID %s : " + x.errorString(), + filterUserName(user.getName()).prefixWith("for "))); } } diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsUserPrincipals.java b/src/java.base/windows/classes/sun/nio/fs/WindowsUserPrincipals.java index 336bbe22cfb..0a4e2b9c9fa 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsUserPrincipals.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsUserPrincipals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,8 @@ import static sun.nio.fs.WindowsConstants.*; import static sun.nio.fs.WindowsNativeDispatcher.*; +import static jdk.internal.util.Exceptions.formatMsg; +import static jdk.internal.util.Exceptions.filterUserName; class WindowsUserPrincipals { private WindowsUserPrincipals() { } @@ -132,13 +134,14 @@ static UserPrincipal fromSid(long sidAddress) throws IOException { static UserPrincipal lookup(String name) throws IOException { // invoke LookupAccountName to get buffer size needed for SID - int size; + int size = 0; try { size = LookupAccountName(name, 0L, 0); } catch (WindowsException x) { if (x.lastError() == ERROR_NONE_MAPPED) throw new UserPrincipalNotFoundException(name); - throw new IOException(name + ": " + x.errorString()); + throw new IOException(formatMsg("%s " + x.errorString(), + filterUserName(name).suffixWith(": "))); } assert size > 0; @@ -153,7 +156,8 @@ static UserPrincipal lookup(String name) throws IOException { // return user principal return fromSid(sidBuffer.address()); } catch (WindowsException x) { - throw new IOException(name + ": " + x.errorString()); + throw new IOException(formatMsg("%s " + x.errorString(), + filterUserName(name).suffixWith(": "))); } } } diff --git a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c index ebbad326146..df5ad1e8911 100644 --- a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c +++ b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c @@ -134,7 +134,7 @@ WCHAR * fixes[2][2][3][16] = L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", }, { // currency - L"\xA4", L"", L"\xA4 ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", + L"¤", L"", L"¤ ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", }, { // percent L"", L"", L"%", L"% ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", @@ -145,7 +145,7 @@ WCHAR * fixes[2][2][3][16] = L"(", L"-", L"- ", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", }, { //currency - L"(\xA4", L"-\xA4", L"\xA4-", L"\xA4", L"(", L"-", L"", L"", L"-", L"-\xA4 ", L"", L"\xA4 ", L"\xA4 -", L"", L"(\xA4 ", L"(" + L"(¤", L"-¤", L"¤-", L"¤", L"(", L"-", L"", L"", L"-", L"-¤ ", L"", L"¤ ", L"¤ -", L"", L"(¤ ", L"(" }, { // percent L"-", L"-", L"-%", L"%-", L"%", L"", L"", L"-% ", L"", L"% ", L"% -", L"", L"", L"", L"", L"", @@ -158,7 +158,7 @@ WCHAR * fixes[2][2][3][16] = L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"" }, { // currency - L"", L"\xA4 ", L"", L" \xA4", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", + L"", L"¤ ", L"", L" ¤", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", }, { // percent L" %", L"%", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", @@ -169,7 +169,7 @@ WCHAR * fixes[2][2][3][16] = L")", L"", L" ", L"-", L" -", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", L"", }, { //currency - L")", L"", L"", L"-", L"\xA4)", L"\xA4", L"-\xA4", L"\xA4-", L" \xA4", L"", L" \xA4-", L"-", L"", L"- \xA4", L")", L" \xA4)" + L")", L"", L"", L"-", L"¤)", L"¤", L"-¤", L"¤-", L" ¤", L"", L" ¤-", L"-", L"", L"- ¤", L")", L" ¤)" }, { // percent L" %", L"%", L"", L"", L"-", L"-%", L"%-", L"", L" %-", L"-", L"", L"- %", L"", L"", L"", L"", diff --git a/src/java.base/windows/native/libjava/WinNTFileSystem_md.c b/src/java.base/windows/native/libjava/WinNTFileSystem_md.c index 2598eaa6fec..ccf89eb71e0 100644 --- a/src/java.base/windows/native/libjava/WinNTFileSystem_md.c +++ b/src/java.base/windows/native/libjava/WinNTFileSystem_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -649,31 +649,43 @@ Java_java_io_WinNTFileSystem_createFileExclusively0(JNIEnv *env, jclass cls, } static int -removeFileOrDirectory(const jchar *path) +removeFileOrDirectory(const jchar *path, jboolean allowDeleteReadOnlyFiles) { /* Returns 0 on success */ - DWORD a; - - SetFileAttributesW(path, FILE_ATTRIBUTE_NORMAL); - a = GetFileAttributesW(path); + DWORD a = GetFileAttributesW(path); if (a == INVALID_FILE_ATTRIBUTES) { return 1; } else if (a & FILE_ATTRIBUTE_DIRECTORY) { + // read-only attribute cannot be set on directories return !RemoveDirectoryW(path); } else { - return !DeleteFileW(path); + // unset read-only attribute if deleting read-only files is enabled + BOOL readOnlyAttrCleared = FALSE; + if (allowDeleteReadOnlyFiles && ((a & FILE_ATTRIBUTE_READONLY) != 0)) { + DWORD notReadOnlyAttr = a & (~FILE_ATTRIBUTE_READONLY); + readOnlyAttrCleared = SetFileAttributesW(path, notReadOnlyAttr); + } + + BOOL deleted = !DeleteFileW(path); + + // reinstate the read-only attribute if it was unset but deletion failed + if (!deleted && readOnlyAttrCleared) + SetFileAttributesW(path, a); + + return deleted; } } JNIEXPORT jboolean JNICALL -Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file) +Java_java_io_WinNTFileSystem_delete0(JNIEnv *env, jobject this, jobject file, + jboolean allowDeleteReadOnlyFiles) { jboolean rv = JNI_FALSE; WCHAR *pathbuf = fileToNTPath(env, file, ids.path); if (pathbuf == NULL) { return JNI_FALSE; } - if (removeFileOrDirectory(pathbuf) == 0) { + if (removeFileOrDirectory(pathbuf, allowDeleteReadOnlyFiles) == 0) { rv = JNI_TRUE; } free(pathbuf); diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index 275dd3795c5..9495faf81e5 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -634,7 +634,7 @@ GetJavaProperties(JNIEnv* env) LCID userDefaultUILCID = MAKELCID(userDefaultUILang, SORTIDFROMLCID(userDefaultLCID)); { - HANDLE hStdOutErr; + HANDLE hStdHandle; // Windows UI Language selection list only cares "language" // information of the UI Language. For example, the list @@ -677,14 +677,19 @@ GetJavaProperties(JNIEnv* env) sprops.sun_jnu_encoding = "MS950_HKSCS"; } - hStdOutErr = GetStdHandle(STD_OUTPUT_HANDLE); - if (hStdOutErr != INVALID_HANDLE_VALUE && - GetFileType(hStdOutErr) == FILE_TYPE_CHAR) { + hStdHandle = GetStdHandle(STD_INPUT_HANDLE); + if (hStdHandle != INVALID_HANDLE_VALUE && + GetFileType(hStdHandle) == FILE_TYPE_CHAR) { + sprops.stdin_encoding = getConsoleEncoding(FALSE); + } + hStdHandle = GetStdHandle(STD_OUTPUT_HANDLE); + if (hStdHandle != INVALID_HANDLE_VALUE && + GetFileType(hStdHandle) == FILE_TYPE_CHAR) { sprops.stdout_encoding = getConsoleEncoding(TRUE); } - hStdOutErr = GetStdHandle(STD_ERROR_HANDLE); - if (hStdOutErr != INVALID_HANDLE_VALUE && - GetFileType(hStdOutErr) == FILE_TYPE_CHAR) { + hStdHandle = GetStdHandle(STD_ERROR_HANDLE); + if (hStdHandle != INVALID_HANDLE_VALUE && + GetFileType(hStdHandle) == FILE_TYPE_CHAR) { if (sprops.stdout_encoding != NULL) sprops.stderr_encoding = sprops.stdout_encoding; else diff --git a/src/java.base/windows/native/libnet/Inet4AddressImpl.c b/src/java.base/windows/native/libnet/Inet4AddressImpl.c index 0e2d6a3455f..0ef0cae5be7 100644 --- a/src/java.base/windows/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet4AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,8 +88,9 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, if (error) { // report error - NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException", - hostname); + NET_ThrowByNameWithLastError( + env, "java/net/UnknownHostException", + getEnhancedExceptionsAllowed(env) ? hostname : ""); goto cleanupAndReturn; } else { int i = 0; diff --git a/src/java.base/windows/native/libnet/Inet6AddressImpl.c b/src/java.base/windows/native/libnet/Inet6AddressImpl.c index 244e2fefa9b..0281e2ddecb 100644 --- a/src/java.base/windows/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet6AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -84,7 +84,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, if (error) { // report error NET_ThrowByNameWithLastError(env, "java/net/UnknownHostException", - hostname); + getEnhancedExceptionsAllowed(env) ? hostname : ""); goto cleanupAndReturn; } else { int i = 0, inetCount = 0, inet6Count = 0, inetIndex = 0, diff --git a/src/java.base/windows/native/libsyslookup/syslookup.c b/src/java.base/windows/native/libsyslookup/syslookup.c index c7ddce46a79..3216632c53d 100644 --- a/src/java.base/windows/native/libsyslookup/syslookup.c +++ b/src/java.base/windows/native/libsyslookup/syslookup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,10 @@ #include #include +#include "jni_util.h" + +DEF_STATIC_JNI_OnLoad + // Forces generation of inline code on Windows __declspec(dllexport) void* funcs[] = { // stdio.h 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 26ee999e533..1561cf05a59 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package javax.annotation.processing; import java.io.IOException; +import java.io.Serial; /** * Indicates a {@link Filer} detected an attempt to open a file that @@ -38,7 +39,10 @@ * @since 1.6 */ public class FilerException extends IOException { - static final long serialVersionUID = 8426423106453163293L; + + @Serial + private static final long serialVersionUID = 8426423106453163293L; + /** * Constructs an exception with the specified detail message. * @param s the detail message, which should include the name of 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 9260ce532f1..6b4ae119504 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,6 +81,8 @@ public enum SourceVersion { * switch in second preview, module Import Declarations in second * preview, simple source files and instance main in fourth * preview, flexible constructor bodies in third preview) + * 25: module import declarations, compact source files and + * instance main methods, and flexible constructor bodies */ /** @@ -449,13 +451,35 @@ public enum SourceVersion { * The version introduced by the Java Platform, Standard Edition * 25. * + * Additions in this release include module import declarations, + * compact source files and instance main methods, and flexible + * constructor bodies. + * * @since 25 * * @see * The Java Language Specification, Java SE 25 Edition + * @see + * JEP 511: Module Import Declarations + * @see + * JEP 512: Compact Source Files and Instance Main Methods + * @see + * JEP 513: Flexible Constructor Bodies */ RELEASE_25, + + /** + * The version introduced by the Java Platform, Standard Edition + * 26. + * + * @since 26 + * + * @see + * The Java Language Specification, Java SE 26 Edition + */ + RELEASE_26, ; // Reduce code churn when appending new constants // Note that when adding constants for newer releases, the @@ -465,7 +489,7 @@ public enum SourceVersion { * {@return the latest source version that can be modeled} */ public static SourceVersion latest() { - return RELEASE_25; + return RELEASE_26; } private static final SourceVersion latestSupported = getLatestSupported(); @@ -480,7 +504,7 @@ public static SourceVersion latest() { private static SourceVersion getLatestSupported() { int intVersion = Runtime.version().feature(); return (intVersion >= 11) ? - valueOf("RELEASE_" + Math.min(25, intVersion)): + valueOf("RELEASE_" + Math.min(26, intVersion)): RELEASE_10; } 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 2ca3a1d988c..6bbf114c327 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * 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 javax.lang.model; +import java.io.Serial; + /** * Superclass of exceptions which indicate that an unknown kind of * entity was encountered. This situation can occur if the language @@ -39,6 +41,7 @@ */ public class UnknownEntityException extends RuntimeException { + @Serial private static final long serialVersionUID = 269L; /** 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 869235d88d3..6f672d014fb 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package javax.lang.model.element; +import java.io.Serial; + import javax.lang.model.UnknownEntityException; /** @@ -40,6 +42,7 @@ */ public class UnknownAnnotationValueException extends UnknownEntityException { + @Serial private static final long serialVersionUID = 269L; private transient AnnotationValue av; 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 7139573824a..4cec97d79f2 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package javax.lang.model.element; +import java.io.Serial; + import javax.lang.model.UnknownEntityException; /** @@ -39,6 +41,7 @@ */ public class UnknownDirectiveException extends UnknownEntityException { + @Serial private static final long serialVersionUID = 269L; private final transient ModuleElement.Directive directive; 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 bb1f1d495b6..723724cd4a3 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package javax.lang.model.element; +import java.io.Serial; + import javax.lang.model.UnknownEntityException; /** @@ -39,6 +41,7 @@ */ public class UnknownElementException extends UnknownEntityException { + @Serial private static final long serialVersionUID = 269L; private transient Element element; 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 61117bc2cc6..dcf336d305b 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,10 +25,11 @@ package javax.lang.model.type; -import java.io.ObjectInputStream; import java.io.IOException; -import javax.lang.model.element.Element; +import java.io.ObjectInputStream; +import java.io.Serial; +import javax.lang.model.element.Element; /** * Thrown when an application attempts to access the {@link Class} object @@ -40,7 +41,8 @@ */ public class MirroredTypeException extends MirroredTypesException { - private static final long serialVersionUID = 269; + @Serial + private static final long serialVersionUID = 269L; private transient TypeMirror type; // cannot be serialized @@ -72,6 +74,7 @@ public TypeMirror getTypeMirror() { * deserialization * @throws IOException for an IO problem during deserialization */ + @Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); 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 9fa3c5e8c3c..b89654a453c 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,14 @@ package javax.lang.model.type; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serial; import java.util.ArrayList; -import java.util.List; import java.util.Collections; -import java.io.ObjectInputStream; -import java.io.IOException; -import javax.lang.model.element.Element; +import java.util.List; +import javax.lang.model.element.Element; /** * Thrown when an application attempts to access a sequence of {@link @@ -43,7 +44,8 @@ */ public class MirroredTypesException extends RuntimeException { - private static final long serialVersionUID = 269; + @Serial + private static final long serialVersionUID = 269L; transient List types; // cannot be serialized @@ -87,6 +89,7 @@ public List getTypeMirrors() { * deserialization * @throws IOException for an IO problem during deserialization */ + @Serial private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); 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 dac3fecf86c..9127e2a4efe 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package javax.lang.model.type; +import java.io.Serial; + import javax.lang.model.UnknownEntityException; /** @@ -39,6 +41,7 @@ */ public class UnknownTypeException extends UnknownEntityException { + @Serial private static final long serialVersionUID = 269L; private transient TypeMirror type; 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 4d36781c584..2b2f80358b0 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ * @see AbstractAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) public abstract class AbstractAnnotationValueVisitor14 extends AbstractAnnotationValueVisitor9 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java index 4afcc7fbf1d..59d1eb28282 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @see AbstractAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractAnnotationValueVisitorPreview extends AbstractAnnotationValueVisitor14 { diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java index 3a57ef18c5b..b624bb9f999 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ * @see AbstractElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) public abstract class AbstractElementVisitor14 extends AbstractElementVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java index b9642b203fe..761916a1434 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ * @see AbstractElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractElementVisitorPreview extends AbstractElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java index eb96f4abb99..1860cd09ac5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * @see AbstractTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) public abstract class AbstractTypeVisitor14 extends AbstractTypeVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java index 74b007356d4..6b701262a4f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ * @see AbstractTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractTypeVisitorPreview extends AbstractTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java index d7941d6e153..cb0e1cfbc9f 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ * @see ElementKindVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) public class ElementKindVisitor14 extends ElementKindVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java index 868e89c23eb..0f436e6d1e5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,7 @@ * @see ElementKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementKindVisitorPreview extends ElementKindVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java index e0c05ab228e..946cf97b092 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -77,7 +77,7 @@ * @see ElementScanner9 * @since 16 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) public class ElementScanner14 extends ElementScanner9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java index 6d80aa8c661..a9d8e7c1f3f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,7 @@ * @see ElementScanner14 * @since 23 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementScannerPreview extends ElementScanner14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java index 7f0b493572e..5d97674c53d 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -778,6 +778,12 @@ default TypeElement getOutermostTypeElement(Element e) { * elements.getTypeElement("I")); * } * + * @apiNote This method examines the method's name, signature, subclass relationship, and accessibility + * in determining whether one method overrides another, as specified in JLS {@jls 8.4.8.1}. + * In addition, an implementation may have stricter checks including method modifiers, return types and + * exception types as described in JLS {@jls 8.4.8.1} and {@jls 8.4.8.3}. + * Note that such additional compile-time checks are not guaranteed and may vary between implementations. + * * @param overrider the first method, possible overrider * @param overridden the second method, possibly being overridden * @param type the class or interface of which the first method is a member 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 4682e2a7ee8..9320e18d5dd 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,7 +52,7 @@ * @see SimpleAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) public class SimpleAnnotationValueVisitor14 extends SimpleAnnotationValueVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java index a477f33017c..01509c0c4a5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ * @see SimpleAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleAnnotationValueVisitorPreview extends SimpleAnnotationValueVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java index db97e59152f..dff1731d3c9 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ * @see SimpleElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) public class SimpleElementVisitor14 extends SimpleElementVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java index 0d9914f3852..c3896a794c0 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ * @see SimpleElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleElementVisitorPreview extends SimpleElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java index 3f962137987..d06f5d673d3 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ * @see SimpleTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) public class SimpleTypeVisitor14 extends SimpleTypeVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java index 13a0ad41d7e..11e2e8a50d5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ * @see SimpleTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleTypeVisitorPreview extends SimpleTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java index 57d43e77500..295ceb200b8 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,7 @@ * @see TypeKindVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) public class TypeKindVisitor14 extends TypeKindVisitor9 { /** * Constructor for concrete subclasses to call; uses {@code null} diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java index 3ae19353a0b..c0ca3a0450a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,7 @@ * @see TypeKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_25) +@SupportedSourceVersion(RELEASE_26) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class TypeKindVisitorPreview extends TypeKindVisitor14 { /** diff --git a/src/java.desktop/macosx/classes/apple/laf/JRSUIConstants.java b/src/java.desktop/macosx/classes/apple/laf/JRSUIConstants.java index 1e98cb19ba4..9da55002b72 100644 --- a/src/java.desktop/macosx/classes/apple/laf/JRSUIConstants.java +++ b/src/java.desktop/macosx/classes/apple/laf/JRSUIConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -194,6 +194,14 @@ public static class State extends Property { @Native private static final byte _pressed = 4; public static final State PRESSED = new State(_pressed); @Native private static final byte _pulsed = 5; + /** + * This identifies the default button in a window/dialog. + * The name PULSED has become misleading over time. + * The default button used to continually pulse up until + * Mac OS 10.9, but now there is no pulsing animation. + * We still need this State constant to render default + * buttons correctly, though. + */ public static final State PULSED = new State(_pulsed); @Native private static final byte _rollover = 6; public static final State ROLLOVER = new State(_rollover); diff --git a/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java b/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java index c16f956f114..cfe3b916161 100644 --- a/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java +++ b/src/java.desktop/macosx/classes/apple/laf/JRSUIControl.java @@ -324,7 +324,7 @@ private void sync() { @Override public int hashCode() { - int bits = (int)(currentEncodedProperties ^ (currentEncodedProperties >>> 32)); + int bits = Long.hashCode(currentEncodedProperties); bits ^= nativeMap.hashCode(); bits ^= changes.hashCode(); return bits; diff --git a/src/java.desktop/macosx/classes/apple/laf/JRSUIState.java b/src/java.desktop/macosx/classes/apple/laf/JRSUIState.java index 867f93da73c..116e85c3509 100644 --- a/src/java.desktop/macosx/classes/apple/laf/JRSUIState.java +++ b/src/java.desktop/macosx/classes/apple/laf/JRSUIState.java @@ -90,7 +90,7 @@ public boolean is(Property property) { @Override public int hashCode() { - return (int)(encodedState ^ (encodedState >>> 32)) ^ getClass().hashCode(); + return Long.hashCode(encodedState) ^ getClass().hashCode(); } public static class AnimationFrameState extends JRSUIState { @@ -183,8 +183,7 @@ public boolean equals(final Object obj) { @Override public int hashCode() { - final long bits = Double.doubleToRawLongBits(value); - return super.hashCode() ^ (int)bits ^ (int)(bits >>> 32); + return super.hashCode() ^ Double.hashCode(value); } } @@ -258,7 +257,7 @@ public boolean equals(final Object obj) { @Override public int hashCode() { final long bits = Double.doubleToRawLongBits(thumbProportion) ^ Double.doubleToRawLongBits(thumbStart); - return super.hashCode() ^ (int)bits ^ (int)(bits >>> 32); + return super.hashCode() ^ Long.hashCode(bits); } } } 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 1d11a0a8d96..60ceb4893a8 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, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -202,12 +202,6 @@ public Dynamic(final Dynamic other) { super(other); } - protected State getButtonState(final AbstractButton b, final ButtonModel model) { - final State state = super.getButtonState(b, model); - painter.state.set(state == State.PULSED ? Animating.YES : Animating.NO); - return state; - } - public Insets getContentInsets(final AbstractButton b, final int width, final int height) { final Size size = AquaUtilControlSize.getUserSizeFrom(b); final Widget style = getStyleForSize(b, size, width, height); 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 063923ff807..17818d09121 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,8 +58,6 @@ import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.Border; -import javax.swing.event.AncestorEvent; -import javax.swing.event.AncestorListener; import javax.swing.plaf.ButtonUI; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.RootPaneUI; @@ -225,8 +223,6 @@ protected void installListeners(final AbstractButton b) { // put the listener in the button's client properties so that // we can get at it later b.putClientProperty(this, listener); - - b.addAncestorListener(listener); } installHierListener(b); AquaUtilControlSize.addSizePropertyListener(b); @@ -252,11 +248,7 @@ protected void uninstallKeyboardActions(final AbstractButton b) { protected void uninstallListeners(final AbstractButton b) { super.uninstallListeners(b); - final AquaButtonListener listener = (AquaButtonListener)b.getClientProperty(this); b.putClientProperty(this, null); - if (listener != null) { - b.removeAncestorListener(listener); - } uninstallHierListener(b); AquaUtilControlSize.removeSizePropertyListener(b); } @@ -591,7 +583,7 @@ public void hierarchyChanged(final HierarchyEvent e) { } } - class AquaButtonListener extends BasicButtonListener implements AncestorListener { + class AquaButtonListener extends BasicButtonListener { protected final AbstractButton b; public AquaButtonListener(final AbstractButton b) { @@ -658,27 +650,5 @@ public void propertyChange(final PropertyChangeEvent e) { } } } - - public void ancestorMoved(final AncestorEvent e) {} - - public void ancestorAdded(final AncestorEvent e) { - updateDefaultButton(); - } - - public void ancestorRemoved(final AncestorEvent e) { - updateDefaultButton(); - } - - protected void updateDefaultButton() { - if (!(b instanceof JButton)) return; - if (!((JButton)b).isDefaultButton()) return; - - final JRootPane rootPane = b.getRootPane(); - if (rootPane == null) return; - - final RootPaneUI ui = rootPane.getUI(); - if (!(ui instanceof AquaRootPaneUI)) return; - ((AquaRootPaneUI)ui).updateDefaultButton(rootPane); - } } } 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 bdb440bf4d2..90b02fb6dad 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileChooserUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileChooserUI.java @@ -1192,6 +1192,9 @@ public Component getTableCellRendererComponent(final JTable list, setText(fc.getName(file)); setIcon(fc.getIcon(file)); setEnabled(isSelectableInList(file)); + + putClientProperty("html.disable", getFileChooser().getClientProperty("html.disable")); + return this; } } @@ -1256,6 +1259,9 @@ public Component getListCellRendererComponent(final JList list, final JFileChooser chooser = getFileChooser(); setText(chooser.getName(directory)); setIcon(chooser.getIcon(directory)); + + putClientProperty("html.disable", getFileChooser().getClientProperty("html.disable")); + return this; } }; 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 2b4e1bb0867..6bd472b7605 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, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,17 +40,10 @@ /** * From AquaRootPaneUI.java * - * The JRootPane manages the default button. There can be only one active rootpane, - * and one default button, so we need only one timer - * * AquaRootPaneUI is a singleton object */ public class AquaRootPaneUI extends BasicRootPaneUI implements AncestorListener, WindowListener, ContainerListener { private static final RecyclableSingleton sRootPaneUI = new RecyclableSingletonFromDefaultConstructor(AquaRootPaneUI.class); - - static final int kDefaultButtonPaintDelayBetweenFrames = 50; - JButton fCurrentDefaultButton = null; - Timer fTimer = null; static final boolean sUseScreenMenuBar = AquaMenuBarUI.getScreenMenuBarProperty(); public static ComponentUI createUI(final JComponent c) { @@ -61,10 +54,6 @@ public void installUI(final JComponent c) { super.installUI(c); c.addAncestorListener(this); - if (c.isShowing() && c.isEnabled()) { - updateDefaultButton((JRootPane)c); - } - // for REGR: Realtime LAF updates no longer work // // because the JFrame parent has a LAF background set (why without a UI element I don't know!) @@ -92,7 +81,6 @@ public void installUI(final JComponent c) { } public void uninstallUI(final JComponent c) { - stopTimer(); c.removeAncestorListener(this); if (sUseScreenMenuBar) { @@ -161,73 +149,6 @@ public void componentRemoved(final ContainerEvent e) { } } - /** - * Invoked when a property changes on the root pane. If the event - * indicates the {@code defaultButton} has changed, this will - * update the animation. - * If the enabled state changed, it will start or stop the animation - */ - public void propertyChange(final PropertyChangeEvent e) { - super.propertyChange(e); - - final String prop = e.getPropertyName(); - if ("defaultButton".equals(prop) || "temporaryDefaultButton".equals(prop)) { - // Change the animating button if this root is showing and enabled - // otherwise do nothing - someone else may be active - final JRootPane root = (JRootPane)e.getSource(); - - if (root.isShowing() && root.isEnabled()) { - updateDefaultButton(root); - } - } else if ("enabled".equals(prop) || AquaFocusHandler.FRAME_ACTIVE_PROPERTY.equals(prop)) { - final JRootPane root = (JRootPane)e.getSource(); - if (root.isShowing()) { - if (((Boolean)e.getNewValue()).booleanValue()) { - updateDefaultButton((JRootPane)e.getSource()); - } else { - stopTimer(); - } - } - } - } - - synchronized void stopTimer() { - if (fTimer != null) { - fTimer.stop(); - fTimer = null; - } - } - - synchronized void updateDefaultButton(final JRootPane root) { - final JButton button = root.getDefaultButton(); - //System.err.println("in updateDefaultButton button = " + button); - fCurrentDefaultButton = button; - stopTimer(); - if (button != null) { - fTimer = new Timer(kDefaultButtonPaintDelayBetweenFrames, new DefaultButtonPainter(root)); - fTimer.start(); - } - } - - class DefaultButtonPainter implements ActionListener { - JRootPane root; - - public DefaultButtonPainter(final JRootPane root) { - this.root = root; - } - - public void actionPerformed(final ActionEvent e) { - final JButton defaultButton = root.getDefaultButton(); - if ((defaultButton != null) && defaultButton.isShowing()) { - if (defaultButton.isEnabled()) { - defaultButton.repaint(); - } - } else { - stopTimer(); - } - } - } - /** * This is sort of like viewDidMoveToWindow:. When the root pane is put into a window * this method gets called for the notification. @@ -249,18 +170,6 @@ public void ancestorAdded(final AncestorEvent event) { owningWindow.removeWindowListener(this); owningWindow.addWindowListener(this); } - - // The root pane has been added to the hierarchy. If it's enabled update the default - // button to start the throbbing. Since the UI is a singleton make sure the root pane - // we are checking has a default button before calling update otherwise we will stop - // throbbing the current default button. - final JComponent comp = event.getComponent(); - if (comp instanceof JRootPane) { - final JRootPane rp = (JRootPane)comp; - if (rp.isEnabled() && rp.getDefaultButton() != null) { - updateDefaultButton((JRootPane)comp); - } - } } /** diff --git a/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java index 3c09758e87f..0ca85104817 100644 --- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsConfig.java @@ -41,7 +41,8 @@ public abstract class CGraphicsConfig extends GraphicsConfiguration private final CGraphicsDevice device; private ColorModel colorModel; - private final SurfaceManager.ProxyCache surfaceDataProxyCache = new SurfaceManager.ProxyCache(); + private final SurfaceManager.ProxyCache surfaceDataProxyCache = + new SurfaceManager.ProxyCache(); protected CGraphicsConfig(CGraphicsDevice device) { this.device = device; diff --git a/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java b/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java index fe4431e3091..e11dabc7a10 100644 --- a/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java +++ b/src/java.desktop/macosx/classes/sun/awt/CGraphicsEnvironment.java @@ -37,9 +37,7 @@ import java.util.ListIterator; import java.util.Map; -import sun.java2d.MacosxSurfaceManagerFactory; import sun.java2d.SunGraphicsEnvironment; -import sun.java2d.SurfaceManagerFactory; /** * This is an implementation of a GraphicsEnvironment object for the default @@ -70,8 +68,6 @@ public static void init() { } static { // Load libraries and initialize the Toolkit. Toolkit.getDefaultToolkit(); - // Install the correct surface manager factory. - SurfaceManagerFactory.setInstance(new MacosxSurfaceManagerFactory()); } /** diff --git a/src/java.desktop/macosx/classes/sun/font/CCharToGlyphMapper.java b/src/java.desktop/macosx/classes/sun/font/CCharToGlyphMapper.java index a919fcbbd88..7ce12b7d4f7 100644 --- a/src/java.desktop/macosx/classes/sun/font/CCharToGlyphMapper.java +++ b/src/java.desktop/macosx/classes/sun/font/CCharToGlyphMapper.java @@ -27,6 +27,9 @@ import java.util.HashMap; +import static sun.font.FontUtilities.isDefaultIgnorable; +import static sun.font.FontUtilities.isIgnorableWhitespace; + public class CCharToGlyphMapper extends CharToGlyphMapper { private static native int countGlyphs(final long nativeFontPtr); @@ -47,12 +50,12 @@ public int getNumGlyphs() { } public boolean canDisplay(char ch) { - int glyph = charToGlyph(ch); + int glyph = charToGlyph(ch, false); return glyph != missingGlyph; } public boolean canDisplay(int cp) { - int glyph = charToGlyph(cp); + int glyph = charToGlyph(cp, false); return glyph != missingGlyph; } @@ -89,17 +92,17 @@ public synchronized boolean charsToGlyphsNS(int count, } public synchronized int charToGlyph(char unicode) { - int glyph = cache.get(unicode); + return charToGlyph(unicode, false); + } + + private int charToGlyph(char unicode, boolean raw) { + int glyph = cache.get(unicode, raw); if (glyph != 0) return glyph; - if (FontUtilities.isDefaultIgnorable(unicode)) { - glyph = INVISIBLE_GLYPH_ID; - } else { - final char[] unicodeArray = new char[] { unicode }; - final int[] glyphArray = new int[1]; - nativeCharsToGlyphs(fFont.getNativeFontPtr(), 1, unicodeArray, glyphArray); - glyph = glyphArray[0]; - } + final char[] unicodeArray = new char[] { unicode }; + final int[] glyphArray = new int[1]; + nativeCharsToGlyphs(fFont.getNativeFontPtr(), 1, unicodeArray, glyphArray); + glyph = glyphArray[0]; cache.put(unicode, glyph); @@ -107,26 +110,34 @@ public synchronized int charToGlyph(char unicode) { } public synchronized int charToGlyph(int unicode) { + return charToGlyph(unicode, false); + } + + public synchronized int charToGlyphRaw(int unicode) { + return charToGlyph(unicode, true); + } + + private int charToGlyph(int unicode, boolean raw) { if (unicode >= 0x10000) { int[] glyphs = new int[2]; char[] surrogates = new char[2]; int base = unicode - 0x10000; surrogates[0] = (char)((base >>> 10) + HI_SURROGATE_START); surrogates[1] = (char)((base % 0x400) + LO_SURROGATE_START); - charsToGlyphs(2, surrogates, glyphs); + cache.get(2, surrogates, glyphs, raw); return glyphs[0]; } else { - return charToGlyph((char)unicode); + return charToGlyph((char) unicode, raw); } } public synchronized void charsToGlyphs(int count, char[] unicodes, int[] glyphs) { - cache.get(count, unicodes, glyphs); + cache.get(count, unicodes, glyphs, false); } public synchronized void charsToGlyphs(int count, int[] unicodes, int[] glyphs) { for (int i = 0; i < count; i++) { - glyphs[i] = charToGlyph(unicodes[i]); + glyphs[i] = charToGlyph(unicodes[i], false); } } @@ -153,7 +164,11 @@ private class Cache { firstLayerCache[1] = 1; } - public synchronized int get(final int index) { + public synchronized int get(final int index, final boolean raw) { + if (isIgnorableWhitespace(index) || (isDefaultIgnorable(index) && !raw)) { + return INVISIBLE_GLYPH_ID; + } + if (index < FIRST_LAYER_SIZE) { // catch common glyphcodes return firstLayerCache[index]; @@ -224,7 +239,7 @@ public void put(final int index, final int value) { } } - public synchronized void get(int count, char[] indices, int[] values) + public synchronized void get(int count, char[] indices, int[] values, boolean raw) { // "missed" is the count of 'char' that are not mapped. // Surrogates count for 2. @@ -246,16 +261,13 @@ public synchronized void get(int count, char[] indices, int[] values) } } - final int value = get(code); + final int value = get(code, raw); if (value != 0 && value != -1) { values[i] = value; if (code >= 0x10000) { values[i+1] = INVISIBLE_GLYPH_ID; i++; } - } else if (FontUtilities.isDefaultIgnorable(code)) { - values[i] = INVISIBLE_GLYPH_ID; - put(code, INVISIBLE_GLYPH_ID); } else { values[i] = 0; put(code, -1); diff --git a/src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java b/src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java deleted file mode 100644 index 93fac3fb22a..00000000000 --- a/src/java.desktop/macosx/classes/sun/java2d/MacosxSurfaceManagerFactory.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 - * 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.java2d; - -import sun.awt.image.SunVolatileImage; -import sun.awt.image.VolatileSurfaceManager; -import sun.awt.CGraphicsDevice; -import sun.java2d.metal.MTLVolatileSurfaceManager; -import sun.java2d.opengl.CGLVolatileSurfaceManager; - -/** - * This is a factory class with static methods for creating a - * platform-specific instance of a particular SurfaceManager. Each platform - * (Windows, Unix, etc.) has its own specialized SurfaceManagerFactory. - */ -public class MacosxSurfaceManagerFactory extends SurfaceManagerFactory { - - /** - * Creates a new instance of a VolatileSurfaceManager given any - * arbitrary SunVolatileImage. An optional context Object can be supplied - * as a way for the caller to pass pipeline-specific context data to - * the VolatileSurfaceManager (such as a backbuffer handle, for example). - * - * For Mac OS X, this method returns either an CGL/MTL-specific - * VolatileSurfaceManager based on the GraphicsConfiguration - * under which the SunVolatileImage was created. - */ - public VolatileSurfaceManager createVolatileManager(SunVolatileImage vImg, - Object context) - { - return CGraphicsDevice.usingMetalPipeline() ? new MTLVolatileSurfaceManager(vImg, context) : - new CGLVolatileSurfaceManager(vImg, context); - } -} diff --git a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java index 82adac72c03..e4afec42482 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java @@ -29,6 +29,8 @@ import sun.awt.CGraphicsDevice; import sun.awt.image.OffScreenImage; import sun.awt.image.SunVolatileImage; +import sun.awt.image.SurfaceManager; +import sun.awt.image.VolatileSurfaceManager; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; import sun.java2d.Surface; @@ -67,7 +69,7 @@ import static sun.java2d.metal.MTLContext.MTLContextCaps.CAPS_EXT_BIOP_SHADER; public final class MTLGraphicsConfig extends CGraphicsConfig - implements AccelGraphicsConfig + implements AccelGraphicsConfig, SurfaceManager.Factory { private static ImageCapabilities imageCaps = new MTLImageCaps(); @@ -372,4 +374,10 @@ public int getMaxTextureHeight() { return Math.max(maxTextureSize / getDevice().getScaleFactor(), getBounds().height); } + + @Override + public VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context) { + return new MTLVolatileSurfaceManager(image, context); + } } diff --git a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java index ee9b0aec3a0..6022d516bf9 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/java2d/opengl/CGLGraphicsConfig.java @@ -46,6 +46,8 @@ import sun.awt.CGraphicsDevice; import sun.awt.image.OffScreenImage; import sun.awt.image.SunVolatileImage; +import sun.awt.image.SurfaceManager; +import sun.awt.image.VolatileSurfaceManager; import sun.java2d.Disposer; import sun.java2d.DisposerRecord; import sun.java2d.Surface; @@ -386,4 +388,10 @@ public int getMaxTextureHeight() { return Math.max(maxTextureSize / getDevice().getScaleFactor(), getBounds().height); } + + @Override + public VolatileSurfaceManager createVolatileManager(SunVolatileImage image, + Object context) { + return new CGLVolatileSurfaceManager(image, context); + } } 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 417750507aa..0017c39bfda 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,9 +60,11 @@ import javax.swing.JComponent; import javax.swing.JEditorPane; import javax.swing.JLabel; +import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JTextArea; import javax.swing.JList; +import javax.swing.JPopupMenu; import javax.swing.JTree; import javax.swing.KeyStroke; @@ -856,6 +858,34 @@ public Accessible call() throws Exception { }, c); } + private static Accessible getCurrentAccessiblePopupMenu(Accessible a, Component c) { + if (a == null) return null; + + return invokeAndWait(new Callable() { + @Override + public Accessible call() throws Exception { + return traversePopupMenu(a); + } + }, c); + } + + private static Accessible traversePopupMenu(Accessible a) { + // a is root level popupmenu + AccessibleContext ac = a.getAccessibleContext(); + if (ac != null) { + for (int i = 0; i < ac.getAccessibleChildrenCount(); i++) { + Accessible child = ac.getAccessibleChild(i); + if (child instanceof JMenu subMenu) { + JPopupMenu popup = subMenu.getPopupMenu(); + if (popup.isVisible()) { + return traversePopupMenu((Accessible) popup); + } + } + } + } + return a; + } + @Native private static final int JAVA_AX_ROWS = 1; @Native private static final int JAVA_AX_COLS = 2; 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 cb7333c79d6..1ca94eb3f51 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import javax.print.*; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.standard.Chromaticity; import javax.print.attribute.standard.Copies; import javax.print.attribute.standard.Destination; import javax.print.attribute.standard.Media; @@ -73,6 +74,8 @@ public final class CPrinterJob extends RasterPrinterJob { private Throwable printerAbortExcpn; + private boolean monochrome = false; + // This is the NSPrintInfo for this PrinterJob. Protect multi thread // access to it. It is used by the pageDialog, jobDialog, and printLoop. // This way the state of these items is shared across these calls. @@ -212,6 +215,11 @@ protected void setAttributes(PrintRequestAttributeSet attributes) throws Printer setPageRange(-1, -1); } } + + PrintService service = getPrintService(); + Chromaticity chromaticity = (Chromaticity)attributes.get(Chromaticity.class); + monochrome = chromaticity == Chromaticity.MONOCHROME && service != null && + service.isAttributeCategorySupported(Chromaticity.class); } private void setPageRangeAttribute(int from, int to, boolean isRangeSet) { @@ -788,6 +796,9 @@ private void printToPathGraphics( final PeekGraphics graphics, // Always an a Graphics2D pathGraphics = new CPrinterGraphics(delegate, printerJob); // Just stores delegate into an ivar Rectangle2D pageFormatArea = getPageFormatArea(page); initPrinterGraphics(pathGraphics, pageFormatArea); + if (monochrome) { + pathGraphics = new GrayscaleProxyGraphics2D(pathGraphics, printerJob); + } painter.print(pathGraphics, FlipPageFormat.getOriginal(page), pageIndex); delegate.dispose(); delegate = null; 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 5dba06cb612..036da04a7cb 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package sun.lwawt.macosx; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Rectangle; import java.awt.peer.RobotPeer; @@ -63,7 +65,41 @@ public void mouseMove(int x, int y) { mouseLastX = x; mouseLastY = y; - mouseEvent(mouseLastX, mouseLastY, mouseButtonsState, true, true); + int leastDiff = Integer.MAX_VALUE; + int finX = x; + int finY = y; + + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] gs = ge.getScreenDevices(); + Rectangle[] allScreenBounds = new Rectangle[gs.length]; + + for (int i = 0; i < gs.length; i++) { + allScreenBounds[i] = gs[i].getDefaultConfiguration().getBounds(); + } + + for (Rectangle screenBounds : allScreenBounds) { + Point cP = calcClosestPoint(x, y, screenBounds); + + int currXDiff = Math.abs(x - cP.x); + int currYDiff = Math.abs(y - cP.y); + int currDiff = (int) Math.round(Math.hypot(currXDiff, currYDiff)); + + if (currDiff == 0) { + mouseEvent(mouseLastX, mouseLastY, mouseButtonsState, true, true); + return; + } if (currDiff < leastDiff) { + finX = cP.x; + finY = cP.y; + leastDiff = currDiff; + } + } + + mouseEvent(finX, finY, mouseButtonsState, true, true); + } + + private Point calcClosestPoint(int x, int y, Rectangle screenBounds) { + return new Point(Math.min(Math.max(x, screenBounds.x), screenBounds.x + screenBounds.width - 1), + Math.min(Math.max(y, screenBounds.y), screenBounds.y + screenBounds.height - 1)); } /** diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/ApplicationDelegate.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/ApplicationDelegate.m index 4d8f1c765e6..b256c4121d4 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/ApplicationDelegate.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/ApplicationDelegate.m @@ -43,6 +43,11 @@ // The following is a AWT convention? #define PREFERENCES_TAG 42 +// Custom event that is provided by AWT to allow libraries like +// JavaFX to forward native events to AWT even if AWT runs in +// embedded mode. +static NSString* awtEmbeddedEvent = @"AWTEmbeddedEvent"; + static void addMenuItem(NSMenuItem* menuItem, NSInteger index) { AWT_ASSERT_APPKIT_THREAD; @@ -125,6 +130,14 @@ + (ApplicationDelegate *)sharedDelegate { isApplicationOwner = YES; } } + + if (!isApplicationOwner) { + // Register embedded event listener + NSNotificationCenter *ctr = [NSNotificationCenter defaultCenter]; + Class clz = [ApplicationDelegate class]; + [ctr addObserver:clz selector:@selector(_embeddedEvent:) name:awtEmbeddedEvent object:nil]; + } + checked = YES; if (!shouldInstall) { [ThreadUtilities setApplicationOwner:NO]; @@ -290,11 +303,16 @@ - (void)dealloc { GET_CLASS_RETURN(sjc_AppEventHandler, "com/apple/eawt/_AppEventHandler", ret); - (void)_handleOpenURLEvent:(NSAppleEventDescriptor *)openURLEvent withReplyEvent:(NSAppleEventDescriptor *)replyEvent { -AWT_ASSERT_APPKIT_THREAD; if (!fHandlesURLTypes) return; NSString *url = [[openURLEvent paramDescriptorForKeyword:keyDirectObject] stringValue]; + [ApplicationDelegate _openURL:url]; + + [replyEvent insertDescriptor:[NSAppleEventDescriptor nullDescriptor] atIndex:0]; +} ++ (void)_openURL:(NSString *)url { +AWT_ASSERT_APPKIT_THREAD; //fprintf(stderr,"jm_handleOpenURL\n"); JNIEnv *env = [ThreadUtilities getJNIEnv]; jstring jURL = NSStringToJavaString(env, url); @@ -303,8 +321,6 @@ - (void)_handleOpenURLEvent:(NSAppleEventDescriptor *)openURLEvent withReplyEven (*env)->CallStaticVoidMethod(env, sjc_AppEventHandler, jm_handleOpenURI, jURL); CHECK_EXCEPTION(); (*env)->DeleteLocalRef(env, jURL); - - [replyEvent insertDescriptor:[NSAppleEventDescriptor nullDescriptor] atIndex:0]; } // Helper for both open file and print file methods @@ -475,6 +491,15 @@ + (void)_systemDidWake { [self _notifyJava:com_apple_eawt__AppEventHandler_NOTIFY_SYSTEM_WAKE]; } ++ (void)_embeddedEvent:(NSNotification *)notification { + NSString *name = notification.userInfo[@"name"]; + + if ([name isEqualToString:@"openURL"]) { + NSString *url = notification.userInfo[@"url"]; + [ApplicationDelegate _openURL:url]; + } +} + + (void)_registerForNotification:(NSNumber *)notificationTypeNum { NSNotificationCenter *ctr = [[NSWorkspace sharedWorkspace] notificationCenter]; Class clz = [ApplicationDelegate class]; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m index e8b28d93068..90a147aa5a2 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,10 @@ */ #import "MenuAccessibility.h" +#import "ThreadUtilities.h" +#import "sun_lwawt_macosx_CAccessibility.h" + +static jclass sjc_CAccessibility = NULL; /* * Implementing a protocol that represents menus both as submenu and as a @@ -51,4 +55,31 @@ - (id _Nullable)accessibilityValue return NULL; } +/* + * Return all non-ignored children. + */ +- (NSArray *)accessibilityChildren { + JNIEnv *env = [ThreadUtilities getJNIEnv]; + GET_CACCESSIBILITY_CLASS_RETURN(nil); + DECLARE_STATIC_METHOD_RETURN(sjm_getCurrentAccessiblePopupMenu, sjc_CAccessibility, + "getCurrentAccessiblePopupMenu", + "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/Accessible;", nil); + jobject axComponent = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, + sjm_getCurrentAccessiblePopupMenu, + fAccessible, fComponent); + + CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent + withEnv:env withView:self->fView isCurrent:YES]; + + NSArray *children = [CommonComponentAccessibility childrenOfParent:currentElement + withEnv:env + withChildrenCode:sun_lwawt_macosx_CAccessibility_JAVA_AX_ALL_CHILDREN + allowIgnored:NO]; + + if ([children count] == 0) { + return nil; + } else { + return children; + } +} @end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.h b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.h index 83e868b37b7..ec477323f98 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ @property (readwrite, assign) int leftInset; @property (readwrite, assign) CVDisplayLinkRef displayLink; @property (readwrite, atomic) int displayLinkCount; +@property (readwrite, atomic) int displayLinkFailCount; - (id) initWithJavaLayer:(jobject)layer; diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.m index d7d75f16966..9f3ab974feb 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLLayer.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,8 @@ #import "MTLSurfaceData.h" #import "JNIUtilities.h" #define KEEP_ALIVE_INC 4 +#define CV_DISPLAYLINK_FAIL_DELAY 1.0 +#define MAX_DISPLAYLINK_FAIL_COUNT 5 @implementation MTLLayer @@ -44,11 +46,27 @@ @implementation MTLLayer @synthesize nextDrawableCount; @synthesize displayLink; @synthesize displayLinkCount; +@synthesize displayLinkFailCount; - (void) createDisplayLink { - CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); - CVDisplayLinkSetOutputCallback(displayLink, &displayLinkCallback, (__bridge void*)self); - self.displayLinkCount = 0; + CVReturn r = CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + if (r != kCVReturnSuccess) { + if (self.displayLinkFailCount >= MAX_DISPLAYLINK_FAIL_COUNT) { + J2dTraceLn(J2D_TRACE_ERROR, + "MTLLayer.createDisplayLink --- unable to create CVDisplayLink."); + self.displayLinkFailCount = 0; + return; + } + self.displayLinkFailCount++; + [self performSelector:@selector(createDisplayLink) + withObject:nil + afterDelay:CV_DISPLAYLINK_FAIL_DELAY]; + return; + } else { + CVDisplayLinkSetOutputCallback(displayLink, &displayLinkCallback, (__bridge void*)self); + self.displayLinkCount = 0; + self.displayLinkFailCount = 0; + } } - (id) initWithJavaLayer:(jobject)layer diff --git a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_Ports.cpp b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_Ports.cpp index bf4f2e143a0..ae0ffa5f2ca 100644 --- a/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_Ports.cpp +++ b/src/java.desktop/macosx/native/libjsound/PLATFORM_API_MacOSX_Ports.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,9 +124,12 @@ OSStatus ChangeListenerProc(AudioObjectID inObjectID, UInt32 inNumberAddresses, kAudioHardwarePropertyDevices, &size); if (err == noErr) { int count = size/sizeof(AudioDeviceID); - AudioDeviceID devices[count]; + AudioDeviceID *devices = (AudioDeviceID *) malloc(size); + if (!devices) { + break; + } err = GetAudioObjectProperty(kAudioObjectSystemObject, kAudioObjectPropertyScopeGlobal, - kAudioHardwarePropertyDevices, count*sizeof(AudioDeviceID), devices, 1); + kAudioHardwarePropertyDevices, size, devices, 1); if (err == noErr) { bool found = false; for (int j = 0; j < count; j++) { @@ -139,6 +142,7 @@ OSStatus ChangeListenerProc(AudioObjectID inObjectID, UInt32 inNumberAddresses, invalid = true; } } + free(devices); } break; case kAudioObjectPropertyOwnedObjects: @@ -148,9 +152,12 @@ OSStatus ChangeListenerProc(AudioObjectID inObjectID, UInt32 inNumberAddresses, kAudioObjectPropertyOwnedObjects, &size); if (err == noErr) { int count = size / sizeof(AudioObjectID); - AudioObjectID controlIDs[count]; + AudioObjectID *controlIDs = (AudioObjectID *) malloc(size); + if (!controlIDs) { + break; + } err = GetAudioObjectProperty(mixer->deviceID, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyOwnedObjects, count * sizeof(AudioObjectID), &controlIDs, 1); + kAudioObjectPropertyOwnedObjects, size, controlIDs, 1); if (err == noErr) { for (PortControl *ctrl = mixer->portControls; ctrl != NULL; ctrl = ctrl->next) { for (int i = 0; i < ctrl->controlCount; i++) { @@ -168,6 +175,7 @@ OSStatus ChangeListenerProc(AudioObjectID inObjectID, UInt32 inNumberAddresses, } } } + free(controlIDs); } } } @@ -229,6 +237,9 @@ INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* mixer void* PORT_Open(INT32 mixerIndex) { TRACE1("\n>>PORT_Open (mixerIndex=%d)\n", (int)mixerIndex); PortMixer *mixer = (PortMixer *)calloc(1, sizeof(PortMixer)); + if (!mixer) { + return nullptr; + } mixer->deviceID = deviceCache.GetDeviceID(mixerIndex); if (mixer->deviceID != 0) { @@ -480,16 +491,20 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { mixer->deviceControlCount = size / sizeof(AudioObjectID); TRACE1(" PORT_GetControls: detected %d owned objects\n", mixer->deviceControlCount); - AudioObjectID controlIDs[mixer->deviceControlCount]; + AudioObjectID *controlIDs = (AudioObjectID *) malloc(size); + if (!controlIDs) { + return; + } err = GetAudioObjectProperty(mixer->deviceID, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyOwnedObjects, sizeof(controlIDs), controlIDs, 1); + kAudioObjectPropertyOwnedObjects, size, controlIDs, 1); if (err) { OS_ERROR1(err, "PORT_GetControls (portIndex = %d) get OwnedObject values", portIndex); } else { mixer->deviceControls = (AudioControl *)calloc(mixer->deviceControlCount, sizeof(AudioControl)); if (mixer->deviceControls == NULL) { + free(controlIDs); return; } @@ -513,6 +528,7 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { control->controlID, FourCC2Str(control->classID), FourCC2Str(control->scope), control->channel); } } + free(controlIDs); } } @@ -524,10 +540,14 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { int totalChannels = GetChannelCount(mixer->deviceID, port->scope == kAudioDevicePropertyScopeOutput ? 1 : 0); // collect volume and mute controls - AudioControl* volumeControls[totalChannels+1]; // 0 - for master channel - memset(&volumeControls, 0, sizeof(AudioControl *) * (totalChannels+1)); - AudioControl* muteControls[totalChannels+1]; // 0 - for master channel - memset(&muteControls, 0, sizeof(AudioControl *) * (totalChannels+1)); + size_t totalAndMaster = totalChannels + 1; // 0 - for master channel + AudioControl **volumeControls = (AudioControl **) calloc(totalAndMaster, sizeof(AudioControl *)); + AudioControl **muteControls = (AudioControl **) calloc(totalAndMaster, sizeof(AudioControl *)); + if (!volumeControls || !muteControls) { + free(muteControls); + free(volumeControls); + return; + } for (int i=0; ideviceControlCount; i++) { AudioControl *control = &mixer->deviceControls[i]; @@ -626,6 +646,8 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { CFIndex length = CFStringGetLength(cfname) + 1; channelName = (char *)malloc(length); if (channelName == NULL) { + free(muteControls); + free(volumeControls); return; } CFStringGetCString(cfname, channelName, length, kCFStringEncodingUTF8); @@ -633,6 +655,8 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { } else { channelName = (char *)malloc(16); if (channelName == NULL) { + free(muteControls); + free(volumeControls); return; } snprintf(channelName, 16, "Ch %d", ch); @@ -657,7 +681,8 @@ void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) { } AddChangeListeners(mixer); - + free(muteControls); + free(volumeControls); TRACE1("<controlCount]; + Float32 *subVolumes = (Float32 *) malloc(control->controlCount * sizeof(Float32)); + if (!subVolumes) { + return DEFAULT_VOLUME_VALUE; + } Float32 maxVolume; switch (control->type) { case PortControl::Volume: if (!TestPortControlValidity(control)) { - return DEFAULT_VOLUME_VALUE; + result = DEFAULT_VOLUME_VALUE; + break; } if (!GetPortControlVolumes(control, subVolumes, &maxVolume)) { - return DEFAULT_VOLUME_VALUE; + result = DEFAULT_VOLUME_VALUE; + break; } result = maxVolume; break; case PortControl::Balance: if (!TestPortControlValidity(control)) { - return DEFAULT_BALANCE_VALUE; + result = DEFAULT_BALANCE_VALUE; + break; } // balance control always has 2 volume controls if (!GetPortControlVolumes(control, subVolumes, &maxVolume)) { - return DEFAULT_VOLUME_VALUE; + result = DEFAULT_VOLUME_VALUE; + break; } // calculate balance value if (subVolumes[0] > subVolumes[1]) { @@ -806,9 +838,10 @@ float PORT_GetFloatValue(void* controlIDV) { break; default: ERROR1("GetFloatValue requested for non-Float control (control-type == %d)\n", control->type); - return 0; + result = 0; + break; } - + free(subVolumes); TRACE1("<controlCount]; + Float32 *subVolumes = (Float32 *) malloc(sizeof(Float32) * control->controlCount); + if (!subVolumes) { + return; + } Float32 maxVolume; switch (control->type) { case PortControl::Volume: if (!GetPortControlVolumes(control, subVolumes, &maxVolume)) { - return; + break; } // update the values if (maxVolume > 0.001) { @@ -845,7 +881,7 @@ void PORT_SetFloatValue(void* controlIDV, float value) { case PortControl::Balance: // balance control always has 2 volume controls if (!GetPortControlVolumes(control, subVolumes, &maxVolume)) { - return; + break; } // calculate new values if (value < 0.0f) { @@ -861,8 +897,9 @@ void PORT_SetFloatValue(void* controlIDV, float value) { break; default: ERROR1("PORT_SetFloatValue requested for non-Float control (control-type == %d)\n", control->type); - return; + break; } + free(subVolumes); } #endif // USE_PORTS 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 25c95988393..496cbd3cd6b 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,10 +31,11 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Type; +import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.Deque; import java.util.List; import java.util.Set; @@ -105,13 +106,16 @@ static List get(Class type) { } } - // Add default methods inherited from interfaces - for (Class iface : type.getInterfaces()) { + // Add methods inherited from interfaces + Deque> ifaceDeque = new ArrayDeque<>(List.of(type.getInterfaces())); + while (!ifaceDeque.isEmpty()) { + Class iface = ifaceDeque.removeLast(); if (IGNORABLE_INTERFACES.contains(iface)) { continue; } + ifaceDeque.addAll(List.of(iface.getInterfaces())); for (Method method : iface.getMethods()) { - if (!Modifier.isAbstract(method.getModifiers())) { + if (!Modifier.isAbstract(method.getModifiers()) && !method.isBridge()) { (list = createIfNeeded(list)).add(method); } } diff --git a/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java b/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java index 833aeb7265c..f894a5ca1f2 100644 --- a/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java +++ b/src/java.desktop/share/classes/com/sun/beans/introspect/PropertyInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,7 +78,8 @@ private boolean initialize() { } if (!isInitedToIsGetter && this.readList != null) { for (MethodInfo info : this.readList) { - if ((this.read == null) || this.read.type.isAssignableFrom(info.type)) { + if ((this.read == null) || (!info.method.isDefault() + && this.read.type.isAssignableFrom(info.type))) { this.read = info; this.type = info.type; } @@ -91,6 +92,9 @@ private boolean initialize() { if (writeType == null) { this.write = info; writeType = info.type; + } else if (isParentOfIncoming(this.write, info)) { + this.write = info; + writeType = info.type; } else if (writeType.isAssignableFrom(info.type)) { if ((this.write == null) || this.write.type.isAssignableFrom(info.type)) { this.write = info; @@ -307,4 +311,16 @@ public static Map get(Class type) { ? Collections.unmodifiableMap(map) : Collections.emptyMap(); } + + private static boolean isParentOfIncoming(MethodInfo current, MethodInfo incoming) { + if (null == current) { + return false; + } + Class currentClass = current.method.getDeclaringClass(); + Class incomingClass = incoming.method.getDeclaringClass(); + if (currentClass == incomingClass) { + return false; + } + return currentClass.isAssignableFrom(incomingClass); + } } 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 0f1ecd0dc1e..342583aaa46 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 @@ -656,6 +656,9 @@ public Component getListCellRendererComponent(JList list, Object value, int i super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); setText(getFileChooser().getName((File) value)); setInheritsPopupMenu(true); + + putClientProperty("html.disable", getFileChooser().getClientProperty("html.disable")); + return this; } } @@ -668,6 +671,9 @@ public Component getListCellRendererComponent(JList list, Object value, int i super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); setText(getFileChooser().getName((File) value)); setInheritsPopupMenu(true); + + putClientProperty("html.disable", getFileChooser().getClientProperty("html.disable")); + return this; } } 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 d40c2cd8c31..bf2dbde39db 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ public final class DataPusher implements Runnable { private boolean looping; private Thread pushThread = null; + boolean daemonThread = false; private int wantedState; private int threadState; @@ -70,28 +71,39 @@ public final class DataPusher implements Runnable { private final int BUFFER_SIZE = 16384; public DataPusher(SourceDataLine sourceLine, AudioFormat format, byte[] audioData, int byteLength) { - this(sourceLine, format, null, audioData, byteLength); + this(sourceLine, format, null, audioData, byteLength, false); + } + + public DataPusher(SourceDataLine sourceLine, AudioFormat format, + byte[] audioData, int byteLength, boolean daemon) { + this(sourceLine, format, null, audioData, byteLength, daemon); } public DataPusher(SourceDataLine sourceLine, AudioInputStream ais) { - this(sourceLine, ais.getFormat(), ais, null, 0); + this(sourceLine, ais.getFormat(), ais, null, 0, false); } private DataPusher(final SourceDataLine source, final AudioFormat format, final AudioInputStream ais, final byte[] audioData, - final int audioDataByteLength) { + final int audioDataByteLength, + final boolean daemon) { this.source = source; this.format = format; this.ais = ais; this.audioDataByteLength = audioDataByteLength; this.audioData = audioData == null ? null : Arrays.copyOf(audioData, audioData.length); + this.daemonThread = daemon; } public synchronized void start() { start(false); } + public synchronized boolean isPlaying() { + return threadState == STATE_PLAYING; + } + public synchronized void start(boolean loop) { try { if (threadState == STATE_STOPPING) { @@ -109,7 +121,7 @@ public synchronized void start(boolean loop) { if (pushThread == null) { pushThread = JSSecurityManager.createThread(this, "DataPusher", // name - false, // daemon + daemonThread, // daemon -1, // priority true); // doStart } 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 00862ea9022..fa90f92f0ab 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ import java.applet.AudioClip; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; @@ -69,8 +71,10 @@ public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, L private AutoClosingClip clip = null; private boolean clipLooping = false; + private boolean clipPlaying = false; private DataPusher datapusher = null; + private boolean daemonThread = false; private Sequencer sequencer = null; private Sequence sequence = null; @@ -90,12 +94,21 @@ public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, L private static final long CLIP_THRESHOLD = 1048576; private static final int STREAM_BUFFER_SIZE = 1024; + public static JavaSoundAudioClip create(final File file) throws IOException { + JavaSoundAudioClip clip = new JavaSoundAudioClip(); + clip.daemonThread = true; // used only by javax.sound.SoundClip + try (FileInputStream stream = new FileInputStream(file)) { + clip.init(stream); + } + return clip; + } + public static JavaSoundAudioClip create(final URLConnection uc) { JavaSoundAudioClip clip = new JavaSoundAudioClip(); try { clip.init(uc.getInputStream()); } catch (final Exception ignored) { - // AudioClip will be no-op if some exception will occurred + // Playing the clip will be a no-op if an exception occured in inititialization. } return clip; } @@ -105,7 +118,7 @@ public static JavaSoundAudioClip create(final URL url) { try { clip.init(url.openStream()); } catch (final Exception ignored) { - // AudioClip will be no-op if some exception will occurred + // Playing the clip will be a no-op if an exception occurred in inititialization. } return clip; } @@ -128,7 +141,6 @@ private void init(InputStream in) throws IOException { } } } catch (UnsupportedAudioFileException e) { - // not an audio file try { MidiFileFormat mff = MidiSystem.getMidiFileFormat(bis); success = createSequencer(bis); @@ -138,6 +150,23 @@ private void init(InputStream in) throws IOException { } } + public synchronized boolean canPlay() { + return success; + } + + public synchronized boolean isPlaying() { + if (!canPlay()) { + return false; + } else if (clip != null) { + return clipPlaying; + } else if (datapusher != null) { + return datapusher.isPlaying(); + } else if (sequencer != null) { + return sequencer.isRunning(); + } + return false; + } + @Override public synchronized void play() { if (!success) { @@ -258,6 +287,16 @@ public synchronized void stop() { @Override public synchronized void update(LineEvent event) { + if (clip != null) { + if (clip == event.getSource()) { + if (event.getType() == LineEvent.Type.START) { + clipPlaying = true; + } else if ((event.getType() == LineEvent.Type.STOP) || + (event.getType() == LineEvent.Type.CLOSE)) { + clipPlaying = false; + } + } + } } // handle MIDI track end meta events for looping @@ -381,6 +420,7 @@ private boolean createClip() { } clip = (AutoClosingClip) line; clip.setAutoClosing(true); + clip.addLineListener(this); } catch (Exception e) { if (Printer.err) e.printStackTrace(); // fail silently @@ -403,7 +443,7 @@ private boolean createSourceDataLine() { return false; } SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info); - datapusher = new DataPusher(source, loadedAudioFormat, loadedAudio, loadedAudioByteLength); + datapusher = new DataPusher(source, loadedAudioFormat, loadedAudio, loadedAudioByteLength, daemonThread); } catch (Exception e) { if (Printer.err) e.printStackTrace(); // fail silently diff --git a/src/java.desktop/share/classes/java/awt/BorderLayout.java b/src/java.desktop/share/classes/java/awt/BorderLayout.java index c5bb016b944..f48e3119abc 100644 --- a/src/java.desktop/share/classes/java/awt/BorderLayout.java +++ b/src/java.desktop/share/classes/java/awt/BorderLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * 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,31 +89,39 @@ * the {@code CENTER} component may stretch both horizontally * and vertically to fill any space left over. *

                - * Here is an example of five buttons in an applet laid out using + * Here is an example of five buttons in a window laid out using * the {@code BorderLayout} layout manager: *

                - * Diagram of an applet
+ * <img src= + * Center, East, or South."> *

                - * The code for this applet is as follows: + * The code for this program is as follows: * - *


                - * import java.awt.*;
                - * import java.applet.Applet;
                + * {@snippet lang='java':
                + * import java.awt.BorderLayout;
                + * import java.awt.Button;
                + * import java.awt.EventQueue;
                + * import java.awt.Frame;
                  *
                - * public class buttonDir extends Applet {
                - *   public void init() {
                - *     setLayout(new BorderLayout());
                - *     add(new Button("North"), BorderLayout.NORTH);
                - *     add(new Button("South"), BorderLayout.SOUTH);
                - *     add(new Button("East"), BorderLayout.EAST);
                - *     add(new Button("West"), BorderLayout.WEST);
                - *     add(new Button("Center"), BorderLayout.CENTER);
                - *   }
                + * public class BorderLayoutExample {
                + *
                + *     public static void main(String[] args) throws Exception {
                + *         EventQueue.invokeAndWait(() -> {
                + *             Frame frame = new Frame("BorderLayout");
                + *             frame.setLayout(new BorderLayout());
                + *             frame.add(new Button("North"), BorderLayout.NORTH);
                + *             frame.add(new Button("South"), BorderLayout.SOUTH);
                + *             frame.add(new Button("East"), BorderLayout.EAST);
                + *             frame.add(new Button("West"), BorderLayout.WEST);
                + *             frame.add(new Button("Center"), BorderLayout.CENTER);
                + *             frame.setSize(300, 300);
                + *             frame.setVisible(true);
                + *         });
                + *     }
                + * }
                  * }
                - * 

                * * @author Arthur van Hoff * @see java.awt.Container#add(String, Component) diff --git a/src/java.desktop/share/classes/java/awt/Color.java b/src/java.desktop/share/classes/java/awt/Color.java index 3b67cd6ee3b..923afb91866 100644 --- a/src/java.desktop/share/classes/java/awt/Color.java +++ b/src/java.desktop/share/classes/java/awt/Color.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1195,11 +1195,10 @@ public ColorSpace getColorSpace() { * @see AffineTransform * @see RenderingHints */ - public synchronized PaintContext createContext(ColorModel cm, Rectangle r, - Rectangle2D r2d, - AffineTransform xform, - RenderingHints hints) { - return new ColorPaintContext(getRGB(), cm); + public PaintContext createContext(ColorModel cm, Rectangle r, + Rectangle2D r2d, AffineTransform xform, + RenderingHints hints) { + return new ColorPaintContext(getRGB()); } /** diff --git a/src/java.desktop/share/classes/java/awt/ColorPaintContext.java b/src/java.desktop/share/classes/java/awt/ColorPaintContext.java index 15e296cf525..426811bf19e 100644 --- a/src/java.desktop/share/classes/java/awt/ColorPaintContext.java +++ b/src/java.desktop/share/classes/java/awt/ColorPaintContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,61 +23,46 @@ * questions. */ - - package java.awt; import java.awt.image.ColorModel; import java.awt.image.Raster; import java.awt.image.WritableRaster; -import sun.awt.image.IntegerComponentRaster; import java.util.Arrays; -class ColorPaintContext implements PaintContext { - int color; - WritableRaster savedTile; +import sun.awt.image.IntegerComponentRaster; + +final class ColorPaintContext implements PaintContext { - protected ColorPaintContext(int color, ColorModel cm) { + private final int color; + private volatile WritableRaster savedTile; + + ColorPaintContext(int color) { this.color = color; } + @Override public void dispose() { } - /* - * Returns the RGB value representing the color in the default sRGB - * {@link ColorModel}. - * (Bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are - * blue). - * @return the RGB value of the color in the default sRGB - * {@code ColorModel}. - * @see java.awt.image.ColorModel#getRGBdefault - * @see #getRed - * @see #getGreen - * @see #getBlue - */ - int getRGB() { - return color; - } - + @Override public ColorModel getColorModel() { return ColorModel.getRGBdefault(); } - public synchronized Raster getRaster(int x, int y, int w, int h) { + @Override + public Raster getRaster(int x, int y, int w, int h) { WritableRaster t = savedTile; if (t == null || w > t.getWidth() || h > t.getHeight()) { t = getColorModel().createCompatibleWritableRaster(w, h); IntegerComponentRaster icr = (IntegerComponentRaster) t; Arrays.fill(icr.getDataStorage(), color); - // Note - markDirty is probably unnecessary since icr is brand new - icr.markDirty(); + // Note - icr.markDirty() is unnecessary since icr is brand new if (w <= 64 && h <= 64) { savedTile = t; } } - return t; } } diff --git a/src/java.desktop/share/classes/java/awt/FlowLayout.java b/src/java.desktop/share/classes/java/awt/FlowLayout.java index 18f46c54c0c..1e9f3dfd2a2 100644 --- a/src/java.desktop/share/classes/java/awt/FlowLayout.java +++ b/src/java.desktop/share/classes/java/awt/FlowLayout.java @@ -51,31 +51,36 @@ *
              • {@link #TRAILING TRAILING} * *

                - * For example, the following picture shows an applet using the flow + * For example, the following picture shows a window using the flow * layout manager (its default layout manager) to position three buttons: *

                - * Graphic of Layout for Three Buttons + * > *

                - * Here is the code for this applet: + * Here is the code for this program: * - *


                - * import java.awt.*;
                - * import java.applet.Applet;
                + * {@snippet lang='java':
                + * import java.awt.Button;
                + * import java.awt.EventQueue;
                + * import java.awt.FlowLayout;
                + * import java.awt.Frame;
                  *
                - * public class myButtons extends Applet {
                - *     Button button1, button2, button3;
                - *     public void init() {
                - *         button1 = new Button("Ok");
                - *         button2 = new Button("Open");
                - *         button3 = new Button("Close");
                - *         add(button1);
                - *         add(button2);
                - *         add(button3);
                + * public class FlowLayoutExample {
                + *
                + *     public static void main(String[] args) throws Exception {
                + *         EventQueue.invokeAndWait(() -> {
                + *             Frame frame = new Frame("FlowLayout");
                + *             frame.setLayout(new FlowLayout());
                + *             frame.add(new Button("OK"));
                + *             frame.add(new Button("Open"));
                + *             frame.add(new Button("Close"));
                + *             frame.pack();
                + *             frame.setVisible(true);
                + *         });
                  *     }
                  * }
                - * 

                + * } *

                * A flow layout lets each component assume its natural (preferred) size. * diff --git a/src/java.desktop/share/classes/java/awt/GridBagLayout.java b/src/java.desktop/share/classes/java/awt/GridBagLayout.java index 2dc65ab1265..03d6b8b2680 100644 --- a/src/java.desktop/share/classes/java/awt/GridBagLayout.java +++ b/src/java.desktop/share/classes/java/awt/GridBagLayout.java @@ -240,15 +240,15 @@ * left-to-right container and Figure 3 shows the layout for a horizontal, * right-to-left container. * - *

                + *
                *
                - *

                The preceding text describes this graphic (Figure 2). *

                Figure 2: Horizontal, Left-to-Right *

                *
                - *

                The preceding text describes this graphic (Figure 3). *

                Figure 3: Horizontal, Right-to-Left @@ -276,73 +276,66 @@ *

                * Here is the code that implements the example shown above: * - *


                - * import java.awt.*;
                - * import java.util.*;
                - * import java.applet.Applet;
                + * {@snippet lang='java':
                + * import java.awt.Button;
                + * import java.awt.EventQueue;
                + * import java.awt.Frame;
                + * import java.awt.GridBagConstraints;
                + * import java.awt.GridBagLayout;
                  *
                - * public class GridBagEx1 extends Applet {
                + * public class GridBagLayoutExample {
                  *
                - *     protected void makebutton(String name,
                - *                               GridBagLayout gridbag,
                - *                               GridBagConstraints c) {
                + *     private static void addButton(String name,
                + *                                   GridBagLayout gridbag,
                + *                                   GridBagConstraints c,
                + *                                   Frame frame) {
                  *         Button button = new Button(name);
                  *         gridbag.setConstraints(button, c);
                - *         add(button);
                + *         frame.add(button);
                  *     }
                  *
                - *     public void init() {
                - *         GridBagLayout gridbag = new GridBagLayout();
                - *         GridBagConstraints c = new GridBagConstraints();
                + *     public static void main(String[] args) throws Exception {
                + *         EventQueue.invokeAndWait(() -> {
                + *             Frame frame = new Frame("GridBagLayout");
                + *             GridBagLayout gridbag = new GridBagLayout();
                + *             GridBagConstraints c = new GridBagConstraints();
                + *             frame.setLayout(gridbag);
                  *
                - *         setFont(new Font("SansSerif", Font.PLAIN, 14));
                - *         setLayout(gridbag);
                + *             c.fill = GridBagConstraints.BOTH;
                + *             c.weightx = 1.0;
                + *             addButton("Button1", gridbag, c, frame);
                + *             addButton("Button2", gridbag, c, frame);
                + *             addButton("Button3", gridbag, c, frame);
                  *
                - *         c.fill = GridBagConstraints.BOTH;
                - *         c.weightx = 1.0;
                - *         makebutton("Button1", gridbag, c);
                - *         makebutton("Button2", gridbag, c);
                - *         makebutton("Button3", gridbag, c);
                + *             c.gridwidth = GridBagConstraints.REMAINDER; //end row
                + *             addButton("Button4", gridbag, c, frame);
                  *
                - *         c.gridwidth = GridBagConstraints.REMAINDER; //end row
                - *         makebutton("Button4", gridbag, c);
                + *             c.weightx = 0.0;                //reset to the default
                + *             addButton("Button5", gridbag, c, frame); //another row
                  *
                - *         c.weightx = 0.0;                //reset to the default
                - *         makebutton("Button5", gridbag, c); //another row
                + *             c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row
                + *             addButton("Button6", gridbag, c, frame);
                  *
                - *         c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row
                - *         makebutton("Button6", gridbag, c);
                + *             c.gridwidth = GridBagConstraints.REMAINDER; //end row
                + *             addButton("Button7", gridbag, c, frame);
                  *
                - *         c.gridwidth = GridBagConstraints.REMAINDER; //end row
                - *         makebutton("Button7", gridbag, c);
                + *             c.gridwidth = 1;                //reset to the default
                + *             c.gridheight = 2;
                + *             c.weighty = 1.0;
                + *             addButton("Button8", gridbag, c, frame);
                  *
                - *         c.gridwidth = 1;                //reset to the default
                - *         c.gridheight = 2;
                - *         c.weighty = 1.0;
                - *         makebutton("Button8", gridbag, c);
                + *             c.weighty = 0.0;                //reset to the default
                + *             c.gridwidth = GridBagConstraints.REMAINDER; //end row
                + *             c.gridheight = 1;               //reset to the default
                + *             addButton("Button9", gridbag, c, frame);
                + *             addButton("Button10", gridbag, c, frame);
                  *
                - *         c.weighty = 0.0;                //reset to the default
                - *         c.gridwidth = GridBagConstraints.REMAINDER; //end row
                - *         c.gridheight = 1;               //reset to the default
                - *         makebutton("Button9", gridbag, c);
                - *         makebutton("Button10", gridbag, c);
                - *
                - *         setSize(300, 100);
                - *     }
                - *
                - *     public static void main(String args[]) {
                - *         Frame f = new Frame("GridBag Layout Example");
                - *         GridBagEx1 ex1 = new GridBagEx1();
                - *
                - *         ex1.init();
                - *
                - *         f.add("Center", ex1);
                - *         f.pack();
                - *         f.setSize(f.getPreferredSize());
                - *         f.show();
                + *             frame.pack();
                + *             frame.setVisible(true);
                + *         });
                  *     }
                  * }
                - * 

                + * } * * @author Doug Stein * @author Bill Spitzak (original NeWS & OLIT implementation) diff --git a/src/java.desktop/share/classes/java/awt/GridLayout.java b/src/java.desktop/share/classes/java/awt/GridLayout.java index b205aa569b3..6beb92194f7 100644 --- a/src/java.desktop/share/classes/java/awt/GridLayout.java +++ b/src/java.desktop/share/classes/java/awt/GridLayout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * 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,25 +32,33 @@ * lays out a container's components in a rectangular grid. * The container is divided into equal-sized rectangles, * and one component is placed in each rectangle. - * For example, the following is an applet that lays out six buttons + * For example, the following is a window that lays out six buttons * into three rows and two columns: * - *
                - *
                - * import java.awt.*;
                - * import java.applet.Applet;
                - * public class ButtonGrid extends Applet {
                - *     public void init() {
                - *         setLayout(new GridLayout(3,2));
                - *         add(new Button("1"));
                - *         add(new Button("2"));
                - *         add(new Button("3"));
                - *         add(new Button("4"));
                - *         add(new Button("5"));
                - *         add(new Button("6"));
                + * {@snippet lang='java':
                + * import java.awt.Button;
                + * import java.awt.EventQueue;
                + * import java.awt.Frame;
                + * import java.awt.GridLayout;
                + *
                + * public class GridLayoutExample {
                + *
                + *     public static void main(String[] args) throws Exception {
                + *         EventQueue.invokeAndWait(() -> {
                + *             Frame frame = new Frame("GridLayout");
                + *             frame.setLayout(new GridLayout(3, 2));
                + *             frame.add(new Button("1"));
                + *             frame.add(new Button("2"));
                + *             frame.add(new Button("3"));
                + *             frame.add(new Button("4"));
                + *             frame.add(new Button("5"));
                + *             frame.add(new Button("6"));
                + *             frame.setSize(200, 200);
                + *             frame.setVisible(true);
                + *         });
                  *     }
                  * }
                - * 

                + * } *

                * If the container's {@code ComponentOrientation} property is horizontal * and left-to-right, the above example produces the output shown in Figure 1. @@ -59,13 +67,13 @@ * *

                *
                - *

                Shows 6 buttons in rows of 2. Row 1 shows buttons 1 then 2.
  *        Row 2 shows buttons 3 then 4. Row 3 shows buttons 5 then 6. *

                Figure 1: Horizontal, Left-to-Right *

                *
                - *

                Shows 6 buttons in rows of 2. Row 1 shows buttons 2 then 1.
  *        Row 2 shows buttons 4 then 3. Row 3 shows buttons 6 then 5. *

                Figure 2: Horizontal, Right-to-Left diff --git a/src/java.desktop/share/classes/java/awt/MediaTracker.java b/src/java.desktop/share/classes/java/awt/MediaTracker.java index 408d68ffe14..f77816dc2e7 100644 --- a/src/java.desktop/share/classes/java/awt/MediaTracker.java +++ b/src/java.desktop/share/classes/java/awt/MediaTracker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +67,17 @@ *

                * Here is an example of using {@code MediaTracker}: * - *


                {@code
                - * import java.applet.Applet;
                + * {@snippet lang='java':
                  * import java.awt.Color;
                + * import java.awt.EventQueue;
                + * import java.awt.Frame;
                  * import java.awt.Image;
                  * import java.awt.Graphics;
                  * import java.awt.MediaTracker;
                + * import java.awt.Panel;
                + * import java.awt.Toolkit;
                  *
                - * public class ImageBlaster extends Applet implements Runnable {
                + * public class MediaTrackerExample extends Panel implements Runnable {
                  *      MediaTracker tracker;
                  *      Image bg;
                  *      Image anim[] = new Image[5];
                @@ -84,29 +87,34 @@
                  *      // Get the images for the background (id == 0)
                  *      // and the animation frames (id == 1)
                  *      // and add them to the MediaTracker
                - *      public void init() {
                + *      public static void main(String[] args) throws Exception {
                + *          MediaTrackerExample mte = new MediaTrackerExample();
                + *          EventQueue.invokeAndWait(() -> {
                + *              Frame frame = new Frame("MediaTrackerExample");
                + *              frame.setSize(400, 400);
                + *              frame.add(mte);
                + *              frame.setVisible(true);
                + *          });
                + *          mte.startAnimation();
                + *      }
                + *
                + *      public MediaTrackerExample() {
                + *          Toolkit tk = Toolkit.getDefaultToolkit();
                  *          tracker = new MediaTracker(this);
                - *          bg = getImage(getDocumentBase(),
                - *                  "images/background.gif");
                + *          // Note : actual images not provided as part of this code example
                + *          bg = tk.getImage("background.gif");
                  *          tracker.addImage(bg, 0);
                  *          for (int i = 0; i < 5; i++) {
                - *              anim[i] = getImage(getDocumentBase(),
                - *                      "images/anim"+i+".gif");
                + *              anim[i] = tk.getImage("anim" + i + ".gif");
                  *              tracker.addImage(anim[i], 1);
                  *          }
                  *      }
                  *
                - *      // Start the animation thread.
                - *      public void start() {
                + *      public void startAnimation() {
                  *          animator = new Thread(this);
                  *          animator.start();
                  *      }
                  *
                - *      // Stop the animation thread.
                - *      public void stop() {
                - *          animator = null;
                - *      }
                - *
                  *      // Run the animation thread.
                  *      // First wait for the background image to fully load
                  *      // and paint.  Then wait for all of the animation
                @@ -137,7 +145,7 @@
                  *      }
                  *
                  *      // The background image fills the frame so we
                - *      // don't need to clear the applet on repaints.
                + *      // don't need to clear the component background on repaints.
                  *      // Just call the paint method.
                  *      public void update(Graphics g) {
                  *          paint(g);
                @@ -152,7 +160,7 @@
                  *      public void paint(Graphics g) {
                  *          if ((tracker.statusAll(false) & MediaTracker.ERRORED) != 0) {
                  *              g.setColor(Color.red);
                - *              g.fillRect(0, 0, size().width, size().height);
                + *              g.fillRect(0, 0, getSize().width, getSize().height);
                  *              return;
                  *          }
                  *          g.drawImage(bg, 0, 0, this);
                @@ -161,7 +169,7 @@
                  *          }
                  *      }
                  * }
                - * } 

                + * } * * @author Jim Graham * @since 1.0 diff --git a/src/java.desktop/share/classes/java/awt/Toolkit.java b/src/java.desktop/share/classes/java/awt/Toolkit.java index 3d9d781de33..d3d8fa2e268 100644 --- a/src/java.desktop/share/classes/java/awt/Toolkit.java +++ b/src/java.desktop/share/classes/java/awt/Toolkit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1472,8 +1472,7 @@ protected final void setDesktopProperty(String name, Object newValue) { Object oldValue; synchronized (this) { - oldValue = desktopProperties.get(name); - desktopProperties.put(name, newValue); + oldValue = desktopProperties.put(name, newValue); } // Don't fire change event if old and new values are null. @@ -1633,7 +1632,7 @@ public boolean isAlwaysOnTopSupported() { private int[] calls = new int[LONG_BITS]; private static volatile long enabledOnToolkitMask; private AWTEventListener eventListener = null; - private WeakHashMap listener2SelectiveListener = new WeakHashMap<>(); + private final WeakHashMap listener2SelectiveListener = new WeakHashMap<>(); /* * Extracts a "pure" AWTEventListener from a AWTEventListenerProxy, @@ -1736,16 +1735,15 @@ public void addAWTEventListener(AWTEventListener listener, long eventMask) { public void removeAWTEventListener(AWTEventListener listener) { AWTEventListener localL = deProxyAWTEventListener(listener); - if (listener == null) { + if (localL == null) { return; } synchronized (this) { SelectiveAWTEventListener selectiveListener = - listener2SelectiveListener.get(localL); + listener2SelectiveListener.remove(localL); if (selectiveListener != null) { - listener2SelectiveListener.remove(localL); int[] listenerCalls = selectiveListener.getCalls(); for (int i=0; i { - return true; - } - default -> throw new IllegalArgumentException("Unknown Rendering Intent"); + // Extract 16-bit unsigned rendering intent (0–65535) + int intent = (header[index + 2] & 0xff) << 8 | header[index + 3] & 0xff; + // Only check upper bound since intent can't be negative + if (intent > icICCAbsoluteColorimetric) { + throw new IllegalArgumentException( + "Unknown Rendering Intent: %d".formatted(intent)); } } diff --git a/src/java.desktop/share/classes/java/awt/doc-files/BorderLayout-1.gif b/src/java.desktop/share/classes/java/awt/doc-files/BorderLayout-1.gif deleted file mode 100644 index 8a1a2bb670f..00000000000 Binary files a/src/java.desktop/share/classes/java/awt/doc-files/BorderLayout-1.gif and /dev/null differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/BorderLayout-1.png b/src/java.desktop/share/classes/java/awt/doc-files/BorderLayout-1.png new file mode 100644 index 00000000000..894b3e17221 Binary files /dev/null and b/src/java.desktop/share/classes/java/awt/doc-files/BorderLayout-1.png differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/FlowLayout-1.gif b/src/java.desktop/share/classes/java/awt/doc-files/FlowLayout-1.gif deleted file mode 100644 index 5f82d060fe9..00000000000 Binary files a/src/java.desktop/share/classes/java/awt/doc-files/FlowLayout-1.gif and /dev/null differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/FlowLayout-1.png b/src/java.desktop/share/classes/java/awt/doc-files/FlowLayout-1.png new file mode 100644 index 00000000000..fa4dcba153e Binary files /dev/null and b/src/java.desktop/share/classes/java/awt/doc-files/FlowLayout-1.png differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-1.gif b/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-1.gif deleted file mode 100644 index b9117973103..00000000000 Binary files a/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-1.gif and /dev/null differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-1.png b/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-1.png new file mode 100644 index 00000000000..f52ab392260 Binary files /dev/null and b/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-1.png differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-2.gif b/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-2.gif deleted file mode 100644 index c947c6c24f8..00000000000 Binary files a/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-2.gif and /dev/null differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-2.png b/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-2.png new file mode 100644 index 00000000000..254819f3a2f Binary files /dev/null and b/src/java.desktop/share/classes/java/awt/doc-files/GridBagLayout-2.png differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-1.gif b/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-1.gif deleted file mode 100644 index e48d75f6478..00000000000 Binary files a/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-1.gif and /dev/null differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-1.png b/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-1.png new file mode 100644 index 00000000000..8a040b1b47f Binary files /dev/null and b/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-1.png differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-2.gif b/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-2.gif deleted file mode 100644 index 24a2999519a..00000000000 Binary files a/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-2.gif and /dev/null differ diff --git a/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-2.png b/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-2.png new file mode 100644 index 00000000000..850b67795db Binary files /dev/null and b/src/java.desktop/share/classes/java/awt/doc-files/GridLayout-2.png differ diff --git a/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java b/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java index 3202d2d690d..c1c60397198 100644 --- a/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java +++ b/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -684,13 +684,10 @@ public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) { private int getRenderingIntent (ICC_Profile profile) { byte[] header = profile.getData(ICC_Profile.icSigHead); int index = ICC_Profile.icHdrRenderingIntent; - - /* According to ICC spec, only the least-significant 16 bits shall be - * used to encode the rendering intent. The most significant 16 bits - * shall be set to zero. Thus, we are ignoring two most significant - * bytes here. - * - * See https://www.color.org/ICC1v42_2006-05.pdf, section 7.2.15. + /* + * ICC spec: only the least-significant 16 bits encode the rendering + * intent. The most significant 16 bits must be zero and can be ignored. + * https://www.color.org/specification/ICC.1-2022-05.pdf, section 7.2.15 */ return ((header[index+2] & 0xff) << 8) | (header[index+3] & 0xff); diff --git a/src/java.desktop/share/classes/java/beans/Introspector.java b/src/java.desktop/share/classes/java/beans/Introspector.java index c526190808e..564021104a7 100644 --- a/src/java.desktop/share/classes/java/beans/Introspector.java +++ b/src/java.desktop/share/classes/java/beans/Introspector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1052,8 +1052,12 @@ private void addMethod(MethodDescriptor md) { } } if (match) { - MethodDescriptor composite = new MethodDescriptor(old, md); - methods.put(name, composite); + Class oldClass = old.getMethod().getDeclaringClass(); + Class mdClass = md.getMethod().getDeclaringClass(); + if (oldClass == mdClass || oldClass.isAssignableFrom(mdClass) || !mdClass.isAssignableFrom(oldClass)) { + MethodDescriptor composite = new MethodDescriptor(old, md); + methods.put(name, composite); + } return; } diff --git a/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java b/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java index 2dc3e39e9ba..197b351feb7 100644 --- a/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java +++ b/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -268,9 +267,7 @@ public void removeTagSet(TIFFTagSet tagSet) { throw new NullPointerException("tagSet == null"); } - if(tagSets.contains(tagSet)) { - tagSets.remove(tagSet); - } + tagSets.remove(tagSet); } /** diff --git a/src/java.desktop/share/classes/javax/imageio/spi/PartiallyOrderedSet.java b/src/java.desktop/share/classes/javax/imageio/spi/PartiallyOrderedSet.java index a547db84363..f88724cce6a 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/PartiallyOrderedSet.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/PartiallyOrderedSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.Map; -import java.util.Set; /** * A set of {@code Object}s with pairwise orderings between them. @@ -58,10 +57,7 @@ class PartiallyOrderedSet extends AbstractSet { // p. 315. // Maps Objects to DigraphNodes that contain them - private Map> poNodes = new HashMap<>(); - - // The set of Objects - private Set nodes = poNodes.keySet(); + private final Map> poNodes = new HashMap<>(); /** * Constructs a {@code PartiallyOrderedSet}. @@ -69,11 +65,11 @@ class PartiallyOrderedSet extends AbstractSet { public PartiallyOrderedSet() {} public int size() { - return nodes.size(); + return poNodes.size(); } public boolean contains(Object o) { - return nodes.contains(o); + return poNodes.containsKey(o); } /** @@ -90,7 +86,7 @@ public Iterator iterator() { * {@code PartiallyOrderedSet}. */ public boolean add(E o) { - if (nodes.contains(o)) { + if (poNodes.containsKey(o)) { return false; } diff --git a/src/java.desktop/share/classes/javax/sound/SoundClip.java b/src/java.desktop/share/classes/javax/sound/SoundClip.java new file mode 100644 index 00000000000..41ad11e5cac --- /dev/null +++ b/src/java.desktop/share/classes/javax/sound/SoundClip.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package javax.sound; + +import java.io.File; +import java.io.IOException; + +import com.sun.media.sound.JavaSoundAudioClip; + +/** + * The {@code SoundClip} class is a simple abstraction for playing a sound clip. + * It will play any format that is recognized by the {@code javax.sound} API, + * and for which it has support. This includes midi data. + *

                + * This class is intended for easy playback of short clips or snippets of sound. + * Examples of when this might be used is to play an audible alert or effect in a UI app, + * or to make a short announcement or to provide audible feedback such announcing as the + * function of a button or control. + * The application will typically let such clips play once to completion. + *

                + * Applications needing more precise control or advanced + * features should look into other parts of the {@code javax.sound} API. + * Playing sound requires that the environment grants access to audio devices. + * Typically this means running the application in a desktop environment. + *

                + * Multiple {@code SoundClip} items can be playing at the same time, and + * the resulting sound is mixed together to produce a composite. + * + * @since 25 + */ +public final class SoundClip { + + private final JavaSoundAudioClip clip; + + /** + * Creates a {@code SoundClip} instance which will play a clip from the supplied file. + *

                + * The file contents will be fully read before this method returns. + * If the file does not contain recognizable and supported sound data, or + * if the implementation does not find a suitable output device for the data, + * playing the clip will be a no-op. + * + * @param file the file from which to obtain the sound data + * @return a {@code SoundClip} + * @throws NullPointerException if {@code file} is {@code null} + * @throws IOException if there is an error reading from {@code file} + */ + public static SoundClip createSoundClip(File file) throws IOException { + if (file == null) { + throw new NullPointerException("file must not be null"); + } + return new SoundClip(file); + } + + private SoundClip(File file) throws IOException { + this.clip = JavaSoundAudioClip.create(file); + } + + /** + * {@return whether this is a playable sound clip} + *

                + * A value of {@code false} means that calling any of the other methods + * of this class is a no-op. + */ + public boolean canPlay() { + return clip.canPlay(); + } + + /** + * {@return whether sound is currently playing} + */ + public boolean isPlaying() { + return clip.isPlaying(); + } + + /** + * Starts playing this sound clip. + * Each time this method is called, the clip is restarted from the beginning. + * This method will return immediately whether or not sound is played, + * and possibly before the sound has started playing. + *

                + * Threading notes : Most applications will not need to do anything except call {@code play()}. + * The following is therefore something most applications need not be concerned about. + * Play back is managed in a background thread, which is usually a daemon thread. + * Running daemon threads do not prevent the VM from exiting. + * So at least one thread must be alive to prevent the VM from terminating. + * A UI application with any window displayed automatically satisfies this requirement. + * Conversely, if the application wants to guarantee VM exit before the play() has completed, + * it should call the {@code stop()} method. + */ + public void play() { + clip.play(); + } + + /** + * Starts playing this sound clip in a loop. + * Each time this method is called, the clip is restarted from the beginning. + * This method will return immediately whether or not sound is played, + * and possibly before the sound has started playing. + *

                + * Threading notes : Most applications will not need to do anything except call {@code loop()}. + * The following is therefore something most applications need not be concerned about. + * Play back is managed in a background thread, which is ususally a daemon thread. + * Running daemon threads do not prevent the VM from exiting. + * So at least one thread must be alive to prevent the VM from terminating. + * A UI application with any window displayed automatically satisfies this requirement. + * Conversely, if the application wants to guarantee VM exit before the play() has completed, + * it should call the {@code stop()} method. + */ + public void loop() { + clip.loop(); + } + + /** + * Stops playing this sound clip. + * Call this if the clip is playing and the application needs to stop + * it early, for example so that the application can ensure the clip + * playing does not block exit. It is also required to stop a {@code loop()}. + */ + public void stop() { + clip.stop(); + } +} diff --git a/src/java.desktop/share/classes/javax/sound/package-info.java b/src/java.desktop/share/classes/javax/sound/package-info.java new file mode 100644 index 00000000000..e84319318e6 --- /dev/null +++ b/src/java.desktop/share/classes/javax/sound/package-info.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * Provides interfaces and classes for the Java Sound API. + * The API is divided into sub-packages. + *

                  + *
                • Capture, processing and playback of sampled audio data is under {@link javax.sound.sampled}. + *
                • Sequencing, and synthesis of MIDI (Musical Instrument Digital Interface) data is under {@link javax.sound.midi}. + *
                + * + *

                Related Documentation

                + * For more information on using Java Sound see: + * + * + * @since 25 + */ +package javax.sound; diff --git a/src/java.desktop/share/classes/javax/swing/Action.java b/src/java.desktop/share/classes/javax/swing/Action.java index 3942d3309d4..b1b092e2104 100644 --- a/src/java.desktop/share/classes/javax/swing/Action.java +++ b/src/java.desktop/share/classes/javax/swing/Action.java @@ -263,7 +263,7 @@ public interface Action extends ActionListener { * commonly used to specify a mnemonic. For example: * myAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A) * sets the mnemonic of myAction to 'a', while - * myAction.putValue(Action.MNEMONIC_KEY, KeyEvent.getExtendedKeyCodeForChar('\u0444')) + * myAction.putValue(Action.MNEMONIC_KEY, KeyEvent.getExtendedKeyCodeForChar('ф')) * sets the mnemonic of myAction to Cyrillic letter "Ef". * * @since 1.3 diff --git a/src/java.desktop/share/classes/javax/swing/JFileChooser.java b/src/java.desktop/share/classes/javax/swing/JFileChooser.java index a5802e26938..ddb3a3911a6 100644 --- a/src/java.desktop/share/classes/javax/swing/JFileChooser.java +++ b/src/java.desktop/share/classes/javax/swing/JFileChooser.java @@ -399,6 +399,7 @@ protected void setup(FileSystemView view) { setFileFilter(getAcceptAllFileFilter()); } enableEvents(AWTEvent.MOUSE_EVENT_MASK); + putClientProperty("html.disable", true); } private void installHierarchyListener() { diff --git a/src/java.desktop/share/classes/javax/swing/JSplitPane.java b/src/java.desktop/share/classes/javax/swing/JSplitPane.java index 90f3efb3e69..f21b2b3339a 100644 --- a/src/java.desktop/share/classes/javax/swing/JSplitPane.java +++ b/src/java.desktop/share/classes/javax/swing/JSplitPane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -369,22 +369,25 @@ public JSplitPane(int newOrientation, */ @Override public void setComponentOrientation(ComponentOrientation orientation) { + ComponentOrientation curOrn = this.getComponentOrientation(); super.setComponentOrientation(orientation); - Component leftComponent = this.getLeftComponent(); - Component rightComponent = this.getRightComponent(); - if (!this.getComponentOrientation().isLeftToRight()) { - if (rightComponent != null) { - setLeftComponent(rightComponent); - } - if (leftComponent != null) { - setRightComponent(leftComponent); - } - } else { - if (leftComponent != null) { - setLeftComponent(leftComponent); - } - if (rightComponent != null) { - setRightComponent(rightComponent); + if (!orientation.equals(curOrn)) { + Component leftComponent = this.getLeftComponent(); + Component rightComponent = this.getRightComponent(); + if (!this.getComponentOrientation().isLeftToRight()) { + if (rightComponent != null) { + setLeftComponent(rightComponent); + } + if (leftComponent != null) { + setRightComponent(leftComponent); + } + } else { + if (leftComponent != null) { + setLeftComponent(leftComponent); + } + if (rightComponent != null) { + setRightComponent(rightComponent); + } } } } diff --git a/src/java.desktop/share/classes/javax/swing/PopupFactory.java b/src/java.desktop/share/classes/javax/swing/PopupFactory.java index 9789e95e7ff..682cdbd005b 100644 --- a/src/java.desktop/share/classes/javax/swing/PopupFactory.java +++ b/src/java.desktop/share/classes/javax/swing/PopupFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -433,10 +433,8 @@ private static HeavyWeightPopup getRecycledHeavyWeightPopup(Window w) { } else { return null; } - if (cache.size() > 0) { - HeavyWeightPopup r = cache.get(0); - cache.remove(0); - return r; + if (!cache.isEmpty()) { + return cache.removeFirst(); } return null; } @@ -776,10 +774,8 @@ private static void recycleLightWeightPopup(LightWeightPopup popup) { private static LightWeightPopup getRecycledLightWeightPopup() { synchronized (LightWeightPopup.class) { List lightPopupCache = getLightWeightPopupCache(); - if (lightPopupCache.size() > 0) { - LightWeightPopup r = lightPopupCache.get(0); - lightPopupCache.remove(0); - return r; + if (!lightPopupCache.isEmpty()) { + return lightPopupCache.removeFirst(); } return null; } @@ -934,10 +930,8 @@ private static void recycleMediumWeightPopup(MediumWeightPopup popup) { private static MediumWeightPopup getRecycledMediumWeightPopup() { synchronized (MediumWeightPopup.class) { List mediumPopupCache = getMediumWeightPopupCache(); - if (mediumPopupCache.size() > 0) { - MediumWeightPopup r = mediumPopupCache.get(0); - mediumPopupCache.remove(0); - return r; + if (!mediumPopupCache.isEmpty()) { + return mediumPopupCache.removeFirst(); } return null; } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java index a7b8718ca8d..032db36b87e 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -949,6 +949,8 @@ public Component getListCellRendererComponent(JList list, Object value, ii.depth = directoryComboBoxModel.getDepth(index); setIcon(ii); + putClientProperty("html.disable", getFileChooser().getClientProperty("html.disable")); + return this; } } diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/doc-files/synth.dtd b/src/java.desktop/share/classes/javax/swing/plaf/synth/doc-files/synth.dtd index 9653dca129b..3433d48fc39 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/doc-files/synth.dtd +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/doc-files/synth.dtd @@ -1,5 +1,5 @@ - + /, + { relevance: 10 } + ), + { + begin: //, + relevance: 10 + }, + XML_ENTITIES, + // xml processing instructions + { + className: 'meta', + end: /\?>/, + variants: [ + { + begin: /<\?xml/, + relevance: 10, + contains: [ + QUOTE_META_STRING_MODE + ] + }, + { + begin: /<\?[a-z][a-z0-9]+/, + } + ] + + }, + { + className: 'tag', + /* + The lookahead pattern (?=...) ensures that 'begin' only matches + ')/, + end: />/, + keywords: { name: 'style' }, + contains: [ TAG_INTERNALS ], + starts: { + end: /<\/style>/, + returnEnd: true, + subLanguage: [ + 'css', + 'xml' + ] + } + }, + { + className: 'tag', + // See the comment in the + + +

                This test is for Motif LaF.

                + +

                + When the test starts, you'll see 2 radio buttons and 2 check boxes + with the checkmarks painted.

                + +

                + Ensure that all the button's checkmarks are painted entirely + within the circular/rectangle checkbox, NOT over them or outside them. +

                + + """; + + public static void main(String[] args) throws Exception { + try { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + } catch (Exception e) { + throw new SkippedException("Unsupported LaF", e); + } + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .rows(10) + .columns(45) + .testUI(createAndShowUI()) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JFrame frame = new JFrame("bug4673850"); + frame.setLayout(new FlowLayout()); + + JRadioButton rb = new JRadioButton("RadioButt"); + rb.setSelected(true); + frame.add(rb); + JRadioButton rb2 = new JRadioButton("RadioButt"); + rb2.setHorizontalTextPosition(SwingConstants.LEFT); + rb2.setSelected(true); + frame.add(rb2); + + JCheckBox cb = new JCheckBox("CheckBox"); + cb.setSelected(true); + frame.add(cb); + JCheckBox cb2 = new JCheckBox("CheckBox"); + cb2.setHorizontalTextPosition(SwingConstants.LEFT); + cb2.setSelected(true); + frame.add(cb2); + frame.setSize(200, 150); + return frame; + } +} \ No newline at end of file diff --git a/test/jdk/javax/swing/JRootPane/bug4403624.java b/test/jdk/javax/swing/JRootPane/bug4403624.java new file mode 100644 index 00000000000..1c3ba3ddd2a --- /dev/null +++ b/test/jdk/javax/swing/JRootPane/bug4403624.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4403624 + * @summary Tests JRootPane layout with invisible menubar + * @key headful + * @run main bug4403624 + */ + +import java.awt.Color; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.SwingUtilities; + +public class bug4403624 { + private static JFrame f; + private static Container c; + private static JButton b; + private static volatile Point p; + private static volatile int bWidth; + private static volatile int bHeight; + private static final int OFFSET = 2; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("bug4403624 Test"); + JMenuBar mbar; + mbar = new JMenuBar(); + mbar.add(new JMenu("Menu")); + f.setJMenuBar(mbar); + b = new JButton("Hide Menu"); + b.addActionListener(e -> mbar.setVisible(false)); + c = f.getContentPane(); + c.setLayout(new FlowLayout()); + c.setBackground(Color.GREEN); + c.add(b); + f.pack(); + f.setLocationRelativeTo(null); + f.setAlwaysOnTop(true); + f.setVisible(true); + }); + + Robot r = new Robot(); + r.setAutoDelay(200); + r.waitForIdle(); + r.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + p = b.getLocationOnScreen(); + bWidth = b.getWidth(); + bHeight = b.getHeight(); + }); + + r.mouseMove(p.x + (bWidth / 2), p.y + (bHeight / 2)); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + SwingUtilities.invokeAndWait(() -> p = c.getLocationOnScreen()); + + Color c = r.getPixelColor(p.x + OFFSET, p.y + OFFSET); + + if (c.getGreen() < 240 && c.getBlue() > 10 && c.getRed() > 10) { + System.out.println("EXPECTED: " + Color.GREEN); + System.out.println("ACTUAL: " + c); + throw new RuntimeException("Failure to hide menu bar."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JRootPane/bug4614623.java b/test/jdk/javax/swing/JRootPane/bug4614623.java new file mode 100644 index 00000000000..9a714d3cdfd --- /dev/null +++ b/test/jdk/javax/swing/JRootPane/bug4614623.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4614623 + * @requires (os.family == "windows") + * @summary Tests that w2k mnemonic underlining works when there's no + focus owner + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4614623 + */ + +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.UIManager; + +public class bug4614623 { + private static final String INSTRUCTIONS = """ + This test verifies if the short-cut character + (menu mnemonic) is underlined when the ALT key is held down. + + Check if the following is true. + 1) Press Alt key. The letter 'F' (menu mnemonic) of + the "File" menu should now be underlined. + 2) Release the Alt key, the selection background (light grey) + should appear around the "File" menu. Compare "About" menu + with "File" menu to see the light grey selection background. + + If the above is true, press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(62) + .rows(12) + .testUI(bug4614623::createAndShowUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createAndShowUI() { + JFrame frame = new JFrame("bug4614623 - File menu test"); + JMenuBar menuBar = new JMenuBar(); + + JMenu fileMenu = new JMenu("File"); + fileMenu.setMnemonic('F'); + menuBar.add(fileMenu); + + JMenu about = new JMenu("About"); + menuBar.add(about); + menuBar.setSize(300, 100); + + frame.setJMenuBar(menuBar); + menuBar.requestFocus(); + frame.setSize(300, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JScrollBar/4865918/bug4865918.java b/test/jdk/javax/swing/JScrollBar/4865918/bug4865918.java index 96b1034c943..d68f1bff597 100644 --- a/test/jdk/javax/swing/JScrollBar/4865918/bug4865918.java +++ b/test/jdk/javax/swing/JScrollBar/4865918/bug4865918.java @@ -24,14 +24,16 @@ /* * @test * @bug 4865918 - * @requires (os.family != "mac") + * @key headful * @summary REGRESSION:JCK1.4a-runtime api/javax_swing/interactive/JScrollBarTests.html#JScrollBar * @run main bug4865918 */ import java.awt.Dimension; +import java.awt.Robot; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import javax.swing.JFrame; import javax.swing.JScrollBar; import javax.swing.SwingUtilities; import java.util.concurrent.CountDownLatch; @@ -41,24 +43,33 @@ public class bug4865918 { + private static JFrame frame; private static TestScrollBar sbar; private static final CountDownLatch mousePressLatch = new CountDownLatch(1); public static void main(String[] argv) throws Exception { - String osName = System.getProperty("os.name"); - if (osName.toLowerCase().contains("os x")) { - System.out.println("This test is not for MacOS, considered passed."); - return; - } - SwingUtilities.invokeAndWait(() -> setupTest()); + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> createAndShowGUI()); - SwingUtilities.invokeAndWait(() -> sbar.pressMouse()); - if (!mousePressLatch.await(2, TimeUnit.SECONDS)) { - throw new RuntimeException("Timed out waiting for mouse press"); - } + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> sbar.pressMouse()); + if (!mousePressLatch.await(2, TimeUnit.SECONDS)) { + throw new RuntimeException("Timed out waiting for mouse press"); + } - if (getValue() != 9) { - throw new RuntimeException("The scrollbar block increment is incorrect"); + if (getValue() != 9) { + throw new RuntimeException("The scrollbar block increment " + + getValue() + " is incorrect"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); } } @@ -73,8 +84,8 @@ private static int getValue() throws Exception { return result[0]; } - private static void setupTest() { - + private static void createAndShowGUI() { + frame = new JFrame("bug4865918"); sbar = new TestScrollBar(JScrollBar.HORIZONTAL, -1, 10, -100, 100); sbar.setPreferredSize(new Dimension(200, 20)); sbar.setBlockIncrement(10); @@ -83,7 +94,11 @@ public void mousePressed(MouseEvent e) { mousePressLatch.countDown(); } }); - + frame.getContentPane().add(sbar); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); } static class TestScrollBar extends JScrollBar { diff --git a/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java new file mode 100644 index 00000000000..61124ea1e97 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/HorizScrollers.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5078454 + * @summary Test horizontal wheel scroll behavior of (including RTL) + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HorizScrollers + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; + +public class HorizScrollers { + private static final String INSTRUCTIONS = """ + This is a semi-automatic test with three phases. + For each phase, you will need to change the mouse setting, as + directed by a dialog. Once the correct setting is confirmed, + the next test phase will run automatically. + DO NOT TOUCH ANYTHING DURING TESTING! + + The test will automatically FAIL during testing if something + fails. Otherwise, the test will automatically PASS after the + third testing phase. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("HorizScrollers Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testTimeOut(10) + .splitUIRight(ConfigPanel::new) + .logArea(6) + .build() + .awaitAndCheck(); + } + + private static final int[] SCROLLAMTS = {1, 30, 3}; + private static final String[] CONFIG_MSGS = { + "Set the scrolling speed to the slowest value (1 line).", + "Set the scrolling speed to the fastest value (30 lines).", + "Set the scrolling speed to two ticks above the slowest value (3 lines)." + }; + + private static int current = 0; + private static final String MW_TEXT = "Rotate the mouse wheel here"; + private static final String CONFIG_INSTRUCTION_TEMPLATE = """ + Configure Mouse Wheel for Phase %d + + Open the Mouse Control Panel and go to the 'Wheel' tab. + If 'Wheel' tab is not available just press Pass. + + %s + + Test the setting on the area below. + Once the mouse is setup correctly, the area will turn green. + When you're ready for the next part of the test to run, press GO! + """; + + static class ConfigPanel extends JPanel + implements ActionListener, MouseWheelListener { + JTextArea msg; + JButton goBtn; + JLabel mwArea; + int scrollAmount; + + private final Color defaultBg; + + ConfigPanel() { + this.scrollAmount = SCROLLAMTS[current]; + Container content = this; + content.setLayout(new BorderLayout()); + msg = new JTextArea(); + msg.setMargin(new Insets(5, 5, 5, 5)); + msg.setEditable(false); + msg.setLineWrap(true); + msg.setWrapStyleWord(true); + content.add(msg, BorderLayout.NORTH); + + mwArea = new JLabel(MW_TEXT, SwingConstants.CENTER); + mwArea.setPreferredSize(new Dimension(200, 250)); + mwArea.setBorder(BorderFactory.createLineBorder(Color.BLACK)); + mwArea.setOpaque(true); + mwArea.addMouseWheelListener(this); + content.add(mwArea, BorderLayout.CENTER); + + defaultBg = mwArea.getBackground(); + setPhase(current); + + goBtn = new JButton("GO!"); + goBtn.setEnabled(false); + goBtn.addActionListener(this); + JPanel flowPanel = new JPanel(); + flowPanel.setLayout(new FlowLayout()); + flowPanel.add(goBtn); + content.add(flowPanel, BorderLayout.SOUTH); + + setPreferredSize(new Dimension(600, 400)); + } + + public void setPhase(int phase) { + if (phase < 3) { + setVisible(true); + PassFailJFrame.log("Phase %d scroll speed %d" + .formatted(phase + 1, SCROLLAMTS[phase])); + PassFailJFrame.log(CONFIG_MSGS[phase]); + + scrollAmount = SCROLLAMTS[phase]; + msg.setText(CONFIG_INSTRUCTION_TEMPLATE + .formatted(phase + 1, CONFIG_MSGS[phase])); + mwArea.setBackground(defaultBg); + mwArea.setText(MW_TEXT); + } else { + // all cases passed + showFinalReminderIfNeeded(false); + } + } + + private void showFinalReminderIfNeeded(boolean isFailure) { + if (scrollAmount != 3) { + JOptionPane.showMessageDialog( + ConfigPanel.this.getTopLevelAncestor(), + ("Test %s. Please make sure you have restored " + + "the original scrolling speed in the " + + "Mouse settings.") + .formatted(isFailure + ? "failed" + : "passed"), + isFailure + ? "Failure" + : "Success", + isFailure + ? JOptionPane.WARNING_MESSAGE + : JOptionPane.INFORMATION_MESSAGE + ); + } + + if (isFailure) { + PassFailJFrame.forceFail(); + } else { + PassFailJFrame.forcePass(); + } + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == goBtn) { + goBtn.setEnabled(false); + + new Thread(() -> { // new thread to avoid running robot on EDT + boolean passed; + try { + passed = RTLScrollers.runTest(SCROLLAMTS[current]); + } catch (Exception ex) { + PassFailJFrame.log("Failure: " + ex); + SwingUtilities.invokeLater(() -> + showFinalReminderIfNeeded(true)); + return; + } + + PassFailJFrame.log("Phase %d passed: %b\n" + .formatted(current + 1, passed)); + if (passed) { + SwingUtilities.invokeLater(() -> { + goBtn.setEnabled(true); + setPhase(++current); + }); + } else { + SwingUtilities.invokeLater(() -> + showFinalReminderIfNeeded(true)); + } + }).start(); + } + } + + public void mouseWheelMoved(MouseWheelEvent e) { + int eventScrollAmt = e.getScrollAmount(); + if (eventScrollAmt == scrollAmount) { + mwArea.setBackground(Color.GREEN); + mwArea.setText("Mouse wheel configured - press Go"); + goBtn.setEnabled(true); + goBtn.requestFocusInWindow(); + PassFailJFrame.log("Proceed to the test with go button"); + return; + } + if (eventScrollAmt < scrollAmount) { + mwArea.setText("Increase the scroll speed. (Want:" + + scrollAmount + " Got:" + eventScrollAmt + ")"); + } else { + mwArea.setText("Decrease the scroll speed. (Want:" + + scrollAmount + " Got:" + eventScrollAmt + ")"); + } + } + } +} diff --git a/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java new file mode 100644 index 00000000000..da395282bf5 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/AcceleratedWheelScrolling/RTLScrollers.java @@ -0,0 +1,680 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// A few Swing components which use the mouse wheel to scroll + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.event.MouseWheelListener; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; + +import javax.swing.DefaultListModel; +import javax.swing.ImageIcon; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.ListModel; +import javax.swing.ScrollPaneConstants; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +public class RTLScrollers extends JDialog + implements MouseWheelListener, ActionListener { + private static final int ROWS = 5; + private static final int COLUMNS = 150; + private static final int WINWIDTH = 1000; + + static RTLScrollers rtl; + static volatile RTLScrollers f; + static volatile boolean retVal; + static volatile JScrollPane jsp; + static volatile JScrollBar hsb; + static volatile JScrollBar sb; + static volatile Point loc; + static volatile Dimension size; + TestList list; + JScrollPane listScroller; + JTextArea text; + JScrollPane textScroller; + TestTable table; + JScrollPane tableScroller; + JCheckBoxMenuItem rightToLeft; + ImageIcon photoIcon; + int scrollAmount; + + private static Robot robot; + private static BufferedImage logo = genIcon(166, 39, Color.PINK); + private static BufferedImage photo = genIcon(59, 80, Color.MAGENTA); + private static BufferedImage photo2 = genIcon(80, 53, Color.ORANGE); + + private static BufferedImage genIcon(int width, int height, Color color) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics g = image.getGraphics(); + g.setColor(color); + g.fillRect(0, 0, width, height); + + return image; + } + + public RTLScrollers() { + this(0); + } + + public RTLScrollers(int scrollAmount) { + super(new JFrame(), "RTLScrollers", false); + + this.scrollAmount = scrollAmount; + Container content = getContentPane(); + content.setLayout(new GridBagLayout()); + + DefaultListModel listModel = new DefaultListModel<>(); + + photoIcon = new ImageIcon(photo); + for (int i = 0; i < COLUMNS / 4 ; i++) { + for (int j = 0; j < ROWS; j++) { + listModel.addElement(new ImageIcon(logo)); + } + for (int j = 0; j < ROWS; j++) { + listModel.addElement(photoIcon); + } + for (int j = 0; j < ROWS; j++) { + listModel.addElement(new ImageIcon(photo2)); + } + for (int j = 0; j < ROWS; j++) { + listModel.addElement("Text Item " + ((1 + i) * 3)); + } + } + + list = new TestList(listModel); + list.setVisibleRowCount(ROWS); + list.setLayoutOrientation(JList.VERTICAL_WRAP); + listScroller = new JScrollPane(list); + listScroller.addMouseWheelListener(this); + + text = new JTextArea(); + for (int j = 0; j < ROWS ; j++) { + for (int i = 0; i < COLUMNS ; i++) { + text.append(i + " some text, some more text, a really long line of text "); + } + text.append("\n"); + } + + textScroller = new JScrollPane(text); + textScroller.addMouseWheelListener(this); + + DefaultTableModel model = new DefaultTableModel(ROWS, COLUMNS); + table = new TestTable(model); + table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + for (int i = 0; i < COLUMNS; i++) { + for (int j = 0; j < ROWS; j++) { + table.setValueAt(j + ", " + i, j, i); + } + + TableColumn column = table.getColumnModel().getColumn(i); + + if (i % 4 == 0) { + column.setMinWidth(0); + column.setPreferredWidth(0); + column.setMaxWidth(0); + } + else if ((i + 1) % 4 == 0) { + column.setMinWidth(95); + column.setPreferredWidth(95); + column.setMaxWidth(95); + } + else if ((i + 2) % 4 == 0) { + column.setMinWidth(26); + column.setPreferredWidth(26); + column.setMaxWidth(26); + } + else { + column.setMinWidth(50); + column.setPreferredWidth(50); + column.setMaxWidth(50); + } + } + tableScroller = new JScrollPane(table); + tableScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + tableScroller.addMouseWheelListener(this); + + GridBagConstraints tableGBC = new GridBagConstraints(0, + 0, + 1, + 1, + 1.0, + 0.3, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets(0,0,0,0), + 0, + 0); + content.add(tableScroller, tableGBC); + GridBagConstraints textGBC = new GridBagConstraints(0, + 1, + 1, + 1, + 1.0, + 0.3, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets(0,0,0,0), + 0, + 0); + content.add(textScroller, textGBC); + + GridBagConstraints listGBC = new GridBagConstraints(0, + 2, + 1, + 5, + 1.0, + 1.2, + GridBagConstraints.CENTER, + GridBagConstraints.BOTH, + new Insets(0,0,0,0), + 0, + 0); + + content.add(listScroller, listGBC); + + rightToLeft = new JCheckBoxMenuItem("Right-To-Left", false); + rightToLeft.addActionListener(this); + JMenu menu = new JMenu("Component Orientation"); + menu.add(rightToLeft); + + JMenuItem close = new JMenuItem("Close"); + close.addActionListener(e -> RTLScrollers.this.setVisible(false)); + menu.add(close); + + JMenuBar mb = new JMenuBar(); + mb.add(menu); + setJMenuBar(mb); + setBounds(0, 0, WINWIDTH, 760); + setLocationRelativeTo(null); + } + + public void actionPerformed(ActionEvent e) { + if (rightToLeft.getState()) { + applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + } + else { + applyComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + } + } + public void mouseWheelMoved(MouseWheelEvent e) { + System.out.println("Rotation: " + e.getWheelRotation()); + } + + public static boolean runTest(int scrollAmount) + throws InterruptedException, InvocationTargetException { + System.out.println("RTLS.runTest()"); + if (robot == null) { + try { + robot = new Robot(); + robot.setAutoDelay(150); + robot.setAutoWaitForIdle(true); + } + catch (AWTException e) { + e.printStackTrace(); + return false; + } + } + + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + rtl = new RTLScrollers(scrollAmount); + rtl.setVisible(true); + }); + robot.delay(100); + + try { + retVal = rtl.runTests(scrollAmount); + } finally { + SwingUtilities.invokeAndWait(() -> { + rtl.setVisible(false); + rtl.dispose(); + }); + } + + robot.delay(100); + System.out.println("RTLS.runTest(): " + retVal); + return retVal; + } + + private boolean runTests(int scrollAmount) + throws InterruptedException, InvocationTargetException { + if (robot == null) { + try { + robot = new Robot(); + robot.setAutoDelay(150); + robot.setAutoWaitForIdle(true); + } + catch (AWTException e) { + e.printStackTrace(); + return false; + } + } + + // + // run robot tests + // + robot.delay(500); + + System.out.println("Testing Table"); + testComp(table, scrollAmount); + + System.out.println("Testing List"); + testComp(list, scrollAmount); + + SwingUtilities.invokeAndWait(() -> + applyComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT)); + robot.delay(100); + + System.out.println("Testing RTL Table"); + testComp(table, scrollAmount); + + System.out.println("Testing RTL List"); + testComp(list, scrollAmount); + + return true; + } + + public boolean testComp(TestTools comp, int scrollAmount) + throws InterruptedException, InvocationTargetException { + // Make sure we start from the beginning + SwingUtilities.invokeAndWait(() -> { + jsp = (JScrollPane)((JComponent)comp).getParent().getParent(); + hsb = jsp.getHorizontalScrollBar(); + hsb.setValue(hsb.getMinimum()); + + loc = jsp.getLocationOnScreen(); + size = jsp.getSize(); + }); + int midx = loc.x + size.width / 2; + int midy = loc.y + size.height / 2; + int maxIdx = 0; + robot.mouseMove(midx, midy); + + // Don't bother for max scroll w/ RTL JList, because the block increment is broken + if (scrollAmount != 30 || !(comp instanceof TestList) + || getComponentOrientation().isLeftToRight()) { + scrollToMiddle(jsp, robot); + + // check that we're lined up + comp.checkTopCellIsLinedUp(); + + int startVal = hsb.getValue(); + int leadingCell = comp.getLeadingCell().y; + System.out.println("leadingCell is " + leadingCell); + + // become unaligned + int width = comp.getLeadingCellWidth(); + int midVal = startVal + width / 2; + System.out.println("becoming unaligned: startVal is " + + startVal + ", midVal is " + midVal); + SwingUtilities.invokeAndWait(() -> hsb.setValue(midVal)); + + // + // Check partial inc up + // + robot.mouseWheel(-1); + + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, -scrollAmount + 1); + } + comp.checkTopCellIsLinedUp(); + + // + // Check partial inc down + // + SwingUtilities.invokeAndWait(() -> hsb.setValue(midVal)); + robot.delay(100); + robot.mouseWheel(1); + + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, scrollAmount); + } + comp.checkTopCellIsLinedUp(); + + // + // Check full inc down (3 times) + // + SwingUtilities.invokeAndWait(() -> hsb.setValue(startVal)); + leadingCell = comp.getLeadingCell().y; + + // Once... + robot.mouseWheel(1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, scrollAmount); + } + comp.checkTopCellIsLinedUp(); + + // Twice... + robot.mouseWheel(1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, (2 * scrollAmount)); + } + + comp.checkTopCellIsLinedUp(); + + // Thrice... + robot.mouseWheel(1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, (3 * scrollAmount)); + + } + comp.checkTopCellIsLinedUp(); + + // + // Check full inc up (3 times) + // + leadingCell = comp.getLeadingCell().y; + + // Once... + robot.mouseWheel(-1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, -scrollAmount); + } + comp.checkTopCellIsLinedUp(); + + // Twice... + robot.mouseWheel(-1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, -(2 * scrollAmount)); + } + comp.checkTopCellIsLinedUp(); + + // Thrice... + robot.mouseWheel(-1); + if (scrollAmount == 30) { // hack for max scroll amount + comp.checkTopCellIsMax(maxIdx++); + } + else { + comp.checkTopCellIs(leadingCell, -(3 * scrollAmount)); + } + comp.checkTopCellIsLinedUp(); + } + + // + // Test acceleration for max scrolling + // (this part should still work for RTL JList) + if (scrollAmount == 30) { + SwingUtilities.invokeAndWait(() -> hsb.setValue(hsb.getMinimum())); + robot.delay(100); + robot.mouseWheel(2); + robot.mouseWheel(2); + robot.mouseWheel(2); + if (hsb.getValue() < hsb.getMaximum() - hsb.getVisibleAmount()) { + throw new RuntimeException("Wheel acceleration for max " + + "scrolling doesn't work: hsb value (" + hsb.getValue() + + " < hsb max (" + hsb.getMaximum() + + ") - hsb vis (" + hsb.getVisibleAmount() + ")"); + } + robot.delay(100); + robot.mouseWheel(-2); + robot.mouseWheel(-2); + robot.mouseWheel(-2); + if (hsb.getValue() > hsb.getMinimum()) { + throw new RuntimeException("Wheel acceleration for max " + + "scrolling doesn't work: hsb value (" + + hsb.getValue() + " > hsb min (" + hsb.getMinimum() + ")"); + } + } + + return true; + } + + class TestTable extends JTable implements TestTools { + final int[] MAXVALS = {23, 67, 67, 89, 111, 89, 66, 45}; //Lookup table + public TestTable(TableModel model) { + super(model); + } + + public void checkTopCellIsLinedUp() { + boolean isLeftToRight = getComponentOrientation().isLeftToRight(); + Point leading = getLeadingCell(); + Rectangle visRect = getVisibleRect(); + Rectangle cellRect = getCellRect(leading.x, leading.y, true); + + if (isLeftToRight) { + if (cellRect.x != visRect.x) { + throw new RuntimeException("leading cell is not aligned!"); + } + } + else { + if (cellRect.x + cellRect.width != visRect.x + visRect.width) { + throw new RuntimeException("leading cell is not aligned!"); + } + } + } + + public void checkTopCellIs(int col) { + Point cell = getLeadingCell(); + if (cell.y != col) { + throw new RuntimeException("leading cell (" + cell.y + + ") is not " + col); + } + } + + /* + * Account for 0-width cells + * + * shift is a non-0 number of visible cells to shift. The shift is + * augmented for zero-width cells, and the new sum is passed into + * checkTopCellIs(). + */ + public void checkTopCellIs(int col, int shift) { + if (shift == 0) { + checkTopCellIs(col); + return; + } + + int row = getLeadingCell().x; + int newShift = 0; + int foundCells = 0; + int direction = shift > 0 ? 1 : -1; + int index = col; + Rectangle cellRect; + + while (foundCells < Math.abs(shift)) { + index += direction; + cellRect = getCellRect(row, index, true); + if (cellRect.width > 0) { + foundCells++; + } + newShift++; + } + + checkTopCellIs(col + (direction*newShift)); + } + + public void checkTopCellIsMax(int idx) { + checkTopCellIs(MAXVALS[idx]); + } + + public int getLeadingCellWidth() { + Point leading = getLeadingCell(); + Rectangle cellRect = getCellRect(leading.x, leading.y, true); + return cellRect.width; + } + + public Point getLeadingCell() { + boolean isLeftToRight = getComponentOrientation().isLeftToRight(); + Rectangle visRect = getVisibleRect(); + int row = rowAtPoint(visRect.getLocation()); + int column; + if (isLeftToRight) { + column = columnAtPoint(visRect.getLocation()); + } + else { + column = columnAtPoint(new Point(visRect.x + visRect.width - 1, visRect.y)); + } + return new Point(row, column); + } + } + + class TestList extends JList implements TestTools { + final int[] MAXVALS = {5, 16, 15, 20, 25, 20, 15, 10 }; + public TestList(ListModel model) { + super(model); + } + + // Note - implemented in terms of columns + public Point getLeadingCell() { + System.out.println("TL.gLC(): first vis index is " + + getFirstVisibleIndex()); + return new Point(getFirstVisibleIndex() / ROWS, + getFirstVisibleIndex() / ROWS); + } + public void checkTopCellIsLinedUp() { + boolean isLeftToRight = getComponentOrientation().isLeftToRight(); + int visIdx = getFirstVisibleIndex(); + Rectangle cellRect = getCellBounds(visIdx, visIdx); + Rectangle visRect = getVisibleRect(); + if (isLeftToRight) { + if (cellRect.x != visRect.x) { + throw new RuntimeException("leading cell is not aligned!"); + } + } + else { + if (cellRect.x + cellRect.width != visRect.x + visRect.width) { + throw new RuntimeException("leading cell is not aligned!"); + } + } + } + public void checkTopCellIs(int col) { + int firstVis = getLeadingCell().y; + if (firstVis != col) { + throw new RuntimeException("leading cell (" + + firstVis + ") is not " + col); + } + } + public void checkTopCellIs(int idx, int shift) { + checkTopCellIs(idx + shift); + + } + public void checkTopCellIsMax(int idx) { + checkTopCellIs(MAXVALS[idx]); + } + public int getLeadingCellWidth() { + int visIdx = getFirstVisibleIndex(); + Rectangle cellRect = getCellBounds(visIdx, visIdx); + System.out.println("TL.gLCW(): leading cell width is " + cellRect.width); + return cellRect.width; + } + } + + private interface TestTools { + /** + * Throws a runtime exception if the top cell isn't lined up + */ + void checkTopCellIsLinedUp(); + void checkTopCellIs(int col); + void checkTopCellIs(int col, int shift); + int getLeadingCellWidth(); + Point getLeadingCell(); + + void checkTopCellIsMax(int idx); + } + + public void scrollToMiddle(JScrollPane jsp, Robot robot) + throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(() -> { + sb = jsp.getHorizontalScrollBar(); + loc = sb.getLocationOnScreen(); + size = sb.getSize(); + }); + robot.setAutoDelay(250); + + robot.mouseMove(loc.x + size.width / 2, + loc.y + size.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + SwingUtilities.invokeAndWait(() -> { + if (jsp == listScroller) { + int idx = list.getFirstVisibleIndex(); + list.ensureIndexIsVisible(idx); + } + }); + } + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> f = new RTLScrollers()); + } finally { + SwingUtilities.invokeAndWait(() -> { + f.setVisible(true); + f.dispose(); + }); + } + } +} diff --git a/test/jdk/javax/swing/JScrollPane/bug4166037.java b/test/jdk/javax/swing/JScrollPane/bug4166037.java new file mode 100644 index 00000000000..e2ce75867a7 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/bug4166037.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4166037 + * @summary Tests if changes to JScrollPane propagate to ScrollPaneLayout + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4166037 + */ + +import java.awt.Color; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneLayout; + +public class bug4166037 { + static final String INSTRUCTIONS = """ + Press button "Never". Scroll bars should disappear. + Press button "Always". Scroll bars should appear. + Press button "Colhead". Label ColumnHeader should + get replaced with yellow rectangles. + Press button "Corner". You should see 4 green + rectangles in the corners of the scroll pane. + Press button "Rowhead". Label RowHeader should get + replaced with yellow rectangles. + Press button "Viewport". Viewport (the rest of the + area except scrollbars) should get replaced with yellow + rectangles. + If the behavior is as described, the test PASSES. + Otherwise, this test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4166037 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4166037::createUI) + .logArea() + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("JScrollPane in JScrollLayout Test"); + JScrollPane scroll = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + JPanel p = new JPanel(); + scroll.setSize(200, 200); + f.add(scroll); + f.setLayout(new BoxLayout(f.getContentPane(), BoxLayout.Y_AXIS)); + JButton bn = new JButton("Never"); + bn.addActionListener(e -> { + PassFailJFrame.log("pane before: " + + scroll.getVerticalScrollBarPolicy() + + scroll.getHorizontalScrollBarPolicy()); + PassFailJFrame.log("layout before: " + + ((ScrollPaneLayout) scroll.getLayout()).getVerticalScrollBarPolicy() + + ((ScrollPaneLayout) scroll.getLayout()).getHorizontalScrollBarPolicy()); + scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); + scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + PassFailJFrame.log("pane after: " + + scroll.getVerticalScrollBarPolicy() + + scroll.getHorizontalScrollBarPolicy()); + PassFailJFrame.log("layout after: " + + ((ScrollPaneLayout) scroll.getLayout()).getVerticalScrollBarPolicy() + + ((ScrollPaneLayout) scroll.getLayout()).getHorizontalScrollBarPolicy()); + }); + JButton ba = new JButton("Always"); + ba.addActionListener(e -> { + PassFailJFrame.log("pane before: " + + scroll.getVerticalScrollBarPolicy() + + scroll.getHorizontalScrollBarPolicy()); + PassFailJFrame.log("layout before: " + + ((ScrollPaneLayout) scroll.getLayout()).getVerticalScrollBarPolicy() + + ((ScrollPaneLayout) scroll.getLayout()).getHorizontalScrollBarPolicy()); + scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + PassFailJFrame.log("pane after: " + + scroll.getVerticalScrollBarPolicy() + + scroll.getHorizontalScrollBarPolicy()); + PassFailJFrame.log("layout after: " + + ((ScrollPaneLayout) scroll.getLayout()).getVerticalScrollBarPolicy() + + ((ScrollPaneLayout) scroll.getLayout()).getHorizontalScrollBarPolicy()); + }); + JLabel ch = new JLabel("ColumnHeader"); + scroll.setColumnHeaderView(ch); + JButton b1 = new JButton("Colhead"); + b1.addActionListener(e -> { + JPanel filler = new JPanel(); + filler.setSize(150, 150); + filler.setBackground(Color.yellow); + scroll.getColumnHeader().add(filler); + }); + JButton b2 = new JButton("Corners"); + b2.addActionListener(e -> { + JPanel filler1 = new JPanel(); + filler1.setSize(150, 150); + filler1.setBackground(Color.green); + scroll.setCorner(JScrollPane.LOWER_RIGHT_CORNER, filler1); + JPanel filler2 = new JPanel(); + filler2.setSize(150, 150); + filler2.setBackground(Color.green); + scroll.setCorner(JScrollPane.LOWER_LEFT_CORNER, filler2); + JPanel filler3 = new JPanel(); + filler3.setSize(150, 150); + filler3.setBackground(Color.green); + scroll.setCorner(JScrollPane.UPPER_RIGHT_CORNER, filler3); + JPanel filler4 = new JPanel(); + filler4.setSize(150, 150); + filler4.setBackground(Color.green); + scroll.setCorner(JScrollPane.UPPER_LEFT_CORNER, filler4); + }); + JLabel rh = new JLabel("RowHeader"); + scroll.setRowHeaderView(rh); + JButton b3 = new JButton("Rowhead"); + b3.addActionListener(e -> { + JPanel filler = new JPanel(); + filler.setSize(150, 150); + filler.setBackground(Color.yellow); + scroll.getRowHeader().add(filler); + }); + JButton b4 = new JButton("Viewport"); + b4.addActionListener(e -> { + JPanel filler = new JPanel(); + filler.setSize(150, 150); + filler.setBackground(Color.yellow); + scroll.getViewport().add(filler); + }); + + p.add(bn); + p.add(ba); + p.add(b1); + p.add(b2); + p.add(b3); + p.add(b4); + f.add(p); + f.setSize(300, 300); + return f; + } +} diff --git a/test/jdk/javax/swing/JScrollPane/bug4237517.java b/test/jdk/javax/swing/JScrollPane/bug4237517.java new file mode 100644 index 00000000000..4e1d1356199 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/bug4237517.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4237517 + * @summary Tests that scrolling with blit draws the right thing + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4237517 + */ + +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; + +public class bug4237517 { + static final String INSTRUCTIONS = """ + Select the first item in the list and hit PageDown + key two times. If the list is redrawn correctly, + i.e. if the digits go in order, then the test PASSES. + Otherwise, the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4237517 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4237517::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Scrolling Window Blit Test"); + String[] data = new String[100]; + + for (int counter = 0; counter < data.length; counter++) { + data[counter] = Integer.toString(counter); + } + JList list = new JList(data); + JScrollPane sp = new JScrollPane(list); + sp.getViewport().putClientProperty("EnableWindowBlit", Boolean.TRUE); + f.add(sp); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/JScrollPane/bug4237560.java b/test/jdk/javax/swing/JScrollPane/bug4237560.java new file mode 100644 index 00000000000..4f8f27683e5 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/bug4237560.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4237560 + * @summary Tests that JScrollPane do not distort TAB order in an HTML page + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4237560 + */ + +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JScrollPane; + +public class bug4237560 { + static final String INSTRUCTIONS = """ + A JEditorPane contains 10 input fields and is inserted into + JScrollPane. Click text field #8 so that it is selected. Press + TAB three times (even if text field #9 and #10 are not visible in + the ScrollPane). If this gives focus to the first text field (#1) + the test PASSES, else it FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4237560 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4237560::createUI) + .build() + .awaitAndCheck(); + } + + private static final String TEXT = "
                \n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "
                "; + + private static JFrame createUI() { + JFrame frame = new JFrame("JScrollPane HTML TAB Test"); + JEditorPane viewer = new JEditorPane("text/html", TEXT); + viewer.setEditable(false); + frame.add(new JScrollPane(viewer)); + frame.setSize(300, 300); + return frame; + } +} diff --git a/test/jdk/javax/swing/JScrollPane/bug4244899.java b/test/jdk/javax/swing/JScrollPane/bug4244899.java new file mode 100644 index 00000000000..4cb5367f4f5 --- /dev/null +++ b/test/jdk/javax/swing/JScrollPane/bug4244899.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4244899 + * @summary Tests whether scrolling with blit has artifacts + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4244899 + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +public class bug4244899 { + static final String INSTRUCTIONS = """ + Widen the first column of the table, so that + you get a horizontal scrollbar. Click in the + scrollbar (not on the thumb, but in the track). + If you notice some artifacts/flashing at + the bottom of the frame, the test FAILS. + Otherwise, the test PASSES. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4244899 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4244899::createUI) + .build() + .awaitAndCheck(); + } + + static class TestModel extends AbstractTableModel { + private final int rows = 20; + private final int cols = 5; + + private Integer[][] data; + + public TestModel() { + data = new Integer[rows][]; + int realCount = 0; + for (int counter = 0; counter < rows; counter++) { + data[counter] = new Integer[cols]; + for (int y = 0; y < cols; y++) { + data[counter][y] = Integer.valueOf(realCount); + realCount = (realCount + 1) % 23; + } + } + } + + public int getRowCount() { + return data.length; + } + + public int getColumnCount() { + return data[0].length; + } + + public Object getValueAt(int row, int column) { + return data[row][column]; + } + } + + static JFrame createUI() { + JFrame f = new JFrame("Scrolling Blit Artifact Test"); + JTable table = new JTable(new TestModel()); + JScrollPane sp = new JScrollPane(table); + sp.getViewport().putClientProperty("EnableWindowBlit", Boolean.TRUE); + table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + f.add(sp); + f.setSize(400, 400); + return f; + } +} diff --git a/test/jdk/javax/swing/JSlider/bug4186062.java b/test/jdk/javax/swing/JSlider/bug4186062.java new file mode 100644 index 00000000000..1db2f1bba6c --- /dev/null +++ b/test/jdk/javax/swing/JSlider/bug4186062.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4382876 + * @summary Tests if JSlider fires ChangeEvents when thumb is clicked and not moved + * @key headful + * @run main bug4186062 + */ + +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; + +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.SwingUtilities; +import javax.swing.event.ChangeListener; + +public class bug4186062 { + private static JFrame f; + private static JSlider slider; + private static volatile Point loc; + private static volatile int labelNum; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("JSlider Click Value Test"); + f.setSize(400, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + JPanel panel = new JPanel(); + slider = new JSlider(); + final JLabel label = new JLabel("0"); + labelNum = 0; + + ChangeListener listener = e -> { + labelNum++; + label.setText("" + labelNum); + }; + slider.addChangeListener(listener); + + panel.add(slider); + panel.add(label); + f.add(panel); + }); + + Robot r = new Robot(); + r.setAutoDelay(100); + r.waitForIdle(); + r.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + loc = slider.getLocationOnScreen(); + loc.setLocation(loc.x + (slider.getWidth() / 2), + loc.y + (slider.getHeight() / 2)); + }); + + r.mouseMove(loc.x, loc.y); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (labelNum > 0) { + throw new RuntimeException(labelNum + " ChangeEvents fired. " + + "Test failed"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JSlider/bug4275631.java b/test/jdk/javax/swing/JSlider/bug4275631.java new file mode 100644 index 00000000000..4d0aa555721 --- /dev/null +++ b/test/jdk/javax/swing/JSlider/bug4275631.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4275631 + * @summary Tests if vertical JSlider is properly aligned in large container + * @key headful + * @run main bug4275631 + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Point; +import java.awt.Robot; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.SwingUtilities; + +public class bug4275631 { + private static final int OFFSET = 1; + private static JFrame f; + private static JSlider slider1; + private static JSlider slider2; + private static volatile Point loc1; + private static volatile Point loc2; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("JSlider Alignment Test"); + f.setSize(400, 200); + f.setLocationRelativeTo(null); + + // Create two sliders, verify the alignment on the slider to be + // used in the border layout + slider1 = new JSlider(JSlider.VERTICAL, 0, 99, 50); + slider1.setInverted(true); + slider1.setMajorTickSpacing(10); + slider1.setMinorTickSpacing(1); + slider1.setPaintTicks(true); + slider1.setPaintLabels(true); + slider2 = new JSlider(JSlider.VERTICAL, 0, 99, 50); + slider2.setInverted(true); + slider2.setMajorTickSpacing(10); + slider2.setMinorTickSpacing(1); + slider2.setPaintTicks(true); + slider2.setPaintLabels(true); + + // Try to center the natural way, using a border layout in the "Center" + JPanel borderPanel = new JPanel(); + borderPanel.setLayout(new BorderLayout()); + borderPanel.setBorder(BorderFactory.createTitledBorder("BorderLayout")); + borderPanel.add(slider1, BorderLayout.CENTER); + borderPanel.setPreferredSize(new Dimension(200, 200)); + + // Try to center using GridBagLayout, with glue on left + // and right to squeeze slider into place + JPanel gridBagPanel = new JPanel(new GridBagLayout()); + gridBagPanel.setBorder(BorderFactory.createTitledBorder("GridBagLayout")); + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 1; + c.fill = GridBagConstraints.VERTICAL; + c.weighty = 1.0; + gridBagPanel.add(slider2, c); + c.gridx = 0; + c.fill = GridBagConstraints.BOTH; + c.weighty = 0.0; + gridBagPanel.add(Box.createHorizontalGlue(), c); + c.gridx = 2; + c.fill = GridBagConstraints.BOTH; + gridBagPanel.add(Box.createHorizontalGlue(), c); + gridBagPanel.setPreferredSize(new Dimension(200, 200)); + + f.add(borderPanel, BorderLayout.WEST); + f.add(gridBagPanel, BorderLayout.EAST); + f.setVisible(true); + }); + + Robot r = new Robot(); + r.setAutoDelay(100); + r.waitForIdle(); + r.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + loc1 = slider1.getLocationOnScreen(); + loc1.setLocation(loc1.x + (slider1.getWidth() / 2), + loc1.y + (slider1.getHeight() / 2)); + + loc2 = slider2.getLocationOnScreen(); + loc2.setLocation(loc2.x + (slider2.getWidth() / 2), + loc2.y + (slider2.getHeight() / 2)); + }); + + if (loc1.y > loc2.y + OFFSET || loc1.y < loc2.y - OFFSET) { + throw new RuntimeException("JSlider position is not aligned!"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/JSlider/bug4382876.java b/test/jdk/javax/swing/JSlider/bug4382876.java new file mode 100644 index 00000000000..b9ec64aab21 --- /dev/null +++ b/test/jdk/javax/swing/JSlider/bug4382876.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4382876 + * @summary Tests how PgUp and PgDn keys work with JSlider + * @key headful + * @run main bug4382876 + */ + +import java.awt.BorderLayout; +import java.awt.ComponentOrientation; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JSlider; +import javax.swing.SwingUtilities; + +public class bug4382876 { + private static Robot r; + private static JFrame f; + private static JSlider slider; + private static boolean upFail; + private static boolean downFail; + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("JSlider PageUp/Down Test"); + f.setSize(300, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + slider = new JSlider(-1000, -900, -1000); + slider.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + slider.putClientProperty("JSlider.isFilled", Boolean.TRUE); + f.add(slider, BorderLayout.CENTER); + }); + + r = new Robot(); + r.setAutoDelay(100); + r.waitForIdle(); + r.delay(1000); + + r.keyPress(KeyEvent.VK_PAGE_UP); + SwingUtilities.invokeAndWait(() -> { + if (slider.getValue() < -1000) { + System.out.println("PAGE_UP VAL: " + slider.getValue()); + upFail = true; + } + }); + if (upFail) { + writeFailImage(); + throw new RuntimeException("Slider value did NOT change with PAGE_UP"); + } + r.keyPress(KeyEvent.VK_PAGE_DOWN); + SwingUtilities.invokeAndWait(() -> { + if (slider.getValue() > -1000) { + System.out.println("PAGE_DOWN VAL: " + slider.getValue()); + downFail = true; + } + }); + if (downFail) { + writeFailImage(); + throw new RuntimeException("Slider value did NOT change with PAGE_DOWN"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static void writeFailImage() throws IOException { + GraphicsConfiguration ge = GraphicsEnvironment + .getLocalGraphicsEnvironment().getDefaultScreenDevice() + .getDefaultConfiguration(); + BufferedImage failImage = r.createScreenCapture(ge.getBounds()); + ImageIO.write(failImage, "png", new File("failImage.png")); + } +} diff --git a/test/jdk/javax/swing/JSplitPane/TestSplitPaneResetDividerLoc.java b/test/jdk/javax/swing/JSplitPane/TestSplitPaneResetDividerLoc.java new file mode 100644 index 00000000000..e43691f243c --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/TestSplitPaneResetDividerLoc.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8356594 + * @key headful + * @summary Verifies if JSplitPane loses divider location when + * reopened via JOptionPane.createDialog() + * @run main TestSplitPaneResetDividerLoc + */ + +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.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractAction; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +public class TestSplitPaneResetDividerLoc { + + private static JPanel lazyPanel; + private static JSplitPane splitPane; + private static JButton openDialogButton; + private static JDialog dialog; + private static JFrame frame; + private static volatile Point point; + private static volatile Rectangle size; + private static volatile int setLoc; + private static volatile int curLoc; + + private static boolean setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + return true; + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported LAF: " + laf.getClassName()); + return false; + } 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 LAF : " + laf.getClassName()); + try { + if (!setLookAndFeel(laf)) { + continue; + } + SwingUtilities.invokeAndWait(TestSplitPaneResetDividerLoc::createAndShowUI); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + point = openDialogButton.getLocationOnScreen(); + size = openDialogButton.getBounds(); + }); + robot.mouseMove(point.x + size.width / 2, point.y + size.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + int divLoc = splitPane.getDividerLocation(); + splitPane.setDividerLocation(divLoc + 200); + }); + robot.waitForIdle(); + robot.delay(1000); + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + + SwingUtilities.invokeAndWait(() -> { + setLoc = splitPane.getDividerLocation(); + System.out.println(setLoc); + }); + + robot.waitForIdle(); + robot.delay(1000); + robot.mouseMove(point.x + size.width / 2, point.y + size.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + curLoc = splitPane.getDividerLocation(); + System.out.println(curLoc); + }); + + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + + if (curLoc != setLoc) { + throw new RuntimeException("Divider location is not preserved"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + lazyPanel = null; + }); + } + } + } + + private static void createAndShowUI() { + frame = new JFrame("JSplitPane Divider Location"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + openDialogButton = new JButton(new AbstractAction("Open Dialog") { + public void actionPerformed(ActionEvent e) { + openDialogFromOptionPane(frame); + } + }); + + frame.getContentPane().add(openDialogButton, BorderLayout.CENTER); + frame.setSize(400, 100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void openDialogFromOptionPane(JFrame parent) { + if (lazyPanel == null) { + System.out.println("Creating lazy panel..."); + lazyPanel = new JPanel(new BorderLayout()); + + JPanel left = new JPanel(); + left.setBackground(Color.ORANGE); + JPanel right = new JPanel(); + right.setBackground(Color.LIGHT_GRAY); + + splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right); + splitPane.setPreferredSize(new Dimension(400, 200)); + + // Set initial divider location — not preserved across dialog openings in OpenJDK 24 + splitPane.setDividerLocation(120); + + lazyPanel.add(splitPane, BorderLayout.CENTER); + } + + JOptionPane optionPane = new JOptionPane(lazyPanel, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION); + dialog = optionPane.createDialog(parent, "SplitPane Dialog (JOptionPane)"); + dialog.setModal(false); + dialog.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JSplitPane/bug4820080.java b/test/jdk/javax/swing/JSplitPane/bug4820080.java new file mode 100644 index 00000000000..0702a3a2f59 --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/bug4820080.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Panel; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.JSplitPane; +import javax.swing.UIManager; + +/* + * @test + * @bug 4820080 7175397 + * @summary RFE: Cannot Change the JSplitPane Divider Color while dragging + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4820080 + */ + +public class bug4820080 { + private static final String INSTRUCTIONS = """ + Drag the dividers of the splitpanes (both top and bottom). If the divider + color is green while dragging then test passes, otherwise test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4820080::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4820080"); + UIManager.put("SplitPaneDivider.draggingColor", Color.GREEN); + + Box box = new Box(BoxLayout.Y_AXIS); + frame.add(box); + + JPanel jleft = new JPanel(); + jleft.setBackground(Color.DARK_GRAY); + jleft.setPreferredSize(new Dimension(100, 100)); + JPanel jright = new JPanel(); + jright.setBackground(Color.DARK_GRAY); + jright.setPreferredSize(new Dimension(100, 100)); + + JSplitPane jsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, jleft, jright); + jsp.setContinuousLayout(false); + box.add(jsp); + + box.add(Box.createVerticalStrut(5)); + box.add(new JSeparator()); + box.add(Box.createVerticalStrut(5)); + + Panel left = new Panel(); + left.setBackground(Color.DARK_GRAY); + left.setPreferredSize(new Dimension(100, 100)); + Panel right = new Panel(); + right.setBackground(Color.DARK_GRAY); + right.setPreferredSize(new Dimension(100, 100)); + + JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, right); + sp.setContinuousLayout(false); + box.add(sp); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/bug4613811.java b/test/jdk/javax/swing/JTabbedPane/bug4613811.java new file mode 100644 index 00000000000..ecad64e95f8 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/bug4613811.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4613811 + * @summary Scrollable Buttons of JTabbedPane don't + * get enabled or disabled on selecting tab + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4613811 + */ + +import java.awt.BorderLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JTabbedPane; + +public class bug4613811 { + private static final String INSTRUCTIONS = """ + Select different tabs and check that the scrollable + buttons are correctly enabled and disabled. + + When the very first tab (Tab 1) is fully visible + On macOS: + the left arrow button should NOT be visible. + + On other platforms: + the left arrow button should be disabled. + + If the last tab (Tab 5) is fully visible + On macOS: + the right arrow button should NOT be visible. + + On other platforms: + the right arrow button should be disabled. + + If the above is true press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(bug4613811::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JFrame frame = new JFrame("bug4613811 - JTabbedPane Test"); + final JTabbedPane tabPane = new JTabbedPane(JTabbedPane.TOP, + JTabbedPane.SCROLL_TAB_LAYOUT); + for (int i = 1; i <= 5; i++) { + tabPane.addTab("TabbedPane: Tab " + i, null, new JLabel("Tab " + i)); + } + frame.add(tabPane, BorderLayout.CENTER); + frame.setResizable(false); + frame.setSize(400, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/CheckBoxFirstClick.java b/test/jdk/javax/swing/JTable/CheckBoxFirstClick.java new file mode 100644 index 00000000000..91f8930103e --- /dev/null +++ b/test/jdk/javax/swing/JTable/CheckBoxFirstClick.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.BevelBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4115930 + * @summary Verify checkboxes in the table respond to first click. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckBoxFirstClick + */ + +public class CheckBoxFirstClick { + private static final String INSTRUCTIONS = """ + Click over the checkbox in the table. It should change state + on the first click. If not - press 'fail'. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(CheckBoxFirstClick::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("ListSizeBug"); + + // Take the dummy data from SwingSet. + final String[] names = {"First Name", "Last Name", "Favorite Color", + "Favorite Number", "Vegetarian"}; + final Object[][] data = { + {"Mark", "Andrews", "Red", 2, true}, + {"Tom", "Ball", "Blue", 99, false}, + {"Alan", "Chung", "Green", 838, false}, + {"Jeff", "Dinkins", "Turquois", 8, true}, + {"Amy", "Fowler", "Yellow", 3, false}, + {"Brian", "Gerhold", "Green", 0, false}, + {"James", "Gosling", "Pink", 21, false}, + {"David", "Karlton", "Red", 1, false}, + {"Dave", "Kloba", "Yellow", 14, false}, + {"Peter", "Korn", "Purple", 12, false}, + {"Phil", "Milne", "Purple", 3, false}, + {"Dave", "Moore", "Green", 88, false}, + {"Hans", "Muller", "Maroon", 5, false}, + {"Rick", "Levenson", "Blue", 2, false}, + {"Tim", "Prinzing", "Blue", 22, false}, + {"Chester", "Rose", "Black", 0, false}, + {"Ray", "Ryan", "Gray", 77, false}, + {"Georges", "Saab", "Red", 4, false}, + {"Willie", "Walker", "Phthalo Blue", 4, false}, + {"Kathy", "Walrath", "Blue", 8, false}, + {"Arnaud", "Weber", "Green", 44, false} + }; + + // Create a model of the data. + TableModel dataModel = new AbstractTableModel() { + // These methods always need to be implemented. + public int getColumnCount() { + return names.length; + } + + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + // The default implementations of these methods in + // AbstractTableModel would work, but we can refine them. + public String getColumnName(int column) { + return names[column]; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + public boolean isCellEditable(int row, int col) { + return true; + } + + public void setValueAt(Object aValue, int row, int column) { + System.out.println("Setting value to: " + aValue); + data[row][column] = aValue; + } + }; + + // Create the table + JTable tableView = new JTable(dataModel); + // Turn off auto-resizing so that we can set column sizes programmatically. + // In this mode, all columns will get their preferred widths, as set blow. + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + // Create a combo box to show that you can use one in a table. + JComboBox comboBox = new JComboBox(); + comboBox.addItem("Red"); + comboBox.addItem("Orange"); + comboBox.addItem("Yellow"); + comboBox.addItem("Green"); + comboBox.addItem("Blue"); + comboBox.addItem("Indigo"); + comboBox.addItem("Violet"); + + TableColumn colorColumn = tableView.getColumn("Favorite Color"); + // Use the combo box as the editor in the "Favorite Color" column. + colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); + + // Set a pink background and tooltip for the Color column renderer. + DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); + colorColumnRenderer.setBackground(Color.pink); + colorColumnRenderer.setToolTipText("Click for combo box"); + colorColumn.setCellRenderer(colorColumnRenderer); + + // Set a tooltip for the header of the colors column. + TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); + if (headerRenderer instanceof DefaultTableCellRenderer) + ((DefaultTableCellRenderer) headerRenderer).setToolTipText("Hi Mom!"); + + // Set the width of the "Vegetarian" column. + TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); + vegetarianColumn.setPreferredWidth(100); + + // Show the values in the "Favorite Number" column in different colors. + TableColumn numbersColumn = tableView.getColumn("Favorite Number"); + DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { + public void setValue(Object value) { + int cellValue = (value instanceof Number) ? ((Number) value).intValue() : 0; + setForeground((cellValue > 30) ? Color.black : Color.red); + setText((value == null) ? "" : value.toString()); + } + }; + numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); + numbersColumn.setCellRenderer(numberColumnRenderer); + numbersColumn.setPreferredWidth(110); + + // Finish setting up the table. + JScrollPane scrollpane = new JScrollPane(tableView); + scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane.setPreferredSize(new Dimension(430, 200)); + + frame.add(scrollpane); + frame.setSize(500, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/IllegalStateException.java b/test/jdk/javax/swing/JTable/IllegalStateException.java new file mode 100644 index 00000000000..427b81ab2d9 --- /dev/null +++ b/test/jdk/javax/swing/JTable/IllegalStateException.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.BevelBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4133143 + * @summary Illegal State exception in ComboBox editor in table + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual IllegalStateException + */ + +public class IllegalStateException { + private static final String INSTRUCTIONS = """ + Click on a cell in the first column, delete the contents but leave the editor with focus. + Click on the third column popping up a combo box. + Verify that the text editor loses focus. + If it does, press "pass", otherwise press "fail". + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(IllegalStateException::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("IllegalStateException"); + + // Take the dummy data from SwingSet. + final String[] names = {"First Name", "Last Name", "Favorite Color", + "Favorite Number", "Vegetarian"}; + final Object[][] data = { + {"Mark", "Andrews", "Red", 2, true}, + {"Tom", "Ball", "Blue", 99, false}, + {"Alan", "Chung", "Green", 838, false}, + {"Jeff", "Dinkins", "Turquois", 8, true}, + {"Amy", "Fowler", "Yellow", 3, false}, + {"Brian", "Gerhold", "Green", 0, false}, + {"James", "Gosling", "Pink", 21, false}, + {"David", "Karlton", "Red", 1, false}, + {"Dave", "Kloba", "Yellow", 14, false}, + {"Peter", "Korn", "Purple", 12, false}, + {"Phil", "Milne", "Purple", 3, false}, + {"Dave", "Moore", "Green", 88, false}, + {"Hans", "Muller", "Maroon", 5, false}, + {"Rick", "Levenson", "Blue", 2, false}, + {"Tim", "Prinzing", "Blue", 22, false}, + {"Chester", "Rose", "Black", 0, false}, + {"Ray", "Ryan", "Gray", 77, false}, + {"Georges", "Saab", "Red", 4, false}, + {"Willie", "Walker", "Phthalo Blue", 4, false}, + {"Kathy", "Walrath", "Blue", 8, false}, + {"Arnaud", "Weber", "Green", 44, false} + }; + + // Create a model of the data. + TableModel dataModel = new AbstractTableModel() { + // These methods always need to be implemented. + public int getColumnCount() { + return names.length; + } + + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + // The default implementations of these methods in + // AbstractTableModel would work, but we can refine them. + public String getColumnName(int column) { + return names[column]; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + public boolean isCellEditable(int row, int col) { + return true; + } + + public void setValueAt(Object aValue, int row, int column) { + System.out.println("Setting value to: " + aValue); + data[row][column] = aValue; + } + }; + + // Create the table + JTable tableView = new JTable(dataModel); + // Turn off auto-resizing so that we can set column sizes programmatically. + // In this mode, all columns will get their preferred widths, as set blow. + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + // Create a combo box to show that you can use one in a table. + JComboBox comboBox = new JComboBox(); + comboBox.addItem("Red"); + comboBox.addItem("Orange"); + comboBox.addItem("Yellow"); + comboBox.addItem("Green"); + comboBox.addItem("Blue"); + comboBox.addItem("Indigo"); + comboBox.addItem("Violet"); + + TableColumn colorColumn = tableView.getColumn("Favorite Color"); + // Use the combo box as the editor in the "Favorite Color" column. + colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); + + // Set a pink background and tooltip for the Color column renderer. + DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); + colorColumnRenderer.setBackground(Color.pink); + colorColumnRenderer.setToolTipText("Click for combo box"); + colorColumn.setCellRenderer(colorColumnRenderer); + + // Set a tooltip for the header of the colors column. + TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); + if (headerRenderer instanceof DefaultTableCellRenderer) + ((DefaultTableCellRenderer) headerRenderer).setToolTipText("Hi Mom!"); + + // Set the width of the "Vegetarian" column. + TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); + vegetarianColumn.setPreferredWidth(100); + + // Show the values in the "Favorite Number" column in different colors. + TableColumn numbersColumn = tableView.getColumn("Favorite Number"); + DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { + public void setValue(Object value) { + int cellValue = (value instanceof Number) ? ((Number) value).intValue() : 0; + setForeground((cellValue > 30) ? Color.black : Color.red); + setText((value == null) ? "" : value.toString()); + } + }; + numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); + numbersColumn.setCellRenderer(numberColumnRenderer); + numbersColumn.setPreferredWidth(110); + + // Finish setting up the table. + JScrollPane scrollpane = new JScrollPane(tableView); + scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane.setPreferredSize(new Dimension(430, 200)); + + frame.add(scrollpane); + frame.setSize(500, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/InternationalCharacters.java b/test/jdk/javax/swing/JTable/InternationalCharacters.java new file mode 100644 index 00000000000..1d8fc2c4576 --- /dev/null +++ b/test/jdk/javax/swing/JTable/InternationalCharacters.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.BevelBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4179066 + * @summary Tests that JTable prints AltGr characters (~\@|{}[]²µ³) + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual InternationalCharacters + */ + +public class InternationalCharacters { + private static final String INSTRUCTIONS = """ + Double-click an entry in the JTable. + Press Alt-Gr or Option with any key to type an international character. + Verify that the international character appears in the table. + If it does, press "pass", otherwise press "fail". + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(InternationalCharacters::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("InternationalCharacters test"); + // Take the dummy data from SwingSet. + final String[] names = {"First Name", "Last Name", "Favorite Color", + "Favorite Number", "Vegetarian"}; + final Object[][] data = { + {"Mark", "Andrews", "Red", 2, true}, + {"Tom", "Ball", "Blue", 99, false}, + {"Alan", "Chung", "Green", 838, false}, + {"Jeff", "Dinkins", "Turquois", 8, true}, + {"Amy", "Fowler", "Yellow", 3, false}, + {"Brian", "Gerhold", "Green", 0, false}, + {"James", "Gosling", "Pink", 21, false}, + {"David", "Karlton", "Red", 1, false}, + {"Dave", "Kloba", "Yellow", 14, false}, + {"Peter", "Korn", "Purple", 12, false}, + {"Phil", "Milne", "Purple", 3, false}, + {"Dave", "Moore", "Green", 88, false}, + {"Hans", "Muller", "Maroon", 5, false}, + {"Rick", "Levenson", "Blue", 2, false}, + {"Tim", "Prinzing", "Blue", 22, false}, + {"Chester", "Rose", "Black", 0, false}, + {"Ray", "Ryan", "Gray", 77, false}, + {"Georges", "Saab", "Red", 4, false}, + {"Willie", "Walker", "Phthalo Blue", 4, false}, + {"Kathy", "Walrath", "Blue", 8, false}, + {"Arnaud", "Weber", "Green", 44, false} + }; + + // Create a model of the data. + TableModel dataModel = new AbstractTableModel() { + // These methods always need to be implemented. + public int getColumnCount() { return names.length; } + public int getRowCount() { return data.length;} + public Object getValueAt(int row, int col) {return data[row][col];} + + // The default implementations of these methods in + // AbstractTableModel would work, but we can refine them. + public String getColumnName(int column) {return names[column];} + public Class getColumnClass(int c) {return getValueAt(0, c).getClass();} + public boolean isCellEditable(int row, int col) {return true;} + public void setValueAt(Object aValue, int row, int column) { + System.out.println("Setting value to: " + aValue); + data[row][column] = aValue; + } + }; + + // Create the table + JTable tableView = new JTable(dataModel); + // Turn off auto-resizing so that we can set column sizes programmatically. + // In this mode, all columns will get their preferred widths, as set blow. + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + // Create a combo box to show that you can use one in a table. + JComboBox comboBox = new JComboBox(); + comboBox.addItem("Red"); + comboBox.addItem("Orange"); + comboBox.addItem("Yellow"); + comboBox.addItem("Green"); + comboBox.addItem("Blue"); + comboBox.addItem("Indigo"); + comboBox.addItem("Violet"); + + TableColumn colorColumn = tableView.getColumn("Favorite Color"); + // Use the combo box as the editor in the "Favorite Color" column. + colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); + + // Set a pink background and tooltip for the Color column renderer. + DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); + colorColumnRenderer.setBackground(Color.pink); + colorColumnRenderer.setToolTipText("Click for combo box"); + colorColumn.setCellRenderer(colorColumnRenderer); + + // Set a tooltip for the header of the colors column. + TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); + if (headerRenderer instanceof DefaultTableCellRenderer) + ((DefaultTableCellRenderer)headerRenderer).setToolTipText("Hi Mom!"); + + // Set the width of the "Vegetarian" column. + TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); + vegetarianColumn.setPreferredWidth(100); + + // Show the values in the "Favorite Number" column in different colors. + TableColumn numbersColumn = tableView.getColumn("Favorite Number"); + DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { + public void setValue(Object value) { + int cellValue = (value instanceof Number) ? ((Number)value).intValue() : 0; + setForeground((cellValue > 30) ? Color.black : Color.red); + setText((value == null) ? "" : value.toString()); + } + }; + numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); + numbersColumn.setCellRenderer(numberColumnRenderer); + numbersColumn.setPreferredWidth(110); + + // Finish setting up the table. + JScrollPane scrollpane = new JScrollPane(tableView); + scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane.setPreferredSize(new Dimension(430, 200)); + + frame.add(scrollpane); + frame.setSize(500, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/NullTableHeader.java b/test/jdk/javax/swing/JTable/NullTableHeader.java new file mode 100644 index 00000000000..dc62b975d04 --- /dev/null +++ b/test/jdk/javax/swing/JTable/NullTableHeader.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4129409 + * @summary Tests that JTable.setTableHeader(null) doesn't break AutoResize + * @key headful + * @run main NullTableHeader + */ + +public class NullTableHeader { + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + JTable tableView = new JTable(); + tableView.setTableHeader(null); + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + }); + } +} diff --git a/test/jdk/javax/swing/JTable/ShiftClick.java b/test/jdk/javax/swing/JTable/ShiftClick.java new file mode 100644 index 00000000000..4d617b5eeda --- /dev/null +++ b/test/jdk/javax/swing/JTable/ShiftClick.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import javax.swing.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.border.BevelBorder; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4201917 + * @summary Shift Click in table before making selection + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ShiftClick + */ + +public class ShiftClick { + private static final String INSTRUCTIONS = """ + Shift click in the table. Check that all cells + from the first through where you clicked are selected. + If the cells are selected, press pass, otherwise fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(ShiftClick::createTestUI) + .logArea(6) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("ShiftClick"); + + // Take the dummy data from SwingSet. + final String[] names = {"First Name", "Last Name", "Favorite Color", + "Favorite Number", "Vegetarian"}; + final Object[][] data = { + {"Mark", "Andrews", "Red", 2, true}, + {"Tom", "Ball", "Blue", 99, false}, + {"Alan", "Chung", "Green", 838, false}, + {"Jeff", "Dinkins", "Turquois", 8, true}, + {"Amy", "Fowler", "Yellow", 3, false}, + {"Brian", "Gerhold", "Green", 0, false}, + {"James", "Gosling", "Pink", 21, false}, + {"David", "Karlton", "Red", 1, false}, + {"Dave", "Kloba", "Yellow", 14, false}, + {"Peter", "Korn", "Purple", 12, false}, + {"Phil", "Milne", "Purple", 3, false}, + {"Dave", "Moore", "Green", 88, false}, + {"Hans", "Muller", "Maroon", 5, false}, + {"Rick", "Levenson", "Blue", 2, false}, + {"Tim", "Prinzing", "Blue", 22, false}, + {"Chester", "Rose", "Black", 0, false}, + {"Ray", "Ryan", "Gray", 77, false}, + {"Georges", "Saab", "Red", 4, false}, + {"Willie", "Walker", "Phthalo Blue", 4, false}, + {"Kathy", "Walrath", "Blue", 8, false}, + {"Arnaud", "Weber", "Green", 44, false} + }; + + // Create a model of the data. + TableModel dataModel = new AbstractTableModel() { + // These methods always need to be implemented. + public int getColumnCount() { + return names.length; + } + + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + // The default implementations of these methods in + // AbstractTableModel would work, but we can refine them. + public String getColumnName(int column) { + return names[column]; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + public boolean isCellEditable(int row, int col) { + return true; + } + + public void setValueAt(Object aValue, int row, int column) { + System.out.println("Setting value to: " + aValue); + data[row][column] = aValue; + } + }; + + // Create the table + JTable tableView = new JTable(dataModel); + // Turn off auto-resizing so that we can set column sizes programmatically. + // In this mode, all columns will get their preferred widths, as set blow. + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + + // Create a combo box to show that you can use one in a table. + JComboBox comboBox = new JComboBox(); + comboBox.addItem("Red"); + comboBox.addItem("Orange"); + comboBox.addItem("Yellow"); + comboBox.addItem("Green"); + comboBox.addItem("Blue"); + comboBox.addItem("Indigo"); + comboBox.addItem("Violet"); + + TableColumn colorColumn = tableView.getColumn("Favorite Color"); + // Use the combo box as the editor in the "Favorite Color" column. + colorColumn.setCellEditor(new DefaultCellEditor(comboBox)); + + // Set a pink background and tooltip for the Color column renderer. + DefaultTableCellRenderer colorColumnRenderer = new DefaultTableCellRenderer(); + colorColumnRenderer.setBackground(Color.pink); + colorColumnRenderer.setToolTipText("Click for combo box"); + colorColumn.setCellRenderer(colorColumnRenderer); + + // Set a tooltip for the header of the colors column. + TableCellRenderer headerRenderer = colorColumn.getHeaderRenderer(); + if (headerRenderer instanceof DefaultTableCellRenderer) + ((DefaultTableCellRenderer) headerRenderer).setToolTipText("Hi Mom!"); + + // Set the width of the "Vegetarian" column. + TableColumn vegetarianColumn = tableView.getColumn("Vegetarian"); + vegetarianColumn.setPreferredWidth(100); + + // Show the values in the "Favorite Number" column in different colors. + TableColumn numbersColumn = tableView.getColumn("Favorite Number"); + DefaultTableCellRenderer numberColumnRenderer = new DefaultTableCellRenderer() { + public void setValue(Object value) { + int cellValue = (value instanceof Number) ? ((Number) value).intValue() : 0; + setForeground((cellValue > 30) ? Color.black : Color.red); + setText((value == null) ? "" : value.toString()); + } + }; + numberColumnRenderer.setHorizontalAlignment(JLabel.RIGHT); + numbersColumn.setCellRenderer(numberColumnRenderer); + numbersColumn.setPreferredWidth(110); + + // Finish setting up the table. + JScrollPane scrollpane = new JScrollPane(tableView); + scrollpane.setBorder(new BevelBorder(BevelBorder.LOWERED)); + scrollpane.setPreferredSize(new Dimension(430, 200)); + + frame.add(scrollpane); + frame.setSize(500, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4118307.java b/test/jdk/javax/swing/JTable/bug4118307.java new file mode 100644 index 00000000000..537e92176ef --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4118307.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4118307 + * @summary Tests that JTable's cell editor for Number and Date work correctly + * @key headful + * @run main bug4118307 + */ + +public class bug4118307 { + static JFrame frame; + static MyTable tbl; + static Point tableLoc; + static Point p; + private static volatile boolean flag; + static final String[] columnNames = {"Integer", "Double"}; + static final Object[][] data = { + {5, 3.14}, + {10, 2.71}, + {70, 3.14}, + {200, 2.71}, + }; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(250); + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + tableLoc = tbl.getLocationOnScreen(); + p = tbl.getCellRect(0, 0, true).getLocation(); + }); + robot.waitForIdle(); + + robot.mouseMove(tableLoc.x + p.x + 10, tableLoc.y + p.y + 10); + robot.waitForIdle(); + + 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.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> + p = tbl.getCellRect(1, 1, true).getLocation()); + robot.waitForIdle(); + + robot.mouseMove(tableLoc.x + p.x + 10, tableLoc.y + p.y + 10); + robot.waitForIdle(); + + 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.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> + p = tbl.getCellRect(1, 0, true).getLocation()); + robot.waitForIdle(); + + robot.mouseMove(tableLoc.x + p.x + 10, tableLoc.y + p.y + 10); + robot.waitForIdle(); + + 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.waitForIdle(); + robot.delay(5000); + + if (!flag) { + throw new RuntimeException("Test Failed."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4118307"); + MyTableModel myModel = new MyTableModel(); + tbl = new MyTable(myModel); + JScrollPane sp = new JScrollPane(tbl); + flag = true; + + frame.add(sp, BorderLayout.CENTER); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + static class MyTable extends JTable { + public MyTable(TableModel tm) { + super(tm); + } + + public Component prepareRenderer(TableCellRenderer rend, int row, int col) { + try { + return super.prepareRenderer(rend, row, col); + } catch (Exception e) { + e.printStackTrace(); + flag = false; + return null; + } + } + } + + static class MyTableModel extends AbstractTableModel { + public int getColumnCount() { + return columnNames.length; + } + + public int getRowCount() { + return data.length; + } + + @Override + public String getColumnName(int col) { + return columnNames[col]; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + @Override + public boolean isCellEditable(int row, int col) { + return true; + } + + @Override + public void setValueAt(Object value, int row, int col) { + data[row][col] = value; + } + } +} diff --git a/test/jdk/javax/swing/JTable/bug4128506.java b/test/jdk/javax/swing/JTable/bug4128506.java new file mode 100644 index 00000000000..21273c6f318 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4128506.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; + +/* + * @test + * @bug 4128506 + * @summary Tests that JTable with AUTO_RESIZE_ALL_COLUMNS correctly compute width of columns + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4128506 + */ + +public class bug4128506 { + private static final String INSTRUCTIONS = """ + If the columns of JTable have the same width the test passes, else test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4128506::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + final Object[][] data = { + {"cell_1_1", "cell_1_2", "cell_1_3"}, + {"cell_2_1", "cell_2_2", "cell_2_3"}, + {"cell_3_1", "cell_3_2", "cell_3_3"}, + {"cell_4_1", "cell_4_2", "cell_4_3"}, + }; + + TableModel dataModel = new AbstractTableModel() { + public int getColumnCount() { + return 3; + } + + public int getRowCount() { + return data.length; + } + + public Object getValueAt(int row, int col) { + return data[row][col]; + } + }; + + JFrame frame = new JFrame("bug4128506"); + JTable tableView = new JTable(dataModel); + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); + tableView.getColumnModel().getColumn(1).setMinWidth(5); + JScrollPane scrollpane = new JScrollPane(tableView); + frame.add(scrollpane); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4129401.java b/test/jdk/javax/swing/JTable/bug4129401.java new file mode 100644 index 00000000000..37765d34698 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4129401.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.DefaultCellEditor; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.TableColumn; + +/* + * @test + * @bug 4129401 + * @summary Tests that keystroking for combobox cell editor in JTable works + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4129401 + */ + +public class bug4129401 { + private static final String INSTRUCTIONS = """ + 1. Move the mouse cursor to the cell "CELL 2 1", + which contains JComboBox and click left mouse button + to drop down combobox list. + 2. Change selected item in the combobox list + using up and down arrows. + 3. Press Esc. JComboBox drop down list should hide. + If all was successful then test passes, else test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4129401::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + Object data[][] = new Object[4][2]; + JComboBox cb = new JComboBox(); + cb.addItem("Item1"); + cb.addItem("Item2"); + cb.addItem("Item3"); + cb.addItem("Item4"); + data[0][0] = "CELL 0 0"; + data[0][1] = "CELL 0 1"; + data[1][0] = "CELL 1 0"; + data[1][1] = "CELL 1 1"; + data[2][0] = "CELL 2 0"; + data[2][1] = "CELL 2 1"; + data[3][0] = "CELL 3 0"; + data[3][1] = "CELL 3 1"; + String[] str = {"Column 0", "Column 1"}; + JTable tbl = new JTable(data, str); + JScrollPane sp = new JScrollPane(tbl); + + TableColumn col = tbl.getColumn("Column 1"); + col.setCellEditor(new DefaultCellEditor(cb)); + + JFrame f = new JFrame("4129401 test"); + f.getContentPane().add(sp); + f.setBounds(100, 100, 300, 300); + return f; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4138158.java b/test/jdk/javax/swing/JTable/bug4138158.java new file mode 100644 index 00000000000..400b8b1952e --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4138158.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; + +/* + * @test + * @bug 4138158 + * @summary Tests that setAutoscrolls(false) locks autoscroll + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4138158 + */ + +public class bug4138158 { + private static final String INSTRUCTIONS = """ + Move mouse to beginning of table, press left mouse button and drag mouse down + below the frame. If the table isn't scrolled down then test passes. + If the table is scrolled then test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4138158::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4138158"); + JTable table = new JTable(20, 3); + table.setAutoscrolls(false); + JScrollPane sp = new JScrollPane(table); + frame.add(sp); + frame.setSize(200, 200); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4139910.java b/test/jdk/javax/swing/JTable/bug4139910.java new file mode 100644 index 00000000000..c9d6d62cf0c --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4139910.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.DefaultTableModel; + +/* + * @test + * @bug 4139910 + * @summary Column resize mouse pointer doesn't display in non-resizable JTable. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4139910 + */ + +public class bug4139910 { + private static final String INSTRUCTIONS = """ + Move mouse pointer to the position between "A" and "B" headers. + If mouse pointer does not change its shape then test passes. If + it does then test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4139910::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4139910"); + + String[] colName = {"A", "B"}; + JTable tbl = new JTable(new DefaultTableModel(colName, 6)); + tbl.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + tbl.getTableHeader().setReorderingAllowed(false); + tbl.getTableHeader().setResizingAllowed(false); + JScrollPane sp = new JScrollPane(tbl); + frame.add(sp); + + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4188504.java b/test/jdk/javax/swing/JTable/bug4188504.java new file mode 100644 index 00000000000..b58ee7def03 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4188504.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4188504 + * @summary setResizable for specified column. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4188504 + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; + +public class bug4188504 { + private static final String INSTRUCTIONS = """ + 1. A table is displayed with 3 columns - A, B, C. + + 2. Try to resize second column of table (Move mouse to the position + between "B" and "C" headers, press left mouse button and move to + right/left). + PLEASE NOTE: You may be able to swap the columns but make sure the + width of column B stays the same. + + 3. If the second column does not change its width then press PASS + otherwise press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(createAndShowUI()) + .build() + .awaitAndCheck(); + } + + private static JFrame createAndShowUI() { + JFrame jFrame = new JFrame("bug4188504"); + JTable tableView = new JTable(4, 3); + tableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + tableView.getColumnModel().getColumn(1).setResizable(false); + + jFrame.add(new JScrollPane(tableView)); + jFrame.setSize(300, 150); + return jFrame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4190222.java b/test/jdk/javax/swing/JTable/bug4190222.java new file mode 100644 index 00000000000..5d6fcd2b0cc --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4190222.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.Robot; +import java.util.Vector; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; + +/* + * @test + * @bug 4190222 + * @summary Setting data vector on the model correctly repaint table + * @key headful + * @run main bug4190222 + */ + +public class bug4190222 { + static JFrame frame; + static DefaultTableModel dtm; + static JTable tbl; + + static Vector data; + static Vector colNames; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(250); + + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + Dimension preResize = tbl.getSize(); + dtm.setDataVector(data, colNames); + + if (!preResize.equals(tbl.getSize())) { + throw new RuntimeException("Size of table changed after resizing."); + } + }); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createTestUI() { + frame = new JFrame("bug4190222"); + + data = new Vector(1, 1); + colNames = new Vector(3); + for (int i = 1; i < 4; i++) { + Vector row = new Vector(1, 1); + row.addElement("Row " + i + ", Col 1"); + row.addElement("Row " + i + ", Col 2"); + row.addElement("Row " + i + ", Col 3"); + data.addElement(row); + } + colNames.addElement("Col 1"); + colNames.addElement("Col 2"); + colNames.addElement("Col 3"); + + dtm = new DefaultTableModel(data, colNames); + tbl = new JTable(dtm); + JScrollPane scrollPane = new JScrollPane(tbl); + frame.add("Center", scrollPane); + JPanel panel = new JPanel(); + frame.add("South", panel); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +} diff --git a/test/jdk/javax/swing/JTable/bug4193727.java b/test/jdk/javax/swing/JTable/bug4193727.java new file mode 100644 index 00000000000..2ef4159e90c --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4193727.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.FontMetrics; +import java.util.Vector; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; + +/* + * @test + * @bug 4193727 + * @summary Tests that resizing JTable via TableColumn's + * setWidth(int) repaints correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4193727 + */ + +public class bug4193727 { + static EnhancedJTable tblResults; + static JButton bTest = new JButton("Resize"); + + private static final String INSTRUCTIONS = """ + Push button "Resize". + If either of the following happen, test fails: + 1) The size of the columns change + 2) The JTable is not repainted correctly + + Otherwise test passes. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4193727::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4193727"); + Vector v = new Vector(); + Vector data = new Vector(); + Vector cols = new Vector(); + + cols.add("Name"); + cols.add("Address"); + data.add("Steve"); + data.add("100 East Main Street"); + v.add(data); + + data.add("Richard"); + data.add("99 Main Road"); + v.add(data); + + frame.setLayout(new BorderLayout()); + tblResults = new EnhancedJTable(v, cols); + MyTableHeader mth = new MyTableHeader(); + for (int i = 0; i < tblResults.getColumnCount(); i++) + tblResults.getColumnModel().getColumn(i).setHeaderRenderer(mth.getTHR()); + tblResults.setAutoResizeMode(EnhancedJTable.AUTO_RESIZE_OFF); + + JScrollPane pane = new JScrollPane(tblResults); + frame.add(pane, BorderLayout.CENTER); + JPanel panel = new JPanel(); + panel.add(bTest); + frame.add(panel, BorderLayout.EAST); + bTest.addActionListener(e -> tblResults.autoSizeColumns()); + frame.setSize(300, 200); + return frame; + } +} + +class MyTableHeader extends TableColumn { + public TableCellRenderer getTHR() { + return createDefaultHeaderRenderer(); + } +} + +class EnhancedJTable extends JTable { + public EnhancedJTable(Vector data, Vector colNames) { + super(data, colNames); + } + + public synchronized void autoSizeColumns() { + setAutoResizeMode(AUTO_RESIZE_OFF); + int colcnt = getColumnCount(); + int rowcnt = getRowCount(); + + for (int i = 0; i < colcnt; i++) { + // get the max column width needed + Component cell = getColumnModel().getColumn(i).getHeaderRenderer() + .getTableCellRendererComponent(this, null, false, false, -1, i); + FontMetrics fm = cell.getFontMetrics(cell.getFont()); + int max = SwingUtilities.computeStringWidth(fm, getColumnModel().getColumn(i).getHeaderValue() + .toString() + " "); + for (int j = 0; j < rowcnt; j++) { + // add 2 spaces to account for gutter + int width = SwingUtilities.computeStringWidth(fm, getValueAt(j, i).toString() + " "); + if (max < width) max = width; + } + // set the new column width + getColumnModel().getColumn(i).setWidth(max); + } + } +} diff --git a/test/jdk/javax/swing/JTable/bug4224179.java b/test/jdk/javax/swing/JTable/bug4224179.java new file mode 100644 index 00000000000..b223f3f4716 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4224179.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.Dimension; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; + +/* + * @test + * @bug 4224179 + * @summary Tests if Table default cell editor doesn't handle % (percent) character correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4224179 + */ + +public class bug4224179 { + private static final String INSTRUCTIONS = """ + 1. Click ONCE on the center cell ("Huml") + 2. Type the following symbols one after another: a%b + + If the center cell doesn't read "Humla%b" the test fails. + + 3. After the above, press the ESCAPE key and note that the cell + reverts back to "Huml" + 4. Do the stuff in part 1 again + 5. Press the ESCAPE key + + If the center cell now reads "Huml" as it initially was, + the test passed and fails otherwise. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4224179::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4224179"); + JTable table = new JTable(3, 3); + table.setValueAt("Huml", 1, 1); + table.setPreferredScrollableViewportSize(new Dimension(500, 70)); + JScrollPane scrollPane = new JScrollPane(table); + frame.add(scrollPane, BorderLayout.CENTER); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4226181.java b/test/jdk/javax/swing/JTable/bug4226181.java new file mode 100644 index 00000000000..70749cf5d55 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4226181.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.GridLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +/* + * @test + * @bug 4226181 + * @summary Tests that JTable setModel() correctly re-sizes and counts columns + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4226181 + */ + +public class bug4226181 { + private static final String INSTRUCTIONS = """ + Take a look at the table and remember the number of columns you see. + Now press the "setModel" button. If the number of columns has changed, + then test fails, otherwise it passes. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4226181::createTestUI) + .build() + .awaitAndCheck(); + } + + static class TestModel extends AbstractTableModel { + public int getRowCount() { + return 5; + } + + public int getColumnCount() { + return 7; + } + + public Object getValueAt(int row, int column) { + return row + ":" + column; + } + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4226181"); + TestModel testModel = new TestModel(); + final JTable t = new JTable(testModel); + JButton b = new JButton("setModel"); + b.addActionListener(ae -> t.setModel(new TestModel())); + t.setCellSelectionEnabled(true); + JPanel p1 = new JPanel(new GridLayout(1, 2)); + p1.add(new JLabel("dummy")); + p1.add(t); + frame.add(p1); + frame.add(b, BorderLayout.SOUTH); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/javax/swing/JTable/bug4239157.java b/test/jdk/javax/swing/JTable/bug4239157.java new file mode 100644 index 00000000000..025af1615e0 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4239157.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.DefaultCellEditor; +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableColumn; + +/* + * @test + * @bug 4239157 + * @summary Tests that JTable performs cell validation properly + * (i.e. does not accept entries for which stopCellEditing() + * returns false) + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4239157 + */ + +public class bug4239157 { + private static final String INSTRUCTIONS = """ + You see a JTable having one row and two columns. + Click in the very first cell (where "click here" is displayed). + Edit its content (e.g. type some letters) and press right arrow key. + The edited cell should stay active, its content shouldn't change. + The right cell (that with text "inactive forever") shouldn't become active. + The same should be true when you press Tab key. + If it is so, test passes, otherwise it fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4239157::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4239157"); + JTable table = new JTable(new Object[][]{{"click here", + "inactive forever"}}, + new Object[]{"1", "2"}); + frame.add("Center", table); + TableColumn column = table.getColumn("1"); + TableCellEditor editor = new TestEditor(new JTextField()); + column.setCellEditor(editor); + + frame.pack(); + return frame; + } + + static class TestEditor extends DefaultCellEditor { + public TestEditor(JTextField tf) { + super(tf); + } + + public boolean stopCellEditing() { + return false; + } + } +} diff --git a/test/jdk/javax/swing/JTable/bug4242631.java b/test/jdk/javax/swing/JTable/bug4242631.java new file mode 100644 index 00000000000..6e9d1eddc32 --- /dev/null +++ b/test/jdk/javax/swing/JTable/bug4242631.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.ArrayList; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.table.AbstractTableModel; + +/* + * @test + * @bug 4242631 + * @summary Tests that JTable repaints itself correctly after a record + * has been removed and added to the table model. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4242631 + */ + +public class bug4242631 { + private static JButton addButton; + private static JButton removeButton; + private static JButton bothButton; + private static SimpleTableModel tableModel; + + private static final String INSTRUCTIONS = """ + Press Add button to add a record to the table. The record added should + have number 0. Then press Remove/Add button some times. The record number + should increase as you press. If it does not, test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4242631::createTestUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createTestUI() { + JFrame frame = new JFrame("bug4242631"); + GridBagLayout grid = new GridBagLayout(); + + frame.setLayout(grid); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(2, 2, 2, 2); + + // Add button. + c.gridx = 0; + c.gridy = 0; + grid.setConstraints(addButton = new JButton("Add"), c); + frame.add(addButton); + + // Edit button. + c.gridx = 1; + c.gridy = 0; + grid.setConstraints(removeButton = new JButton("Remove"), c); + frame.add(removeButton); + + // Remove button. + c.gridx = 2; + c.gridy = 0; + grid.setConstraints(bothButton = new JButton("Remove/Add"), c); + frame.add(bothButton); + + // Table. + c.gridx = 0; + c.gridy = 1; + c.gridwidth = 6; + c.gridheight = 0; + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1.0; + c.weighty = 1.0; + JScrollPane scroll = null; + tableModel = new SimpleTableModel(); + grid.setConstraints(scroll = new JScrollPane(new JTable(tableModel)), c); + frame.add(scroll); + + // Create some action listeners. + addButton.addActionListener(event -> tableModel.addRow()); + removeButton.addActionListener(event -> tableModel.removeRow()); + bothButton.addActionListener(event -> tableModel.removeThenAddRow()); + + frame.pack(); + return frame; + } + + static class SimpleTableModel extends AbstractTableModel { + int counter = 0; + ArrayList list = new ArrayList(); + + public SimpleTableModel() {} + public int getColumnCount() { return 1; } + public int getRowCount() { return list.size(); } + + public Object getValueAt(int row, int col) { + String str = (String) list.get(row); + return str;// + "." + col; + } + + public void addRow() { + list.add("" + counter++); + fireTableRowsInserted(list.size() - 1, list.size() - 1); + } + + public void removeRow() { + if (list.size() == 0) return; + list.remove(list.size() - 1); + fireTableRowsDeleted(list.size(), list.size()); + } + + public void removeThenAddRow() { + if (list.size() == 0) return; + removeRow(); + addRow(); + } + } +} diff --git a/test/jdk/javax/swing/JTextArea/4697612/bug4697612.java b/test/jdk/javax/swing/JTextArea/4697612/bug4697612.java index ed7f3dba73f..ee01c38ed67 100644 --- a/test/jdk/javax/swing/JTextArea/4697612/bug4697612.java +++ b/test/jdk/javax/swing/JTextArea/4697612/bug4697612.java @@ -224,7 +224,7 @@ private static void createAndShowGUI() { text = new JTextArea(); try { InputStream is = - bug4697612.class.getResourceAsStream("bug4697612.txt"); + bug4697612.class.getResourceAsStream("bug4697612.java"); text.read(new InputStreamReader(is), null); } catch (IOException e) { throw new Error(e); diff --git a/test/jdk/javax/swing/JTextArea/4697612/bug4697612.txt b/test/jdk/javax/swing/JTextArea/4697612/bug4697612.txt deleted file mode 100644 index f7273541285..00000000000 --- a/test/jdk/javax/swing/JTextArea/4697612/bug4697612.txt +++ /dev/null @@ -1,221 +0,0 @@ - README - - Java(TM) 2 SDK, Standard Edition - Version 1.4.2 Beta - - For a more extensive HTML version of this file, see README.html. - -Contents - - * Introduction - * Release Notes - * Bug Reports and Feedback - * Java 2 SDK Documentation - * Redistribution - * Web Pages - - -Introduction - - Thank you for downloading this release of the Java(TM) 2 SDK, - Standard Edition. The Java 2 SDK is a development environment for - building applications, applets, and components that can be - deployed on the Java platform. - - The Java 2 SDK software includes tools useful for developing and - testing programs written in the Java programming language and - running on the Java platform. These tools are designed to be used - from the command line. Except for appletviewer, these tools do not - provide a graphical user interface. - - -Release Notes - - See the Release Notes on the Java Software web site for additional - information pertaining to this release. - - http://java.sun.com/j2se/1.4.2/relnotes.html - - The on-line release notes will be updated as needed, so you should - check it occasionally for the latest information. - - -Bug Reports and Feedback - - The Bug Parade Web Page on the Java Developer Connection(SM) web - site lets you search for and examine existing bug reports, submit - your own bug reports, and tell us which bug fixes matter most to you. - - http://java.sun.com/jdc/bugParade/ - - To directly submit a bug or request a feature, fill out this form: - - http://java.sun.com/cgi-bin/bugreport.cgi - - You can also send comments directly to Java Software engineering - team email addresses. - - http://java.sun.com/mail/ - - -Java 2 SDK Documentation - - The on-line Java 2 SDK Documentation contains API specifications, - feature descriptions, developer guides, tool reference pages, demos, - and links to related information. It is located at - - http://java.sun.com/j2se/1.4.2/docs/ - - The Java 2 SDK documentation is also available in a download bundle - which you can install locally on your machine. See the - Java 2 SDK download page: - - http://java.sun.com/j2se/1.4.2/download.html - - -Redistribution - - The term "vendors" used here refers to licensees, developers, - and independent software vendors (ISVs) who license and - distribute the Java 2 Runtime Environment with their programs. - Vendors must follow the terms of the Java 2 SDK, Standard - Edition, Binary Code License agreement. - Required vs. Optional Files - - The files that make up the Java 2 SDK, Standard Edition, are - divided into two categories: required and optional. Optional - files may be excluded from redistributions of the Java 2 SDK - at the vendor's discretion. The following section contains a - list of the files and directories that may optionally be - omitted from redistributions of the Java 2 SDK. All files not - in these lists of optional files must be included in - redistributions of the Java 2 SDK. - - Optional Files and Directories - - The following files may be optionally excluded from - redistributions: - - jre/lib/charsets.jar - Character conversion classes - jre/lib/ext/ - sunjce_provider.jar - the SunJCE provider for Java - Cryptography APIs - localedata.jar - contains many of the resources - needed for non US English locales - ldapsec.jar - contains security features supported - by the LDAP service provider - dnsns.jar - for the InetAddress wrapper of JNDI DNS - provider - bin/rmid and jre/bin/rmid - Java RMI Activation System Daemon - bin/rmiregistry and jre/bin/rmiregistry - Java Remote Object Registry - bin/tnameserv and jre/bin/tnameserv - Java IDL Name Server - bin/keytool and jre/bin/keytool - Key and Certificate Management Tool - bin/kinit and jre/bin/kinit - Used to obtain and cache Kerberos ticket-granting tickets - bin/klist and jre/bin/klist - Kerberos display entries in credentials cache and keytab - bin/ktab and jre/bin/ktab - Kerberos key table manager - bin/policytool and jre/bin/policytool - Policy File Creation and Management Tool - bin/orbd and jre/bin/orbd - Object Request Broker Daemon - bin/servertool and jre/bin/servertool - Java IDL Server Tool - src.zip - Archive of source files - - In addition, the Java Web Start product may be excluded from - redistributions. The Java Web Start product is contained in a - file named javaws-1_2-solaris-sparc-i.zip, - javaws-1_2-solaris-i586-i.zip, - javaws-1_2-linux-i586-i.zip, or - javaws-1_2-windows-i586-i.exe, depending on the platform. - - - Unlimited Strength Java Cryptography Extension - - Due to import control restrictions for some countries, the - Java Cryptography Extension (JCE) policy files shipped with - the Java 2 SDK, Standard Edition and the Java 2 Runtime - Environment allow strong but limited cryptography to be - used. These files are located at - - /lib/security/local_policy.jar - /lib/security/US_export_policy.jar - - where is the jre directory of the Java 2 - SDK or the top-level directory of the Java 2 Runtime - Environment. - - An unlimited strength version of these files indicating - no restrictions on cryptographic strengths is available - on the Java 2 SDK web site for those living in eligible - countries. Those living in eligible countries may download - the unlimited strength version and replace the strong - cryptography jar files with the unlimited strength files. - - - Endorsed Standards Override Mechanism - - An endorsed standard is a Java API defined through a standards - process other than the Java Community Process(SM) (JCP(SM)). - Because endorsed standards are defined outside the JCP, it is - anticipated that such standards will be revised between - releases of the Java 2 Platform. In order to take advantage of - new revisions to endorsed standards, developers and software - vendors may use the Endorsed Standards Override Mechanism to - provide newer versions of an endorsed standard than those - included in the Java 2 Platform as released by Sun Microsystems. - - For more information on the Endorsed Standards Override - Mechanism, including the list of platform packages that it may - be used to override, see - - http://java.sun.com/j2se/1.4.2/docs/guide/standards/ - - Classes in the packages listed on that web page may be replaced - only by classes implementing a more recent version of the API - as defined by the appropriate standards body. - - In addition to the packages listed in the document at the above - URL, which are part of the Java 2 Platform, Standard Edition - (J2SE(TM)) specification, redistributors of Sun's J2SE - Reference Implementation are allowed to override classes whose - sole purpose is to implement the functionality provided by - public APIs defined in these Endorsed Standards packages. - Redistributors may also override classes in the org.w3c.dom.* - packages, or other classes whose sole purpose is to implement - these APIs. - - -Sun Java Web Pages - - For additional information, refer to these Sun Microsystems pages - on the World Wide Web: - - http://java.sun.com/ - The Java Software web site, with the latest information on - Java technology, product information, news, and features. - http://java.sun.com/docs - Java Platform Documentation provides access to white papers, - the Java Tutorial and other documents. - http://java.sun.com/jdc - The Java Developer Connection(SM) web site. (Free registration - required.) Additional technical information, news, and - features; user forums; support information, and much more. - http://java.sun.com/products/ - Java Technology Products & API - - ------------------------------------------------------------------------- -The Java 2 SDK, Standard Edition, is a product of Sun Microsystems(TM), -Inc. This product includes code licensed from RSA Security. - -Copyright 2003 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, -California 95054, U.S.A. All rights reserved. diff --git a/test/jdk/javax/swing/JToolTip/TooltipTest.java b/test/jdk/javax/swing/JToolTip/TooltipTest.java new file mode 100644 index 00000000000..c081730a8d7 --- /dev/null +++ b/test/jdk/javax/swing/JToolTip/TooltipTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4207474 4218495 4375928 + * @summary Tests various tooltip issues: HTML tooltips, long tooltip text + * and mnemonic keys displayed in tooltips + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TooltipTest + */ + +import java.awt.FlowLayout; +import java.awt.event.KeyEvent; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.UIManager; + +public class TooltipTest { + private static final String INSTRUCTIONS = """ + 1. Move the mouse over the button labeled "Red tip" and let it stay + still in order to test HTML in JToolTip. If the tooltip has some + text which is red then test passes, otherwise it fails (bug 4207474). + + 2. Move the mouse over the button labeled "Long tip". + If the last letter of the tooltip appears clipped, + then the test fails. If you can see the entire last character, + then the test passes (bug 4218495). + + 3. Verify that "M" is underlined on the button labeled "Mnemonic" + Move the mouse pointer over the button labeled "Mnemonic" and look + at tooltip when it appears. It should read "hint". + If the above is true test passes else test fails (bug 4375928). + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + + PassFailJFrame.builder() + .title("TooltipTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TooltipTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JComponent createTestUI() { + JPanel panel = new JPanel(); + panel.setLayout(new FlowLayout()); + + JButton b = new JButton("Red tip"); + b.setToolTipText("
                Here is some " + + "red text.
                "); + panel.add(b); + + b = new JButton("Long tip"); + b.setToolTipText("Is the last letter clipped?"); + panel.add(b); + + b = new JButton("Mnemonic"); + b.setMnemonic(KeyEvent.VK_M); + b.setToolTipText("hint"); + panel.add(b); + + return panel; + } +} diff --git a/test/jdk/javax/swing/JToolTip/bug4225314.java b/test/jdk/javax/swing/JToolTip/bug4225314.java new file mode 100644 index 00000000000..d36bd461272 --- /dev/null +++ b/test/jdk/javax/swing/JToolTip/bug4225314.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4225314 + * @summary Tests that tooltip is painted properly when it has thick border + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4225314 + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JToolTip; +import javax.swing.border.LineBorder; + +public class bug4225314 { + private static final String INSTRUCTIONS = """ + The word "Tooltip" in both tooltips should not be clipped by the + black border and be fully visible for this test to pass. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4225314 Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4225314::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JComponent createTestUI() { + JToolTip tt1 = new JToolTip(); + tt1.setTipText("Tooltip"); + tt1.setBorder(new LineBorder(Color.BLACK, 10)); + + JToolTip tt2 = new JToolTip(); + tt2.setTipText("Tooltip"); + tt2.setBorder(new LineBorder(Color.BLACK, 10)); + + JPanel panel = new JPanel(); + panel.setLayout(new FlowLayout()); + panel.add(tt1); + panel.add(tt2); + + return panel; + } +} diff --git a/test/jdk/javax/swing/JToolTip/bug4255441.java b/test/jdk/javax/swing/JToolTip/bug4255441.java new file mode 100644 index 00000000000..4a90c975502 --- /dev/null +++ b/test/jdk/javax/swing/JToolTip/bug4255441.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4255441 + * @summary Tests that tooltip appears inside AWT Frame + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4255441 + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import javax.swing.JButton; + +public class bug4255441 { + private static final String INSTRUCTIONS = """ + Move mouse pointer inside the button. + If a tooltip with "Tooltip text" appears, the test passes. + """; + + private static Frame createTestUI() { + Frame fr = new Frame("bug4255441"); + fr.setLayout(new FlowLayout()); + + JButton bt = new JButton("Button"); + bt.setToolTipText("Tooltip text"); + fr.add(bt); + + fr.setSize(200, 200); + return fr; + } + + public static void main(String[] argv) throws Exception { + PassFailJFrame.builder() + .title("bug4255441 Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4255441::createTestUI) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/javax/swing/JTree/NodeChangedTest.java b/test/jdk/javax/swing/JTree/NodeChangedTest.java new file mode 100644 index 00000000000..5461136c57b --- /dev/null +++ b/test/jdk/javax/swing/JTree/NodeChangedTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4199472 + * @summary Tests that node changed for the root of the tree update the + * structure. + * @run main NodeChangedTest + */ + +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; + +public class NodeChangedTest { + public static void main(String[] args) { + // Create 3 nodes + final DefaultMutableTreeNode root = new DefaultMutableTreeNode("root", + true); + final DefaultMutableTreeNode child = new DefaultMutableTreeNode("child", + true); + final DefaultMutableTreeNode leaf = new DefaultMutableTreeNode("leaf", + false); + root.add(child); + child.add(leaf); + + final JTree tree = new JTree(root); + + // Change the root node + root.setUserObject("New root"); + ((DefaultTreeModel) tree.getModel()).nodeChanged(root); + + // Check + if (!root.getUserObject().toString().equals("New root")) { + throw new RuntimeException("Failed changing root node for default model."); + } + + // Change to large model + tree.setLargeModel(true); + tree.setRowHeight(20); + root.setUserObject("root"); + tree.setModel(new DefaultTreeModel(root)); + root.setUserObject("New root"); + ((DefaultTreeModel) tree.getModel()).nodeChanged(root); + + // Check again + if (!root.getUserObject().toString().equals("New root")) { + throw new RuntimeException("Failed changing root node for large model."); + } + } +} diff --git a/test/jdk/javax/swing/JTree/bug4118860.java b/test/jdk/javax/swing/JTree/bug4118860.java new file mode 100644 index 00000000000..eb266eb9324 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4118860.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4118860 + * @summary setToggleClickCount/getToggleClickCount have been added. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4118860 + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GridLayout; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTree; + +public class bug4118860 { + static final String INSTRUCTIONS = """ + Push the "Single Click" button and try expanding/contracting + branch nodes of the tree with one left mouse button click + on the label part of the node (not the icon or handles). + + Then push the "Double Click" button and try doing the same using + left mouse button double click. Single click shouldn't cause + expanding/contracting. A double click should now be required + to expand/contract nodes. + + If it works then the test PASSES, else the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4118860 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4118860::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("ToggleClickCount Test"); + JTree tr = new JTree(); + JPanel p = new JPanel(); + p.setBackground(Color.red); + p.setLayout(new GridLayout(1, 1)); + tr.setOpaque(false); + p.add(tr); + f.add(p, BorderLayout.CENTER); + JPanel bp = new JPanel(); + JButton bt1 = new JButton("Single Click"); + bt1.addActionListener(e -> { + tr.setToggleClickCount(1); + if (tr.getToggleClickCount() != 1) { + throw new RuntimeException("ToggleClickCount doesn't set..."); + } + }); + JButton bt2 = new JButton("Double Click"); + bt2.addActionListener(e -> { + tr.setToggleClickCount(2); + if (tr.getToggleClickCount() != 2) { + throw new RuntimeException("ToggleClickCount doesn't set..."); + } + }); + bp.setLayout(new GridLayout(1, 2)); + bp.add(bt1); + bp.add(bt2); + f.add(bp, BorderLayout.SOUTH); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/JTree/bug4169215.java b/test/jdk/javax/swing/JTree/bug4169215.java new file mode 100644 index 00000000000..0b8780b3939 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4169215.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4169215 + * @summary Accessibility hierarchy JTree node test. + * @run main bug4169215 + */ + +import javax.accessibility.AccessibleContext; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; + +public class bug4169215 { + public static void main(String[] args) { + // create the tree + DefaultMutableTreeNode root = new DefaultMutableTreeNode("top"); + DefaultMutableTreeNode nodeA = new DefaultMutableTreeNode("A"); + DefaultMutableTreeNode nodeB = new DefaultMutableTreeNode("B"); + root.add(nodeA); + root.add(nodeB); + JTree tree = new JTree(root); + + // find the AccessibleContext of the tree + AccessibleContext actree = tree.getAccessibleContext(); + + // find the AccessibleContext of top node of the tree + AccessibleContext act = actree.getAccessibleChild(0).getAccessibleContext(); + + // find the AccessibleContext of the first child of the table -> + // the AccessibleContext of nodeA + AccessibleContext accA = act.getAccessibleChild(0).getAccessibleContext(); + + // find the AccessibleContext of the next sibling of nodeA, by getting + // child+1 of the parent (the table) + AccessibleContext accB = act.getAccessibleChild( + accA.getAccessibleIndexInParent()+1).getAccessibleContext(); + + // look to see who the sibling is. + if (accB.getAccessibleName().compareTo("B") != 0) { + throw new RuntimeException("Parent node is a sibling instead!"); + } + } +} diff --git a/test/jdk/javax/swing/JTree/bug4196987.java b/test/jdk/javax/swing/JTree/bug4196987.java new file mode 100644 index 00000000000..1387b669b05 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4196987.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4196987 + * @summary Test Metal L&F JTree expander icons transparency. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4196987 + */ + +import java.awt.Color; +import java.awt.GridLayout; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTree; +import javax.swing.UIManager; + +public class bug4196987 { + static final String INSTRUCTIONS = """ + If the background of tree icons are red, the test PASSES. + Otherwise the test FAILS. + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("bug4196987 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4196987::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("JTree Icon Transparency Test"); + JPanel p = new JPanel(); + p.setBackground(Color.red); + p.setLayout(new GridLayout(1, 1)); + JTree t = new JTree(); + t.setOpaque(false); + p.add(t); + f.add(p); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/JTree/bug4270654.java b/test/jdk/javax/swing/JTree/bug4270654.java new file mode 100644 index 00000000000..413626d7881 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4270654.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4270654 + * @summary Tests that selection change in JTree does not cause unnecessary + scrolling. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4270654 + */ + +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.tree.DefaultMutableTreeNode; + +public class bug4270654 { + static final String INSTRUCTIONS = """ + Select the "dan" node and scroll to the right a little using the + scrollbar. Then press down arrow key. If the tree unscrolls back + to the left, the test FAILS. Otherwise, the test PASSES. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4270654 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4270654::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("JTree Scroll Back Test"); + DefaultMutableTreeNode root = new DefaultMutableTreeNode("root"); + String[] lev1 = {"foo", "bar", "dan"}; + String[][] lev2 = { + {}, + {"small", "a nice big node for testing"}, + {"xyz", "pqd", "a really really big node for testing"}}; + for (int i = 0; i < lev1.length; i++) { + DefaultMutableTreeNode child = new DefaultMutableTreeNode(lev1[i]); + root.add(child); + for (int j = 0; j < lev2[i].length; j++) + child.add(new DefaultMutableTreeNode(lev2[i][j])); + } + final JTree tree = new JTree(root); + tree.expandRow(3); + f.add(new JScrollPane(tree)); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/JTree/bug4618767.java b/test/jdk/javax/swing/JTree/bug4618767.java new file mode 100644 index 00000000000..d8aa52c3952 --- /dev/null +++ b/test/jdk/javax/swing/JTree/bug4618767.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4618767 + * @summary First letter navigation in JTree interferes with mnemonics + * @key headful + * @run main bug4618767 + */ + +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +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.event.MenuEvent; +import javax.swing.event.MenuListener; + +public class bug4618767 { + private static JFrame f; + private static final JTree tree = new + JTree(new String[] {"one", "two", "three", "four"}); + private static boolean menuSelected; + private static CountDownLatch listGainedFocusLatch = new CountDownLatch(1); + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> { + f = new JFrame("bug4618767 Test"); + JMenu menu = new JMenu("File"); + menu.setMnemonic('F'); + JMenuItem menuItem = new JMenuItem("item"); + menu.add(menuItem); + JMenuBar menuBar = new JMenuBar(); + menuBar.add(menu); + f.setJMenuBar(menuBar); + + menu.addMenuListener(new MenuListener() { + public void menuCanceled(MenuEvent e) {} + public void menuDeselected(MenuEvent e) {} + public void menuSelected(MenuEvent e) { + menuSelected = true; + } + }); + + tree.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + listGainedFocusLatch.countDown(); + } + }); + f.add(tree); + f.pack(); + f.setLocationRelativeTo(null); + f.setAlwaysOnTop(true); + f.setVisible(true); + }); + runTest(); + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static void runTest() throws Exception { + if (!listGainedFocusLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Waited too long, but can't gain" + + " focus for list"); + } + Robot robot = new Robot(); + robot.setAutoDelay(200); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_O); + robot.keyRelease(KeyEvent.VK_O); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_ALT); + + SwingUtilities.invokeAndWait(() -> { + if (menuSelected && !tree.getSelectionPath() + .getLastPathComponent().toString().equals("one")) { + throw new RuntimeException("Mnemonics interferes with JTree" + + " item selection using KeyEvent"); + } + }); + } +} diff --git a/test/jdk/javax/swing/JViewport/ScrollRectToVisibleTest3.java b/test/jdk/javax/swing/JViewport/ScrollRectToVisibleTest3.java new file mode 100644 index 00000000000..bf96ab2fc46 --- /dev/null +++ b/test/jdk/javax/swing/JViewport/ScrollRectToVisibleTest3.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact 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 4217252 + * @summary Verify that scrolling beyond the visible region and scrolling + * a component smaller than the viewport is not allowed. + * @library /javax/swing/regtesthelpers + * @build Util + * @run main/othervm -Dsun.java2d.uiScale=1 ScrollRectToVisibleTest3 + */ + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; + +public class ScrollRectToVisibleTest3 { + private static JFrame frame; + private static JTable table; + private static JButton scrollButton; + private static volatile int clickCount = 0; + private static final String[] EXPECTED_TEXT = {"99 x 0", "98 x 0", + "97 x 0", "96 x 0"}; + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoWaitForIdle(true); + + SwingUtilities.invokeAndWait(ScrollRectToVisibleTest3::createTestUI); + robot.waitForIdle(); + robot.delay(1000); + + Rectangle frameBounds = Util.invokeOnEDT(() -> getComponentBounds(frame)); + robot.delay(100); + Point scrollBtnLoc = Util.getCenterPoint(scrollButton); + + robot.mouseMove(scrollBtnLoc.x, scrollBtnLoc.y); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + robot.delay(50); + + int rowHeight = Util.invokeOnEDT(() -> table.getRowHeight()); + for (int i = 1; i <= 4; i++) { + robot.mouseMove(frameBounds.x + 50, + frameBounds.y + frameBounds.height - (rowHeight * i + 2)); + robot.delay(300); + robot.mousePress(MouseEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(MouseEvent.BUTTON1_DOWN_MASK); + // 500 ms delay added so that current mouseClicked event + // is processed successfully before proceeding to the next + robot.delay(500); + } + if (clickCount != 4) { + throw new RuntimeException("Test Failed! Expected 4 mouse clicks" + + " but got " + clickCount); + } + } + + private static void createTestUI() { + frame = new JFrame("ScrollRectToVisibleTest3"); + table = new JTable(new TestModel()); + table.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + JTable testTable = (JTable) e.getComponent(); + int row = testTable.getSelectedRow(); + int column = testTable.getSelectedColumn(); + String cellContent = testTable.getValueAt(row, column).toString(); + if (!EXPECTED_TEXT[clickCount].equals(cellContent)) { + throw new RuntimeException(("Test failed! Table Cell Content" + + " at (row %d , col %d)\n Expected: %s vs Actual: %s") + .formatted(row, column, + EXPECTED_TEXT[clickCount], cellContent)); + } + clickCount++; + } + }); + + scrollButton = new JButton("Scroll"); + scrollButton.addActionListener(ae -> { + Rectangle bounds = table.getBounds(); + bounds.y = bounds.height + table.getRowHeight(); + bounds.height = table.getRowHeight(); + System.out.println("scrolling: " + bounds); + table.scrollRectToVisible(bounds); + System.out.println("bounds: " + table.getVisibleRect()); + }); + + frame.add(scrollButton, BorderLayout.NORTH); + frame.add(new JScrollPane(table), BorderLayout.CENTER); + frame.setSize(400, 300); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + + private static class TestModel extends AbstractTableModel { + @Override + public String getColumnName(int column) { + return Integer.toString(column); + } + + @Override + public int getRowCount() { + return 100; + } + + @Override + public int getColumnCount() { + return 5; + } + + @Override + public Object getValueAt(int row, int col) { + return row + " x " + col; + } + + @Override + public boolean isCellEditable(int row, int column) { return false; } + + @Override + public void setValueAt(Object value, int row, int col) { + } + } + + private static Rectangle getComponentBounds(Component c) { + Point locationOnScreen = c.getLocationOnScreen(); + Dimension size = c.getSize(); + return new Rectangle(locationOnScreen, size); + } +} diff --git a/test/jdk/javax/swing/JViewport/SetViewRepaint.java b/test/jdk/javax/swing/JViewport/SetViewRepaint.java new file mode 100644 index 00000000000..379a3e4e33b --- /dev/null +++ b/test/jdk/javax/swing/JViewport/SetViewRepaint.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4128110 + * @summary Verify that JViewport.setViewportView() and JScrollPane.setViewport() + * force a re-layout and a repaint. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetViewRepaint + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GridLayout; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JViewport; + +public class SetViewRepaint { + private static final String INSTRUCTIONS = """ + Verify the following two cases: + + 1) Press "JViewport.setViewportView()" button and verify that + the blue label is replaced by a scrolling list. + + 2) Press "JScrollPane.setViewport()" button and verify that + the red label is replaced by a scrolling list as well. + + In either case the display should update automatically after + pressing the button. + + If the above is true, press PASS else press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(SetViewRepaint::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("SetViewRepaint"); + JPanel p1 = new JPanel(new BorderLayout()); + JPanel p2 = new JPanel(new BorderLayout()); + + JLabel label1 = new ColorLabel(Color.BLUE, "Blue Label"); + final JList list1 = new JList(new String[]{"one", "two", "three", "four"}); + final JScrollPane sp1 = new JScrollPane(label1); + ActionListener doSetViewportView = e -> sp1.setViewportView(list1); + JButton b1 = new JButton("JViewport.setViewportView()"); + b1.addActionListener(doSetViewportView); + p1.add(sp1, BorderLayout.CENTER); + p1.add(b1, BorderLayout.SOUTH); + + JLabel label2 = new ColorLabel(Color.RED, "Red Label"); + final JList list2 = new JList(new String[]{"five", "six", "seven", "eight"}); + final JScrollPane sp2 = new JScrollPane(label2); + ActionListener doSetViewport = e -> { + JViewport vp = new JViewport(); + vp.setView(list2); + sp2.setViewport(vp); + }; + JButton b2 = new JButton("JScrollPane.setViewport()"); + b2.addActionListener(doSetViewport); + p2.add(sp2, BorderLayout.CENTER); + p2.add(b2, BorderLayout.SOUTH); + frame.setLayout(new GridLayout(1, 2)); + frame.add(p1); + frame.add(p2); + frame.setResizable(false); + frame.setSize(500, 120); + return frame; + } + + private static class ColorLabel extends JLabel { + ColorLabel(Color color, String text) { + super(text); + setForeground(Color.WHITE); + setBackground(color); + setOpaque(true); + setHorizontalAlignment(CENTER); + } + } +} diff --git a/test/jdk/javax/swing/JWindow/bug4251781.java b/test/jdk/javax/swing/JWindow/bug4251781.java new file mode 100644 index 00000000000..0152db71f24 --- /dev/null +++ b/test/jdk/javax/swing/JWindow/bug4251781.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4251781 + * @summary Tests that JWindow repaint is optimized (background is not + cleared). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4251781 + */ + +import java.awt.Color; +import java.awt.Container; +import javax.swing.JButton; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.JWindow; + +public class bug4251781 { + private static final String INSTRUCTIONS = """ + Press the button at the bottom-right corner of the gray + window with the mouse. + If the window DOES NOT flicker when you press and/or release + the mouse button press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4251781::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static JWindow createAndShowUI() { + JWindow w = new JWindow(); + final Container pane = w.getContentPane(); + pane.setLayout(null); + pane.setBackground(Color.GRAY.darker()); + + final JPopupMenu popup = new JPopupMenu(); + popup.add(new JMenuItem("item 1")); + popup.add(new JMenuItem("exit")); + + JButton b = new JButton("menu"); + b.setBounds(350, 250, 50, 50); + b.addActionListener(ev -> popup.show(pane, 0, 0)); + pane.add(b); + + w.setSize(400, 300); + return w; + } +} diff --git a/test/jdk/javax/swing/ProgressMonitor/bug4401480.java b/test/jdk/javax/swing/ProgressMonitor/bug4401480.java new file mode 100644 index 00000000000..74b47107e77 --- /dev/null +++ b/test/jdk/javax/swing/ProgressMonitor/bug4401480.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4401480 + * @summary Tests that closing ProgressMonitor dialog cancels it + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4401480 + */ + +import java.lang.reflect.InvocationTargetException; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.ProgressMonitor; +import javax.swing.SwingUtilities; + +public class bug4401480 { + private static ProgressMonitor monitor; + private static volatile boolean cancelled = false; + + private static final String INSTRUCTIONS = """ + This is a semi-automated test which automatically + passes if closing the JProgressBar dialog cancels it. + Read the following test instructions and when ready + click on the Start button below. + + After clicking on Start button wait for few seconds for + progress monitor (a dialog with progress bar) to appear. + Close it by clicking on the window close button. + DO NOT click on Cancel button. + + NOTE: + Ensure to click on the window close button before + progress bar reaches its max limit. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JProgress Monitor Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .splitUIBottom(bug4401480::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JPanel createTestUI() { + JPanel panel = new JPanel(); + JButton startButton = new JButton("Start"); + startButton.addActionListener(e -> { + monitor = new ProgressMonitor(null, "Progress", "Running ...", 0, 10); + monitor.setProgress(0); + + new Thread(() -> { + for (int i = 0; i < 10; i++) { + int count = i; + try { + SwingUtilities.invokeAndWait(() -> + monitor.setProgress(count)); + Thread.sleep(2000); + SwingUtilities.invokeAndWait(() -> + cancelled = monitor.isCanceled()); + } catch (InterruptedException + | InvocationTargetException ex) { + throw new RuntimeException(ex); + } + if (cancelled) { + break; + } + } + + if (cancelled) { + PassFailJFrame.forcePass(); + } else { + PassFailJFrame.forceFail("Test Failed! JProgress Monitor" + + " was not cancelled"); + } + }).start(); + }); + panel.add(startButton); + return panel; + } +} diff --git a/test/jdk/javax/swing/SwingUtilities/bug4369355.java b/test/jdk/javax/swing/SwingUtilities/bug4369355.java new file mode 100644 index 00000000000..f55d888ef31 --- /dev/null +++ b/test/jdk/javax/swing/SwingUtilities/bug4369355.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact 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 4369355 + * @summary To verify if SwingUtilities.convertPointToScreen() (for invisible frame) + * and SwingUtilities.convertPointFromScreen() return correct values + * @run main bug4369355 + */ + +import java.awt.Point; +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class bug4369355 { + private static JFrame frame; + + private static volatile Point frameToScreenLoc; + private static volatile Point frameFromScreenLoc; + + private static final Point EXPECTED_FROM_SCREEN_LOC = new Point(0, 0); + private static final Point EXPECTED_TO_SCREEN_LOC = new Point(100, 100); + + public static void main (String[] args) throws Exception { + try { + Robot robot = new Robot(); + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("bug4369355"); + frame.setBounds(100, 100, 100, 100); + }); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + frameToScreenLoc = new Point(0, 0); + SwingUtilities.convertPointToScreen(frameToScreenLoc, frame); + }); + robot.delay(100); + + if (!frameToScreenLoc.equals(EXPECTED_TO_SCREEN_LOC)) { + throw new RuntimeException("SwingUtilities.convertPointToScreen()" + + " returns incorrect point " + frameToScreenLoc + "\n" + + "Should be " + EXPECTED_TO_SCREEN_LOC); + } + + SwingUtilities.invokeAndWait(() -> frame.setVisible(true)); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> { + frameFromScreenLoc = frame.getLocationOnScreen(); + SwingUtilities.convertPointFromScreen(frameFromScreenLoc, frame); + }); + robot.delay(100); + + if (!frameFromScreenLoc.equals(EXPECTED_FROM_SCREEN_LOC)) { + throw new RuntimeException("SwingUtilities.convertPointFromScreen()" + + " returns incorrect point " + frameFromScreenLoc + "\n" + + "Should be " + EXPECTED_FROM_SCREEN_LOC); + } + } finally { + SwingUtilities.invokeAndWait(frame::dispose); + } + } +} diff --git a/test/jdk/javax/swing/SwingUtilities/bug4967768.java b/test/jdk/javax/swing/SwingUtilities/bug4967768.java new file mode 100644 index 00000000000..43f9f7cabfb --- /dev/null +++ b/test/jdk/javax/swing/SwingUtilities/bug4967768.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4967768 + * @requires (os.family != "mac") + * @summary Tests that underline is painted correctly in mnemonics + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4967768 + */ + +import java.awt.Font; +import javax.swing.JButton; +import javax.swing.JPanel; + +public class bug4967768 { + private static final String INSTRUCTIONS = """ + When the test starts you'll see a button "Oops" + with the "p" letter underlined at the bottom + of the instruction frame. + + Ensure the underline cuts through the descender + of letter "p", i.e. the underline is painted + not below the letter but below the baseline. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .instructions(INSTRUCTIONS) + .columns(35) + .splitUIBottom(bug4967768::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JPanel createTestUI() { + JPanel panel = new JPanel(); + JButton but = new JButton("Oops"); + but.setFont(new Font("Dialog", Font.BOLD, 24)); + but.setMnemonic('p'); + panel.add(but); + return panel; + } +} diff --git a/test/jdk/javax/swing/border/TransparentTitleTest.java b/test/jdk/javax/swing/border/TransparentTitleTest.java new file mode 100644 index 00000000000..49a32a5890c --- /dev/null +++ b/test/jdk/javax/swing/border/TransparentTitleTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4154572 + * @summary Tests that the area behind a TitledBorder's title string is transparent, + * allowing the component's background to show through + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TransparentTitleTest + */ + +import java.awt.GridLayout; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Color; +import java.awt.image.BufferedImage; +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.border.TitledBorder; +import javax.swing.border.LineBorder; + +public class TransparentTitleTest { + private static final String INSTRUCTIONS = """ + If all panels are correctly painted such that the title of the + border allows the underlying panel image (green rectangle) + to show through the background of the text, + then this test passes; else it fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("TransparentTitleTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TransparentTitleTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("TransparentTitleTest"); + + frame.setLayout(new GridLayout(3, 6, 5, 5)); + + frame.add(new ImagePanel(TitledBorder.TOP, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.TOP, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.TOP, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.ABOVE_TOP, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.ABOVE_TOP, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.ABOVE_TOP, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.BELOW_TOP, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.BELOW_TOP, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.BELOW_TOP, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.BOTTOM, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.BOTTOM, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.BOTTOM, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.ABOVE_BOTTOM, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.ABOVE_BOTTOM, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.ABOVE_BOTTOM, TitledBorder.RIGHT)); + frame.add(new ImagePanel(TitledBorder.BELOW_BOTTOM, TitledBorder.LEFT)); + frame.add(new ImagePanel(TitledBorder.BELOW_BOTTOM, TitledBorder.CENTER)); + frame.add(new ImagePanel(TitledBorder.BELOW_BOTTOM, TitledBorder.RIGHT)); + + frame.pack(); + return frame; + } +} + +class ImagePanel extends JPanel { + + private final ImageIcon imageIcon; + + private static final BufferedImage bufferedImage = + new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB); + + static { + Graphics g = bufferedImage.getGraphics(); + g.setColor(Color.GREEN); + g.fillRect(0, 0, 128, 128); + } + + public ImagePanel(int titlePos, int titleJust) { + imageIcon = new ImageIcon(bufferedImage); + + TitledBorder b = new TitledBorder(new LineBorder(Color.black,3), "title text"); + b.setTitlePosition(titlePos); + b.setTitleJustification(titleJust); + b.setTitleColor(Color.black); + setBorder(b); + } + + public Dimension getPreferredSize() { + return new Dimension(imageIcon.getIconWidth(), imageIcon.getIconHeight()); + } + + public void paintComponent(Graphics g) { + imageIcon.paintIcon(this, g, 0, 0); + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicGraphicsUtils/DrawEtchedRectTest.java b/test/jdk/javax/swing/plaf/basic/BasicGraphicsUtils/DrawEtchedRectTest.java new file mode 100644 index 00000000000..0c5c501596c --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicGraphicsUtils/DrawEtchedRectTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4198822 + * @summary Tests that the bottom line drawn by + * BasicGraphicsUtils.drawEtchedRect extends to the end. + * @run main DrawEtchedRectTest + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.File; + +import javax.imageio.ImageIO; +import javax.swing.plaf.basic.BasicGraphicsUtils; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +public class DrawEtchedRectTest { + private static final int WIDTH = 200; + private static final int HEIGHT = 200; + private static final int RANGE = 10; + + public static void main(String[] args) throws Exception { + // Draw etched rectangle to a BufferedImage + BufferedImage image = new BufferedImage(WIDTH, HEIGHT, TYPE_INT_ARGB); + Graphics2D g2d = image.createGraphics(); + Component sq = new Component() { + public void paint(Graphics g) { + g.setColor(Color.WHITE); + g.fillRect(0, 0, WIDTH, HEIGHT); + BasicGraphicsUtils.drawEtchedRect(g, 0, 0, WIDTH, HEIGHT, + Color.black, Color.black, + Color.black, Color.black); + } + }; + sq.paint(g2d); + g2d.dispose(); + + // Check if connected at bottom-right corner + int c1; + int c2; + for (int i = 1; i < RANGE; i++) { + c1 = image.getRGB(WIDTH - i, HEIGHT - 1); + c2 = image.getRGB(WIDTH - 1, HEIGHT - i); + if (c1 == Color.WHITE.getRGB() || c2 == Color.WHITE.getRGB()) { + ImageIO.write(image, "png", new File("failImage.png")); + throw new RuntimeException("Bottom line is not connected!"); + } + } + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/bug4228104.java b/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/bug4228104.java new file mode 100644 index 00000000000..451590c66ab --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/bug4228104.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4228104 + * @summary Tests work of BODY BACKGROUND tag in HTML renderer + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4228104 + */ + +import java.awt.BorderLayout; + +import javax.swing.JFrame; +import javax.swing.JLabel; + +public class bug4228104 { + static final String INSTRUCTIONS = """ + There should be an image displaying dukes under the rows of digits. + If you can see it, the test PASSES. Otherwise, the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4228104 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4228104::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Background HTML Text Test"); + String dir = System.getProperty("test.src", + System.getProperty("user.dir")); + String htmlText1 = + "\n" + + "
                111111111111111111" + + "
                111111111111111111" + + "
                111111111111111111" + + "
                111111111111111111" + + "
                111111111111111111" + + "
                111111111111111111" + + "
                111111111111111111" + + "
                111111111111111111" + + "
                111111111111111111"; + JLabel button1 = new JLabel(htmlText1); + f.add(button1, BorderLayout.NORTH); + f.setSize(200, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/duke.gif b/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/duke.gif new file mode 100644 index 00000000000..ed32e0ff79b Binary files /dev/null and b/test/jdk/javax/swing/plaf/basic/BasicHTML/4228104/duke.gif differ diff --git a/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4220108.java b/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4220108.java new file mode 100644 index 00000000000..94cc3d65e5d --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicSliderUI/bug4220108.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4220108 + * @summary JSlider in JInternalFrame should be painted correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4220108 + */ + +import java.awt.BorderLayout; +import java.awt.FlowLayout; + +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JSlider; + +public class bug4220108 { + static final String INSTRUCTIONS = """ + If you see a slider in the internal frame, then the test PASSES. + Otherwise the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4220108 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(bug4220108::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Internal Frame Slider Test"); + f.setLayout(new FlowLayout()); + JDesktopPane desktop = new JDesktopPane(); + f.setContentPane(desktop); + + JInternalFrame iFrame = + new JInternalFrame("Slider Frame", true, true, true, true); + JSlider sl = new JSlider(); + iFrame.add(sl); + iFrame.add(new JLabel("Label"), BorderLayout.SOUTH); + desktop.add(iFrame); + iFrame.pack(); + iFrame.setVisible(true); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/NegativeSizeTest.java b/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/NegativeSizeTest.java new file mode 100644 index 00000000000..3a461410e4b --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/NegativeSizeTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4199666 + * @summary Makes sure initial negative size of a component does not confuse + * JSplitPane. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NegativeSizeTest + */ + +import java.awt.BorderLayout; +import java.awt.CardLayout; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSplitPane; + +public class NegativeSizeTest { + static final String INSTRUCTIONS = """ + Click on the 'Show JSplitPane' button. If two buttons appear, + click PASS, otherwise click FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("NegativeSizeTest Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(NegativeSizeTest::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Negative Size Test"); + CardLayout cardLayout = new CardLayout(); + JPanel mainPanel = new JPanel(cardLayout); + + JSplitPane splitPane = new JSplitPane(); + splitPane.setContinuousLayout(true); + JPanel splitContainer = new JPanel(new BorderLayout()); + splitContainer.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + splitContainer.add(splitPane, BorderLayout.CENTER); + + if (false) { + mainPanel.add(splitContainer, "split"); + mainPanel.add(new JPanel(), "blank"); + } + else { + mainPanel.add(new JPanel(), "blank"); + mainPanel.add(splitContainer, "split"); + } + + f.add(mainPanel, BorderLayout.CENTER); + + JButton button = new JButton("Show JSplitPane"); + button.addActionListener(e -> cardLayout.show(mainPanel, "split")); + f.add(button, BorderLayout.SOUTH); + f.setSize(400, 300); + return f; + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/PreferredSizeLayoutTest.java b/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/PreferredSizeLayoutTest.java new file mode 100644 index 00000000000..76d0e45b8eb --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicSplitPaneUI/PreferredSizeLayoutTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4208549 + * @summary Makes sure preferred size returned by layout managers used by + * JSplitPane is correct. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PreferredSizeLayoutTest + */ + +import java.awt.Container; +import java.awt.FlowLayout; + +import javax.swing.JFrame; +import javax.swing.JSplitPane; + +public class PreferredSizeLayoutTest { + static final String INSTRUCTIONS = """ + If the buttons in the JSplitpanes do not have '...' in them, + click PASS, otherwise click FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("PreferredSizeLayoutTest Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PreferredSizeLayoutTest::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Preferred Size Layout Test"); + Container parent = f.getContentPane(); + JSplitPane sp = new JSplitPane(); + + parent.setLayout(new FlowLayout()); + + sp.setOrientation(JSplitPane.HORIZONTAL_SPLIT); + parent.add(sp); + sp = new JSplitPane(); + sp.setOrientation(JSplitPane.VERTICAL_SPLIT); + parent.add(sp); + f.setSize(400, 300); + return f; + } +} diff --git a/test/jdk/javax/swing/plaf/windows/bug4991587.java b/test/jdk/javax/swing/plaf/windows/bug4991587.java new file mode 100644 index 00000000000..e4e4fde2b86 --- /dev/null +++ b/test/jdk/javax/swing/plaf/windows/bug4991587.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4991587 + * @requires (os.family == "windows") + * @summary Tests that disabled JButton text is positioned properly in Windows L&F + * @modules java.desktop/com.sun.java.swing.plaf.windows + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual bug4991587 + */ + +import java.awt.Color; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.UIManager; + +import com.sun.java.swing.plaf.windows.WindowsButtonUI; + +public class bug4991587 { + static final String INSTRUCTIONS = """ + There are two buttons: enabled (left) and disabled (right). + Ensure that the disabled button text is painted entirely + inside the blue bounding rectangle, just like the enabled + button (use it as an example of how this should look like). + """; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + PassFailJFrame.builder() + .title("bug4991587 Test Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(bug4991587::createUI) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame f = new JFrame("Disabled JButton Text Test"); + f.setLayout(new FlowLayout()); + f.setSize(400, 100); + + JButton button1 = new JButton("\u0114 Enabled JButton"); + button1.setUI(new MyButtonUI()); + f.add(button1); + + JButton button2 = new JButton("\u0114 Disabled JButton"); + button2.setEnabled(false); + button2.setUI(new MyButtonUI()); + f.add(button2); + + return f; + } + + static class MyButtonUI extends WindowsButtonUI { + protected void paintText(Graphics g, AbstractButton b, + Rectangle textRect, String text) { + g.setColor(Color.blue); + g.drawRect(textRect.x, + textRect.y, + textRect.width + 1, // add 1 for the shadow, otherwise it + // will be painted over the textRect + textRect.height); + super.paintText(g, b, textRect, text); + } + } +} diff --git a/test/jdk/javax/swing/text/html/parser/Parser/6990651/bug6990651.java b/test/jdk/javax/swing/text/html/parser/Parser/6990651/bug6990651.java index b939f3e148f..9dada22ba60 100644 --- a/test/jdk/javax/swing/text/html/parser/Parser/6990651/bug6990651.java +++ b/test/jdk/javax/swing/text/html/parser/Parser/6990651/bug6990651.java @@ -23,7 +23,7 @@ /* @test @bug 6990651 - @summary Regression: NPE when refreshing applet since 6u22-b01 + @summary Regression: NPE when refreshing embedded window since 6u22-b01 @author Pavel Porvatov @modules java.desktop/sun.awt */ diff --git a/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java b/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java index b5d3ba5d584..ac1292b1062 100644 --- a/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java +++ b/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,22 +30,25 @@ * @run junit ConstantDescSymbolsTest */ -import java.lang.classfile.constantpool.ConstantPoolBuilder; -import java.lang.constant.ClassDesc; -import java.lang.constant.DynamicConstantDesc; -import java.lang.constant.MethodHandleDesc; -import java.lang.constant.MethodTypeDesc; +import java.lang.classfile.constantpool.*; +import java.lang.constant.*; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.nio.charset.StandardCharsets; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; import java.lang.classfile.ClassFile; import java.util.stream.Stream; -import jdk.internal.classfile.impl.AbstractPoolEntry; +import jdk.internal.classfile.impl.Util; import jdk.internal.constant.ConstantUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import static java.lang.classfile.ClassFile.ACC_PUBLIC; @@ -88,7 +91,8 @@ void testPrimitiveClassDesc() throws Throwable { // Tests that condy symbols with non-static-method bootstraps are using the right lookup descriptor. @Test void testConstantDynamicNonStaticBootstrapMethod() throws Throwable { - record CondyBoot(MethodHandles.Lookup lookup, String name, Class type) {} + record CondyBoot(MethodHandles.Lookup lookup, String name, Class type) { + } var bootClass = CondyBoot.class.describeConstable().orElseThrow(); var bootMhDesc = MethodHandleDesc.ofConstructor(bootClass, CD_MethodHandles_Lookup, CD_String, CD_Class); var condyDesc = DynamicConstantDesc.of(bootMhDesc); @@ -165,4 +169,216 @@ void testConstantPoolBuilderClassOrInterfaceEntry(ClassDesc cd) { assertSame(utf8, ce.name(), "Reusing existing utf8 entry"); assertEquals(cd, ce.asSymbol(), "Symbol propagation on create with utf8"); } + + @ParameterizedTest + @MethodSource("equalityCases") + void testAsSymbolEquality(ValidSymbolCase validSymbolCase, String entryState, P p) { + var asSymbol = validSymbolCase.translator.extractor.apply(p); + assertEquals(validSymbolCase.sym, asSymbol, "asSym vs sym"); + assertEquals(validSymbolCase.other, asSymbol, "asSym vs other sym"); + } + + @ParameterizedTest + @MethodSource("equalityCases") + void testMatchesOriginalEquality(ValidSymbolCase validSymbolCase, String entryState, P p) { + assertTrue(validSymbolCase.translator.tester.test(p, validSymbolCase.sym)); + } + + @ParameterizedTest + @MethodSource("equalityCases") + void testMatchesEquivalentEquality(ValidSymbolCase validSymbolCase, String entryState, P p) { + assertTrue(validSymbolCase.translator.tester.test(p, validSymbolCase.other)); + } + + @ParameterizedTest + @MethodSource("inequalityCases") + void testAsSymbolInequality(ValidSymbolCase validSymbolCase, String stateName, P p) { + var asSymbol = validSymbolCase.translator.extractor.apply(p); + assertEquals(validSymbolCase.sym, asSymbol, "asSymbol vs original"); + assertNotEquals(validSymbolCase.other, asSymbol, "asSymbol vs inequal"); + } + + @ParameterizedTest + @MethodSource("inequalityCases") + void testMatchesOriginalInequality(ValidSymbolCase validSymbolCase, String stateName, P p) { + assertTrue(validSymbolCase.translator.tester.test(p, validSymbolCase.sym)); + } + + @ParameterizedTest + @MethodSource("inequalityCases") + void testMatchesNonEquivalentInequality(ValidSymbolCase validSymbolCase, String stateName, P p) { + assertFalse(validSymbolCase.translator.tester.test(p, validSymbolCase.other)); + } + + @ParameterizedTest + @MethodSource("malformedCases") + void testAsSymbolMalformed(InvalidSymbolCase baseCase, String entryState, P p) { + assertThrows(IllegalArgumentException.class, () -> baseCase.translator.extractor.apply(p)); + } + + @ParameterizedTest + @MethodSource("malformedCases") + void testMatchesMalformed(InvalidSymbolCase baseCase, String entryState, P p) { + assertFalse(baseCase.translator.tester.test(p, baseCase.target)); + } + + // Support for complex pool entry creation with different inflation states. + // Inflation states include: + // - bound/unbound, + // - asSymbol() + // - matches() resulting in match + // - matches() resulting in mismatch + + // a pool entry, suitable for testing lazy behaviors and has descriptive name + record StatefulPoolEntry

                (String desc, Supplier

                factory) { + } + + // Test pool entry <-> nominal descriptor, also the equals methods + record SymbolicTranslator(String name, BiFunction writer, + BiPredicate tester, Function extractor) { + private P createUnboundEntry(T symbol) { + ConstantPoolBuilder cpb = ConstantPoolBuilder.of(); // Temp pool does not support some entries + return writer.apply(cpb, symbol); + } + + @SuppressWarnings("unchecked") + private P toBoundEntry(P unboundEntry) { + ConstantPoolBuilder cpb = (ConstantPoolBuilder) unboundEntry.constantPool(); + int index = unboundEntry.index(); + var bytes = ClassFile.of().build(cpb.classEntry(ClassDesc.of("Test")), cpb, _ -> { + }); + return (P) ClassFile.of().parse(bytes).constantPool().entryByIndex(index); + } + + // Spawn entries to test from a nominal descriptor + public Stream> entriesSpawner(T original) { + return spawnBounded(() -> this.createUnboundEntry(original)); + } + + // Spawn additional bound entries to test from an initial unbound entry + public Stream> spawnBounded(Supplier

                original) { + return Stream.of(new StatefulPoolEntry<>(original.get().toString(), original)) + .mapMulti((s, sink) -> { + sink.accept(s); // unbound + sink.accept(new StatefulPoolEntry<>(s.desc + "+lazy", () -> toBoundEntry(s.factory.get()))); // bound + }); + } + + // Add extra stage of entry spawn to "inflate" entries via positive/negative tests + public StatefulPoolEntry

                inflateByMatching(StatefulPoolEntry

                last, T arg, String msg) { + return new StatefulPoolEntry<>("+matches(" + msg + ")", () -> { + var ret = last.factory.get(); + tester.test(ret, arg); + return ret; + }); + } + + // Add extra stage of entry spawn to "inflate" entries via descriptor computation + // This should not be used if the pool entry may be invalid (i.e. throws IAE) + public StatefulPoolEntry

                inflateByComputeSymbol(StatefulPoolEntry

                last) { + return new StatefulPoolEntry<>(last.desc + "+asSymbol()", () -> { + var ret = last.factory.get(); + extractor.apply(ret); + return ret; + }); + } + + @Override + public String toString() { + return name; // don't include lambda garbage in failure reports + } + } + + // A case testing valid symbol sym; other is another symbol that may match or mismatch. + record ValidSymbolCase(SymbolicTranslator translator, T sym, T other) { + } + + // Current supported conversions + static final SymbolicTranslator UTF8_STRING_TRANSLATOR = new SymbolicTranslator<>("Utf8", ConstantPoolBuilder::utf8Entry, Utf8Entry::equalsString, Utf8Entry::stringValue); + static final SymbolicTranslator UTF8_CLASS_TRANSLATOR = new SymbolicTranslator<>("FieldTypeUtf8", ConstantPoolBuilder::utf8Entry, Utf8Entry::isFieldType, Util::fieldTypeSymbol); + static final SymbolicTranslator UTF8_METHOD_TYPE_TRANSLATOR = new SymbolicTranslator<>("MethodTypeUtf8", ConstantPoolBuilder::utf8Entry, Utf8Entry::isMethodType, Util::methodTypeSymbol); + static final SymbolicTranslator CLASS_ENTRY_TRANSLATOR = new SymbolicTranslator<>("ClassEntry", ConstantPoolBuilder::classEntry, ClassEntry::matches, ClassEntry::asSymbol); + static final SymbolicTranslator METHOD_TYPE_ENTRY_TRANSLATOR = new SymbolicTranslator<>("MethodTypeEntry", ConstantPoolBuilder::methodTypeEntry, MethodTypeEntry::matches, MethodTypeEntry::asSymbol); + static final SymbolicTranslator STRING_ENTRY_TRANSLATOR = new SymbolicTranslator<>("StringEntry", ConstantPoolBuilder::stringEntry, StringEntry::equalsString, StringEntry::stringValue); + static final SymbolicTranslator PACKAGE_ENTRY_TRANSLATOR = new SymbolicTranslator<>("PackageEntry", ConstantPoolBuilder::packageEntry, PackageEntry::matches, PackageEntry::asSymbol); + static final SymbolicTranslator MODULE_ENTRY_TRANSLATOR = new SymbolicTranslator<>("ModuleEntry", ConstantPoolBuilder::moduleEntry, ModuleEntry::matches, ModuleEntry::asSymbol); + + // Create arguments of tuple (ValidSymbolCase, entryState, PoolEntry) to verify symbolic behavior of pool entries + // with particular inflation states + static void specializeInflation(ValidSymbolCase validSymbolCase, Consumer callArgs) { + validSymbolCase.translator.entriesSpawner(validSymbolCase.sym) + .>mapMulti((src, sink) -> { + sink.accept(src); + sink.accept(validSymbolCase.translator.inflateByMatching(src, validSymbolCase.sym, "same symbol")); + sink.accept(validSymbolCase.translator.inflateByMatching(src, validSymbolCase.other, "another symbol")); + sink.accept(validSymbolCase.translator.inflateByComputeSymbol(src)); + }) + .forEach(stateful -> callArgs.accept(Arguments.of(validSymbolCase, stateful.desc, stateful.factory.get()))); + } + + static Stream equalityCases() { + return Stream.of( + new ValidSymbolCase<>(CLASS_ENTRY_TRANSLATOR, CD_Object, ClassDesc.ofInternalName("java/lang/Object")), // class or interface + new ValidSymbolCase<>(CLASS_ENTRY_TRANSLATOR, CD_Object.arrayType(), ClassDesc.ofDescriptor("[Ljava/lang/Object;")), // array + new ValidSymbolCase<>(UTF8_CLASS_TRANSLATOR, CD_int, ClassDesc.ofDescriptor("I")), // primitive + new ValidSymbolCase<>(UTF8_CLASS_TRANSLATOR, CD_Object, ClassDesc.ofInternalName("java/lang/Object")), // class or interface + new ValidSymbolCase<>(UTF8_CLASS_TRANSLATOR, CD_Object.arrayType(), ClassDesc.ofDescriptor("[Ljava/lang/Object;")), // array + new ValidSymbolCase<>(UTF8_STRING_TRANSLATOR, "Ab\u0000c", "Ab\u0000c"), + new ValidSymbolCase<>(UTF8_METHOD_TYPE_TRANSLATOR, MTD_void, MethodTypeDesc.ofDescriptor("()V")), + new ValidSymbolCase<>(UTF8_METHOD_TYPE_TRANSLATOR, MethodTypeDesc.of(CD_int, CD_Long), MethodTypeDesc.ofDescriptor("(Ljava/lang/Long;)I")), + new ValidSymbolCase<>(METHOD_TYPE_ENTRY_TRANSLATOR, MethodTypeDesc.of(CD_Object), MethodTypeDesc.ofDescriptor("()Ljava/lang/Object;")), + new ValidSymbolCase<>(STRING_ENTRY_TRANSLATOR, "Ape", new String("Ape".getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)), + new ValidSymbolCase<>(PACKAGE_ENTRY_TRANSLATOR, PackageDesc.of("java.lang"), PackageDesc.ofInternalName("java/lang")), + new ValidSymbolCase<>(MODULE_ENTRY_TRANSLATOR, ModuleDesc.of("java.base"), ModuleDesc.of(new String("java.base".getBytes(StandardCharsets.US_ASCII), StandardCharsets.US_ASCII))) + ).mapMulti(ConstantDescSymbolsTest::specializeInflation); + } + + static Stream inequalityCases() { + return Stream.of( + new ValidSymbolCase<>(CLASS_ENTRY_TRANSLATOR, CD_Object, ClassDesc.ofInternalName("java/io/Object")), // class or interface + new ValidSymbolCase<>(CLASS_ENTRY_TRANSLATOR, CD_Object.arrayType(), ClassDesc.ofDescriptor("[Ljava/lang/String;")), // array + new ValidSymbolCase<>(UTF8_CLASS_TRANSLATOR, CD_int, ClassDesc.ofDescriptor("S")), // primitive + new ValidSymbolCase<>(UTF8_CLASS_TRANSLATOR, CD_Object, ClassDesc.ofInternalName("java/lang/String")), // class or interface + new ValidSymbolCase<>(UTF8_CLASS_TRANSLATOR, CD_Object.arrayType(), ClassDesc.ofDescriptor("[Ljava/lang/System;")), // array + new ValidSymbolCase<>(UTF8_STRING_TRANSLATOR, "Ab\u0000c", "Abdc"), + new ValidSymbolCase<>(UTF8_METHOD_TYPE_TRANSLATOR, MTD_void, MethodTypeDesc.ofDescriptor("()I")), + new ValidSymbolCase<>(UTF8_METHOD_TYPE_TRANSLATOR, MethodTypeDesc.of(CD_int, CD_Short), MethodTypeDesc.ofDescriptor("(Ljava/lang/Long;)I")), + new ValidSymbolCase<>(METHOD_TYPE_ENTRY_TRANSLATOR, MethodTypeDesc.of(CD_String), MethodTypeDesc.ofDescriptor("()Ljava/lang/Object;")), + new ValidSymbolCase<>(STRING_ENTRY_TRANSLATOR, "Cat", new String("Ape".getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)), + new ValidSymbolCase<>(PACKAGE_ENTRY_TRANSLATOR, PackageDesc.of("java.lang"), PackageDesc.ofInternalName("java/util")), + new ValidSymbolCase<>(MODULE_ENTRY_TRANSLATOR, ModuleDesc.of("java.base"), ModuleDesc.of(new String("java.desktop".getBytes(StandardCharsets.US_ASCII), StandardCharsets.US_ASCII))) + ).mapMulti(ConstantDescSymbolsTest::specializeInflation); + } + + record InvalidSymbolCase(SymbolicTranslator translator, Supplier

                factory, T target) { + } + + // Type hint function + private static

                Supplier

                badFactory(Function func) { + return () -> func.apply(ConstantPoolBuilder.of()); + } + + static void specializeInflation(InvalidSymbolCase invalidSymbolCase, Consumer callArgs) { + invalidSymbolCase.translator.spawnBounded(invalidSymbolCase.factory) + .>mapMulti((src, sink) -> { + sink.accept(src); + sink.accept(invalidSymbolCase.translator.inflateByMatching(src, invalidSymbolCase.target, "target")); + }) + .forEach(stateful -> callArgs.accept(Arguments.of(invalidSymbolCase, stateful.desc, stateful.factory.get()))); + } + + static Stream malformedCases() { + return Stream.of( + new InvalidSymbolCase<>(CLASS_ENTRY_TRANSLATOR, badFactory(b -> b.classEntry(b.utf8Entry("java.lang.Object"))), CD_Object), // class or interface + new InvalidSymbolCase<>(CLASS_ENTRY_TRANSLATOR, badFactory(b -> b.classEntry(b.utf8Entry("[Ljava/lang/String"))), CD_String.arrayType()), // array + new InvalidSymbolCase<>(UTF8_CLASS_TRANSLATOR, badFactory(b -> b.utf8Entry("int")), ClassDesc.ofDescriptor("I")), // primitive + new InvalidSymbolCase<>(UTF8_CLASS_TRANSLATOR, badFactory(b -> b.utf8Entry("Ljava/lang/String")), CD_String), // class or interface + new InvalidSymbolCase<>(UTF8_CLASS_TRANSLATOR, badFactory(b -> b.utf8Entry("[Ljava/lang/String")), CD_String.arrayType()), // array + new InvalidSymbolCase<>(METHOD_TYPE_ENTRY_TRANSLATOR, badFactory(b -> b.methodTypeEntry(b.utf8Entry("()"))), MTD_void), + new InvalidSymbolCase<>(METHOD_TYPE_ENTRY_TRANSLATOR, badFactory(b -> b.methodTypeEntry(b.utf8Entry("(V)"))), MTD_void), + new InvalidSymbolCase<>(UTF8_METHOD_TYPE_TRANSLATOR, badFactory(b -> b.utf8Entry("()Ljava/lang/String")), MethodTypeDesc.of(CD_String)), + new InvalidSymbolCase<>(PACKAGE_ENTRY_TRANSLATOR, badFactory(b -> b.packageEntry(b.utf8Entry("java.lang"))), PackageDesc.of("java.lang")), + new InvalidSymbolCase<>(MODULE_ENTRY_TRANSLATOR, badFactory(b -> b.moduleEntry(b.utf8Entry("java@base"))), ModuleDesc.of("java.base")) + ).mapMulti(ConstantDescSymbolsTest::specializeInflation); + } } diff --git a/test/jdk/jdk/classfile/SignaturesTest.java b/test/jdk/jdk/classfile/SignaturesTest.java index 4bba69735da..692db1dbb29 100644 --- a/test/jdk/jdk/classfile/SignaturesTest.java +++ b/test/jdk/jdk/classfile/SignaturesTest.java @@ -24,7 +24,7 @@ /* * @test * @summary Testing Signatures. - * @bug 8321540 8319463 + * @bug 8321540 8319463 8357955 * @run junit SignaturesTest */ import java.io.IOException; @@ -300,6 +300,20 @@ void testBadMethodSignatures() { """.lines().forEach(assertThrows(MethodSignature::parseFrom)); } + @Test + void testArraySignatureLimits() { + var sig = Signature.parseFrom("I"); + var arrSig = Signature.parseFrom("[I"); + for (int dim : List.of(256, -1, 0)) + Assertions.assertThrows(IllegalArgumentException.class, () -> Signature.ArrayTypeSig.of(dim, sig)); + for (int dim : List.of(255, -1, 0)) + Assertions.assertThrows(IllegalArgumentException.class, () -> Signature.ArrayTypeSig.of(dim, arrSig)); + for (int dim : List.of(255, 1)) + Signature.ArrayTypeSig.of(dim, sig); + for (int dim : List.of(254, 1)) + Signature.ArrayTypeSig.of(dim, arrSig); + } + private Consumer assertThrows(Function parser) { return s -> Assertions.assertThrows(IllegalArgumentException.class, () -> parser.apply(s), s); } diff --git a/test/jdk/jdk/incubator/vector/AbstractVectorLoadStoreTest.java b/test/jdk/jdk/incubator/vector/AbstractVectorLoadStoreTest.java index 01d4951aaa2..46acd611ba3 100644 --- a/test/jdk/jdk/incubator/vector/AbstractVectorLoadStoreTest.java +++ b/test/jdk/jdk/incubator/vector/AbstractVectorLoadStoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,9 @@ * questions. */ +import jdk.incubator.vector.VectorSpecies; +import org.testng.annotations.DataProvider; + import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; @@ -32,28 +35,104 @@ import java.util.Objects; import java.util.Set; import java.util.function.IntFunction; +import java.util.function.IntUnaryOperator; +import java.util.function.Supplier; +import java.util.function.ToIntFunction; +import java.util.stream.IntStream; import java.util.stream.Stream; public class AbstractVectorLoadStoreTest extends AbstractVectorTest { + static final ValueLayout.OfInt SHUFFLE_ELEMENT_LAYOUT = ValueLayout.JAVA_INT.withByteAlignment(1); + static final Collection BYTE_ORDER_VALUES = Set.of( ByteOrder.BIG_ENDIAN, ByteOrder.LITTLE_ENDIAN); - static final List> BYTE_BUFFER_GENERATORS = List.of( - withToString("HB:RW:NE", (int s) -> - ByteBuffer.allocate(s) - .order(ByteOrder.nativeOrder())), - withToString("DB:RW:NE", (int s) -> - ByteBuffer.allocateDirect(s) - .order(ByteOrder.nativeOrder())), - withToString("MS:RW:NE", (int s) -> - Arena.ofAuto().allocate(s) - .asByteBuffer() - .order(ByteOrder.nativeOrder()) - ) + static final int SHUFFLE_BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); + + static final List> SHUFFLE_INT_GENERATORS = List.of( + withToString("int[i * 5]", (int s) -> { + return fill(s * SHUFFLE_BUFFER_REPS, + i -> (int)(i * 5)); + }), + withToString("int[i + 1]", (int s) -> { + return fill(s * SHUFFLE_BUFFER_REPS, + i -> (((int)(i + 1) == 0) ? 1 : (int)(i + 1))); + }) + ); + + static final List> SHUFFLE_INDEX_GENERATORS = List.of( + withToString("-1", (int l) -> { + return -1; + }), + withToString("l", (int l) -> { + return l; + }), + withToString("l - 1", (int l) -> { + return l - 1; + }), + withToString("l + 1", (int l) -> { + return l + 1; + }) + ); + + // Relative to byte[] array.length or MemorySegment.byteSize() + static final List> SHUFFLE_BYTE_INDEX_GENERATORS = List.of( + withToString("-1", (int l) -> { + return -1; + }), + withToString("l", (int l) -> { + return l; + }), + withToString("l - 1", (int l) -> { + return l - 1; + }), + withToString("l + 1", (int l) -> { + return l + 1; + }) ); - static final List> MEMORY_SEGMENT_GENERATORS = List.of( + @DataProvider + public Object[][] shuffleIntProvider() { + return SHUFFLE_INT_GENERATORS.stream() + .map(f -> new Object[]{f}) + .toArray(Object[][]::new); + } + + @DataProvider + public Object[][] shuffleIntProviderForIOOBE() { + var f = SHUFFLE_INT_GENERATORS.get(0); + return SHUFFLE_INDEX_GENERATORS.stream() + .map(fi -> { + return new Object[] {f, fi}; + }) + .toArray(Object[][]::new); + } + + @DataProvider + public Object[][] shuffleIntMemorySegmentProvider() { + return SHUFFLE_INT_GENERATORS.stream(). + flatMap(fa -> SHUFFLE_MEMORY_SEGMENT_GENERATORS.stream(). + flatMap(fb -> BYTE_ORDER_VALUES.stream().map(bo -> { + return new Object[]{fa, fb, bo}; + }))). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] shuffleIntByteProviderForIOOBE() { + var f = SHUFFLE_INT_GENERATORS.get(0); + return SHUFFLE_BYTE_INDEX_GENERATORS.stream().map(fi -> { + return new Object[] {f, fi}; + }).toArray(Object[][]::new); + } + + static MemorySegment toShuffleSegment(VectorSpecies vsp, int[] a, IntFunction fb) { + MemorySegment ms = fb.apply(a.length * 4); + return ms.copyFrom(MemorySegment.ofArray(a)); + } + + private static final List> SHARED_MEMORY_SEGMENT_GENERATORS = List.of( withToString("DMS", (int s) -> Arena.ofAuto().allocate(s) ), @@ -73,14 +152,6 @@ public class AbstractVectorLoadStoreTest extends AbstractVectorTest { float[] b = new float[s / Float.BYTES]; return MemorySegment.ofArray(b); }), - withToString("HMS:long[]", (int s) -> { - long[] b = new long[s / Long.BYTES]; - return MemorySegment.ofArray(b); - }), - withToString("HMS:double[]", (int s) -> { - double[] b = new double[s / Double.BYTES]; - return MemorySegment.ofArray(b); - }), withToString("HMS:ByteBuffer.wrap", (int s) -> { byte[] b = new byte[s]; ByteBuffer buff = ByteBuffer.wrap(b); @@ -100,12 +171,54 @@ public class AbstractVectorLoadStoreTest extends AbstractVectorTest { withToString("HMS:IntBuffer.allocate", (int s) -> { IntBuffer buff = IntBuffer.allocate(s / Integer.BYTES); return MemorySegment.ofBuffer(buff); - }), - // Slice - withToString("HMS:long[].asSlice", (int s) -> { - long[] b = new long[s / Long.BYTES + 1]; - return MemorySegment.ofArray(b).asSlice(Long.BYTES); }) ); + + //These tests are adjusted to ensure we allocate enough memory for ints because we're passing + //a memory segment size of an int array in bytes, but it's subject to integer division of a longer + //array element. + static final List> SHUFFLE_MEMORY_SEGMENT_GENERATORS = Stream.concat( + SHARED_MEMORY_SEGMENT_GENERATORS.stream(), + Stream.of( + withToString("HMS:long[]:shuffle", (int s) -> { + long[] b = new long[(s + Long.BYTES- 1) / Long.BYTES]; + return MemorySegment.ofArray(b); + }), + + withToString("HMS:double[]:shuffle", (int s) -> { + double[] b = new double[(s + Double.BYTES - 1)/ Double.BYTES]; + return MemorySegment.ofArray(b); + }), + // Slice + withToString("HMS:long[].asSlice:shuffle", (int s) -> { + long[] b = new long[(s + Long.BYTES - 1) / Long.BYTES + 1]; + return MemorySegment.ofArray(b).asSlice(Long.BYTES); + }) + ) + ).toList(); + + static final List> MEMORY_SEGMENT_GENERATORS = Stream.concat( + SHARED_MEMORY_SEGMENT_GENERATORS.stream(), + Stream.of( + withToString("HMS:long[]", (int s) -> { + long[] b = new long[s / Long.BYTES]; + return MemorySegment.ofArray(b); + }), + withToString("HMS:double[]", (int s) -> { + double[] b = new double[s / Double.BYTES]; + return MemorySegment.ofArray(b); + }), + // Slice + withToString("HMS:long[].asSlice", (int s) -> { + long[] b = new long[s / Long.BYTES + 1]; + return MemorySegment.ofArray(b).asSlice(Long.BYTES); + }) + ) + ).toList(); + + private static final int[] fill(int s, IntUnaryOperator f) { + return IntStream.range(0, s).map(f).toArray(); + } + } diff --git a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java index 9352091bafc..71cabe75b76 100644 --- a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java +++ b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,19 +22,16 @@ */ import java.lang.Integer; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.Arrays; -import java.util.Collection; -import java.util.List; import java.util.Random; -import java.util.Set; import java.util.function.BiFunction; import java.util.function.IntFunction; import java.util.function.IntUnaryOperator; import java.util.stream.Stream; +import java.util.List; import java.util.stream.Collectors; +import jdk.incubator.vector.VectorSpecies; import jdk.test.lib.Utils; import org.testng.Assert; @@ -227,4 +224,18 @@ static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBooleanBi Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); } } + + // Non-optimized test partial wrap derived from the Spec: + // Validation function for lane indexes which may be out of the valid range of [0..VLENGTH-1]. + // The index is forced into this range by adding or subtracting a suitable multiple of VLENGTH. + // Specifically, the index is reduced into the required range by computing the value of length-floor, where + // floor=vectorSpecies().loopBound(length) is the next lower multiple of VLENGTH. + // As long as VLENGTH is a power of two, then the reduced index also equal to index & (VLENGTH - 1). + static int testPartiallyWrapIndex(VectorSpecies vsp, int index) { + if (index >= 0 && index < vsp.length()) { + return index; + } + int wrapped = Math.floorMod(index, vsp.length()); + return wrapped - vsp.length(); + } } diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java index ee428120d9d..e450e3ead7e 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static byte[] fill(byte[] a, ToByteF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ByteVector fromArray(byte[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(boolean[] r, byte[] a) { diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index 7c8265169f4..5ead28c47f0 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBi } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2907,6 +2933,112 @@ static void ROLByte128VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static ByteVector bv_MIN = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MINByte128VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte128VectorTests::MIN); + } + + static ByteVector bv_min = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void minByte128VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte128VectorTests::min); + } + + static ByteVector bv_MIN_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MINByte128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, Byte128VectorTests::MIN); + } + + static ByteVector bv_MAX = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXByte128VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte128VectorTests::MAX); + } + + static ByteVector bv_max = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void maxByte128VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte128VectorTests::max); + } + + static ByteVector bv_MAX_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MAXByte128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, Byte128VectorTests::MAX); + } + static byte MIN(byte a, byte b) { return (byte)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java index 45d7b914776..a818043aedc 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static byte[] fill(byte[] a, ToByteF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ByteVector fromArray(byte[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(boolean[] r, byte[] a) { diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index 0fbbca79f5d..22d645b2502 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBi } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2907,6 +2933,112 @@ static void ROLByte256VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static ByteVector bv_MIN = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MINByte256VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte256VectorTests::MIN); + } + + static ByteVector bv_min = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void minByte256VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte256VectorTests::min); + } + + static ByteVector bv_MIN_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MINByte256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, Byte256VectorTests::MIN); + } + + static ByteVector bv_MAX = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXByte256VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte256VectorTests::MAX); + } + + static ByteVector bv_max = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void maxByte256VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte256VectorTests::max); + } + + static ByteVector bv_MAX_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MAXByte256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, Byte256VectorTests::MAX); + } + static byte MIN(byte a, byte b) { return (byte)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java index ddbe78b7099..7df9c1fbf10 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static byte[] fill(byte[] a, ToByteF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ByteVector fromArray(byte[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(boolean[] r, byte[] a) { diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index a17e621a0e6..738d6898374 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBi } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2907,6 +2933,112 @@ static void ROLByte512VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static ByteVector bv_MIN = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MINByte512VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte512VectorTests::MIN); + } + + static ByteVector bv_min = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void minByte512VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte512VectorTests::min); + } + + static ByteVector bv_MIN_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MINByte512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, Byte512VectorTests::MIN); + } + + static ByteVector bv_MAX = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXByte512VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte512VectorTests::MAX); + } + + static ByteVector bv_max = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void maxByte512VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte512VectorTests::max); + } + + static ByteVector bv_MAX_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MAXByte512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, Byte512VectorTests::MAX); + } + static byte MIN(byte a, byte b) { return (byte)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java index 139ed113963..870b9f9b8fb 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static byte[] fill(byte[] a, ToByteF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ByteVector fromArray(byte[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(boolean[] r, byte[] a) { diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index 58f1d6295a0..6d80672f3eb 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBi } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2907,6 +2933,112 @@ static void ROLByte64VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static ByteVector bv_MIN = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MINByte64VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte64VectorTests::MIN); + } + + static ByteVector bv_min = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void minByte64VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte64VectorTests::min); + } + + static ByteVector bv_MIN_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MINByte64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, Byte64VectorTests::MIN); + } + + static ByteVector bv_MAX = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXByte64VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte64VectorTests::MAX); + } + + static ByteVector bv_max = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void maxByte64VectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, Byte64VectorTests::max); + } + + static ByteVector bv_MAX_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MAXByte64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, Byte64VectorTests::MAX); + } + static byte MIN(byte a, byte b) { return (byte)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java index 3ea2205f515..bd5afc3f05a 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,6 +256,26 @@ static byte[] fill(byte[] a, ToByteF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ByteVector fromArray(byte[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -689,18 +709,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(boolean[] r, byte[] a) { diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index 9aaf1b6db95..276ee98fd62 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -421,6 +421,17 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, FBinOp f) { int i = 0; try { @@ -460,6 +471,21 @@ static void assertArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBi } } + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(byte[] r, byte[] a, byte b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(byte[] r, byte[] a, byte[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2912,6 +2938,112 @@ static void ROLByteMaxVectorTestsScalarShiftMaskedConst(IntFunction fa, } + static ByteVector bv_MIN = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MINByteMaxVectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, ByteMaxVectorTests::MIN); + } + + static ByteVector bv_min = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void minByteMaxVectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, ByteMaxVectorTests::min); + } + + static ByteVector bv_MIN_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MINByteMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, ByteMaxVectorTests::MIN); + } + + static ByteVector bv_MAX = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void MAXByteMaxVectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, ByteMaxVectorTests::MAX); + } + + static ByteVector bv_max = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpProvider") + static void maxByteMaxVectorTestsWithMemOp(IntFunction fa) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, ByteMaxVectorTests::max); + } + + static ByteVector bv_MAX_M = ByteVector.broadcast(SPECIES, (byte)10); + + @Test(dataProvider = "byteUnaryOpMaskProvider") + static void MAXByteMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + byte[] a = fa.apply(SPECIES.length()); + byte[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ByteVector av = ByteVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (byte)10, mask, ByteMaxVectorTests::MAX); + } + static byte MIN(byte a, byte b) { return (byte)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java index b1b5726c8cc..fed75349f68 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static double[] fill(double[] a, ToDoubleF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static DoubleVector fromArray(double[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 05678c4290b..9aea4137a3c 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -434,6 +434,17 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { } } + static void assertArraysEquals(double[] r, double[] a, double b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { int i = 0; try { @@ -473,6 +484,21 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, boolean[] mas } } + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2024,6 +2050,112 @@ static void ADDDouble128VectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double128VectorTests::MIN); + } + + static DoubleVector bv_min = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void minDouble128VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double128VectorTests::min); + } + + static DoubleVector bv_MIN_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MINDouble128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, Double128VectorTests::MIN); + } + + static DoubleVector bv_MAX = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXDouble128VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double128VectorTests::MAX); + } + + static DoubleVector bv_max = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void maxDouble128VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double128VectorTests::max); + } + + static DoubleVector bv_MAX_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MAXDouble128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, Double128VectorTests::MAX); + } + static double MIN(double a, double b) { return (double)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java index 96f7602c7c4..d8a7eca2bda 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static double[] fill(double[] a, ToDoubleF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static DoubleVector fromArray(double[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index fe59fc85a2e..b0d9825fa9d 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -434,6 +434,17 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { } } + static void assertArraysEquals(double[] r, double[] a, double b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { int i = 0; try { @@ -473,6 +484,21 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, boolean[] mas } } + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2024,6 +2050,112 @@ static void ADDDouble256VectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double256VectorTests::MIN); + } + + static DoubleVector bv_min = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void minDouble256VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double256VectorTests::min); + } + + static DoubleVector bv_MIN_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MINDouble256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, Double256VectorTests::MIN); + } + + static DoubleVector bv_MAX = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXDouble256VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double256VectorTests::MAX); + } + + static DoubleVector bv_max = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void maxDouble256VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double256VectorTests::max); + } + + static DoubleVector bv_MAX_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MAXDouble256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, Double256VectorTests::MAX); + } + static double MIN(double a, double b) { return (double)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java index 85d41b4ea3d..ddf76df1f3a 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static double[] fill(double[] a, ToDoubleF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static DoubleVector fromArray(double[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 1e5b68ab989..672c943bae2 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -434,6 +434,17 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { } } + static void assertArraysEquals(double[] r, double[] a, double b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { int i = 0; try { @@ -473,6 +484,21 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, boolean[] mas } } + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2024,6 +2050,112 @@ static void ADDDouble512VectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double512VectorTests::MIN); + } + + static DoubleVector bv_min = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void minDouble512VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double512VectorTests::min); + } + + static DoubleVector bv_MIN_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MINDouble512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, Double512VectorTests::MIN); + } + + static DoubleVector bv_MAX = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXDouble512VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double512VectorTests::MAX); + } + + static DoubleVector bv_max = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void maxDouble512VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double512VectorTests::max); + } + + static DoubleVector bv_MAX_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MAXDouble512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, Double512VectorTests::MAX); + } + static double MIN(double a, double b) { return (double)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java index c197ecef8c0..e2c48d84529 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static double[] fill(double[] a, ToDoubleF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static DoubleVector fromArray(double[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index b56b4d237f4..415763c5882 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -434,6 +434,17 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { } } + static void assertArraysEquals(double[] r, double[] a, double b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { int i = 0; try { @@ -473,6 +484,21 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, boolean[] mas } } + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2024,6 +2050,112 @@ static void ADDDouble64VectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double64VectorTests::MIN); + } + + static DoubleVector bv_min = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void minDouble64VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double64VectorTests::min); + } + + static DoubleVector bv_MIN_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MINDouble64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, Double64VectorTests::MIN); + } + + static DoubleVector bv_MAX = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXDouble64VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double64VectorTests::MAX); + } + + static DoubleVector bv_max = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void maxDouble64VectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, Double64VectorTests::max); + } + + static DoubleVector bv_MAX_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MAXDouble64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, Double64VectorTests::MAX); + } + static double MIN(double a, double b) { return (double)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java index 1b7868a3e3b..f8ea6d7c4a2 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,6 +256,26 @@ static double[] fill(double[] a, ToDoubleF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static DoubleVector fromArray(double[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -689,18 +709,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index 43da4f57636..992f16006db 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -439,6 +439,17 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { } } + static void assertArraysEquals(double[] r, double[] a, double b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, FBinOp f) { int i = 0; try { @@ -478,6 +489,21 @@ static void assertArraysEquals(double[] r, double[] a, double[] b, boolean[] mas } } + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(double[] r, double[] a, double b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(double[] r, double[] a, double[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2029,6 +2055,112 @@ static void ADDDoubleMaxVectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, DoubleMaxVectorTests::MIN); + } + + static DoubleVector bv_min = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void minDoubleMaxVectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, DoubleMaxVectorTests::min); + } + + static DoubleVector bv_MIN_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MINDoubleMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, DoubleMaxVectorTests::MIN); + } + + static DoubleVector bv_MAX = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void MAXDoubleMaxVectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, DoubleMaxVectorTests::MAX); + } + + static DoubleVector bv_max = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpProvider") + static void maxDoubleMaxVectorTestsWithMemOp(IntFunction fa) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, DoubleMaxVectorTests::max); + } + + static DoubleVector bv_MAX_M = DoubleVector.broadcast(SPECIES, (double)10); + + @Test(dataProvider = "doubleUnaryOpMaskProvider") + static void MAXDoubleMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + double[] a = fa.apply(SPECIES.length()); + double[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (double)10, mask, DoubleMaxVectorTests::MAX); + } + static double MIN(double a, double b) { return (double)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java index 7a9de397eee..4421c355c14 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static float[] fill(float[] a, ToFloatF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static FloatVector fromArray(float[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 549199513d5..4fc6d1bdb45 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -434,6 +434,17 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { } } + static void assertArraysEquals(float[] r, float[] a, float b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { int i = 0; try { @@ -473,6 +484,21 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, } } + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2035,6 +2061,112 @@ static void ADDFloat128VectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float128VectorTests::MIN); + } + + static FloatVector bv_min = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void minFloat128VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float128VectorTests::min); + } + + static FloatVector bv_MIN_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MINFloat128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, Float128VectorTests::MIN); + } + + static FloatVector bv_MAX = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXFloat128VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float128VectorTests::MAX); + } + + static FloatVector bv_max = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void maxFloat128VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float128VectorTests::max); + } + + static FloatVector bv_MAX_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MAXFloat128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, Float128VectorTests::MAX); + } + static float MIN(float a, float b) { return (float)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java index 511674f7a2a..0ad426d9954 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static float[] fill(float[] a, ToFloatF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static FloatVector fromArray(float[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 6d17727c325..59104c40b9e 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -434,6 +434,17 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { } } + static void assertArraysEquals(float[] r, float[] a, float b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { int i = 0; try { @@ -473,6 +484,21 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, } } + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2035,6 +2061,112 @@ static void ADDFloat256VectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float256VectorTests::MIN); + } + + static FloatVector bv_min = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void minFloat256VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float256VectorTests::min); + } + + static FloatVector bv_MIN_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MINFloat256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, Float256VectorTests::MIN); + } + + static FloatVector bv_MAX = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXFloat256VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float256VectorTests::MAX); + } + + static FloatVector bv_max = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void maxFloat256VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float256VectorTests::max); + } + + static FloatVector bv_MAX_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MAXFloat256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, Float256VectorTests::MAX); + } + static float MIN(float a, float b) { return (float)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java index 9efcfe31fc7..56da27f1149 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static float[] fill(float[] a, ToFloatF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static FloatVector fromArray(float[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index c2290eb7080..3cc45a88e84 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -434,6 +434,17 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { } } + static void assertArraysEquals(float[] r, float[] a, float b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { int i = 0; try { @@ -473,6 +484,21 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, } } + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2035,6 +2061,112 @@ static void ADDFloat512VectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float512VectorTests::MIN); + } + + static FloatVector bv_min = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void minFloat512VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float512VectorTests::min); + } + + static FloatVector bv_MIN_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MINFloat512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, Float512VectorTests::MIN); + } + + static FloatVector bv_MAX = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXFloat512VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float512VectorTests::MAX); + } + + static FloatVector bv_max = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void maxFloat512VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float512VectorTests::max); + } + + static FloatVector bv_MAX_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MAXFloat512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, Float512VectorTests::MAX); + } + static float MIN(float a, float b) { return (float)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java index e1aa2f34cb1..b3ee68a4aca 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static float[] fill(float[] a, ToFloatF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static FloatVector fromArray(float[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index 0d50726f644..70aaeb134a6 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -434,6 +434,17 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { } } + static void assertArraysEquals(float[] r, float[] a, float b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { int i = 0; try { @@ -473,6 +484,21 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, } } + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2035,6 +2061,112 @@ static void ADDFloat64VectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float64VectorTests::MIN); + } + + static FloatVector bv_min = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void minFloat64VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float64VectorTests::min); + } + + static FloatVector bv_MIN_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MINFloat64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, Float64VectorTests::MIN); + } + + static FloatVector bv_MAX = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXFloat64VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float64VectorTests::MAX); + } + + static FloatVector bv_max = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void maxFloat64VectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, Float64VectorTests::max); + } + + static FloatVector bv_MAX_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MAXFloat64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, Float64VectorTests::MAX); + } + static float MIN(float a, float b) { return (float)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java index ff9d0e67202..5c86ab350d2 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,6 +256,26 @@ static float[] fill(float[] a, ToFloatF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static FloatVector fromArray(float[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -689,18 +709,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 6a0b1301ab3..c22b2d329f1 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -439,6 +439,17 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { } } + static void assertArraysEquals(float[] r, float[] a, float b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, FBinOp f) { int i = 0; try { @@ -478,6 +489,21 @@ static void assertArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, } } + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(float[] r, float[] a, float b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(float[] r, float[] a, float[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2040,6 +2066,112 @@ static void ADDFloatMaxVectorTestsBroadcastMaskedLongSmokeTest(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, FloatMaxVectorTests::MIN); + } + + static FloatVector bv_min = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void minFloatMaxVectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, FloatMaxVectorTests::min); + } + + static FloatVector bv_MIN_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MINFloatMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, FloatMaxVectorTests::MIN); + } + + static FloatVector bv_MAX = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void MAXFloatMaxVectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, FloatMaxVectorTests::MAX); + } + + static FloatVector bv_max = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpProvider") + static void maxFloatMaxVectorTestsWithMemOp(IntFunction fa) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + + 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); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, FloatMaxVectorTests::max); + } + + static FloatVector bv_MAX_M = FloatVector.broadcast(SPECIES, (float)10); + + @Test(dataProvider = "floatUnaryOpMaskProvider") + static void MAXFloatMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + float[] a = fa.apply(SPECIES.length()); + float[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + FloatVector av = FloatVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (float)10, mask, FloatMaxVectorTests::MAX); + } + static float MIN(float a, float b) { return (float)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java index fc678965d0f..f2448365138 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static int[] fill(int[] a, ToIntF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static IntVector fromArray(int[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index 4f8f296c519..a88dcf27888 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { } } + static void assertArraysEquals(int[] r, int[] a, int b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinMa } } + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2951,6 +2977,112 @@ static void ROLInt128VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static IntVector bv_MIN = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MINInt128VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int128VectorTests::MIN); + } + + static IntVector bv_min = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void minInt128VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int128VectorTests::min); + } + + static IntVector bv_MIN_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MINInt128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, Int128VectorTests::MIN); + } + + static IntVector bv_MAX = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MAXInt128VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int128VectorTests::MAX); + } + + static IntVector bv_max = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void maxInt128VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int128VectorTests::max); + } + + static IntVector bv_MAX_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MAXInt128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, Int128VectorTests::MAX); + } + static int MIN(int a, int b) { return (int)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java index 85027d700d2..1a8c113d3b9 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static int[] fill(int[] a, ToIntF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static IntVector fromArray(int[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index 312227c54e1..1b88adf9c21 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { } } + static void assertArraysEquals(int[] r, int[] a, int b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinMa } } + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2951,6 +2977,112 @@ static void ROLInt256VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static IntVector bv_MIN = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MINInt256VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int256VectorTests::MIN); + } + + static IntVector bv_min = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void minInt256VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int256VectorTests::min); + } + + static IntVector bv_MIN_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MINInt256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, Int256VectorTests::MIN); + } + + static IntVector bv_MAX = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MAXInt256VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int256VectorTests::MAX); + } + + static IntVector bv_max = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void maxInt256VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int256VectorTests::max); + } + + static IntVector bv_MAX_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MAXInt256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, Int256VectorTests::MAX); + } + static int MIN(int a, int b) { return (int)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java index f9b72103107..4c4ab6c4bc5 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static int[] fill(int[] a, ToIntF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static IntVector fromArray(int[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index 3e5b51180b6..a9da97d66ce 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { } } + static void assertArraysEquals(int[] r, int[] a, int b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinMa } } + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2951,6 +2977,112 @@ static void ROLInt512VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static IntVector bv_MIN = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MINInt512VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int512VectorTests::MIN); + } + + static IntVector bv_min = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void minInt512VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int512VectorTests::min); + } + + static IntVector bv_MIN_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MINInt512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, Int512VectorTests::MIN); + } + + static IntVector bv_MAX = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MAXInt512VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int512VectorTests::MAX); + } + + static IntVector bv_max = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void maxInt512VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int512VectorTests::max); + } + + static IntVector bv_MAX_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MAXInt512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, Int512VectorTests::MAX); + } + static int MIN(int a, int b) { return (int)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java index 6dc2bb1a504..a1fa9a8b16c 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static int[] fill(int[] a, ToIntF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static IntVector fromArray(int[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index fccad11d4d6..b41bf7b95d5 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { } } + static void assertArraysEquals(int[] r, int[] a, int b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinMa } } + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2951,6 +2977,112 @@ static void ROLInt64VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static IntVector bv_MIN = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MINInt64VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int64VectorTests::MIN); + } + + static IntVector bv_min = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void minInt64VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int64VectorTests::min); + } + + static IntVector bv_MIN_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MINInt64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, Int64VectorTests::MIN); + } + + static IntVector bv_MAX = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MAXInt64VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int64VectorTests::MAX); + } + + static IntVector bv_max = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void maxInt64VectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, Int64VectorTests::max); + } + + static IntVector bv_MAX_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MAXInt64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, Int64VectorTests::MAX); + } + static int MIN(int a, int b) { return (int)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java index cc4aef80f6f..564849e22fd 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,6 +256,26 @@ static int[] fill(int[] a, ToIntF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static IntVector fromArray(int[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -689,18 +709,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index 3254c2fb86c..d2b910ba8ae 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -421,6 +421,17 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { } } + static void assertArraysEquals(int[] r, int[] a, int b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, FBinOp f) { int i = 0; try { @@ -460,6 +471,21 @@ static void assertArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinMa } } + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(int[] r, int[] a, int b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(int[] r, int[] a, int[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2956,6 +2982,112 @@ static void ROLIntMaxVectorTestsScalarShiftMaskedConst(IntFunction fa, } + static IntVector bv_MIN = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MINIntMaxVectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, IntMaxVectorTests::MIN); + } + + static IntVector bv_min = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void minIntMaxVectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, IntMaxVectorTests::min); + } + + static IntVector bv_MIN_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MINIntMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, IntMaxVectorTests::MIN); + } + + static IntVector bv_MAX = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void MAXIntMaxVectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, IntMaxVectorTests::MAX); + } + + static IntVector bv_max = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpProvider") + static void maxIntMaxVectorTestsWithMemOp(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, IntMaxVectorTests::max); + } + + static IntVector bv_MAX_M = IntVector.broadcast(SPECIES, (int)10); + + @Test(dataProvider = "intUnaryOpMaskProvider") + static void MAXIntMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + int[] a = fa.apply(SPECIES.length()); + int[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + IntVector av = IntVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (int)10, mask, IntMaxVectorTests::MAX); + } + static int MIN(int a, int b) { return (int)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java index f9fb3a452a1..57a0880aed3 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static long[] fill(long[] a, ToLongF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static LongVector fromArray(long[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index 09fdc3c1979..5bc29f498ba 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -373,6 +373,17 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { } } + static void assertArraysEquals(long[] r, long[] a, long b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { int i = 0; try { @@ -412,6 +423,21 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBi } } + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2973,6 +2999,112 @@ static void ROLLong128VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static LongVector bv_MIN = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MINLong128VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long128VectorTests::MIN); + } + + static LongVector bv_min = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void minLong128VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long128VectorTests::min); + } + + static LongVector bv_MIN_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MINLong128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, Long128VectorTests::MIN); + } + + static LongVector bv_MAX = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MAXLong128VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long128VectorTests::MAX); + } + + static LongVector bv_max = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void maxLong128VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long128VectorTests::max); + } + + static LongVector bv_MAX_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MAXLong128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, Long128VectorTests::MAX); + } + static long MIN(long a, long b) { return (long)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java index 73e81a2635f..f07cf3e68b7 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static long[] fill(long[] a, ToLongF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static LongVector fromArray(long[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index 7dd0da772ed..25a73d1916e 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -373,6 +373,17 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { } } + static void assertArraysEquals(long[] r, long[] a, long b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { int i = 0; try { @@ -412,6 +423,21 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBi } } + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2973,6 +2999,112 @@ static void ROLLong256VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static LongVector bv_MIN = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MINLong256VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long256VectorTests::MIN); + } + + static LongVector bv_min = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void minLong256VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long256VectorTests::min); + } + + static LongVector bv_MIN_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MINLong256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, Long256VectorTests::MIN); + } + + static LongVector bv_MAX = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MAXLong256VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long256VectorTests::MAX); + } + + static LongVector bv_max = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void maxLong256VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long256VectorTests::max); + } + + static LongVector bv_MAX_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MAXLong256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, Long256VectorTests::MAX); + } + static long MIN(long a, long b) { return (long)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java index 7f38adb46a1..1b70f8d1ba4 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static long[] fill(long[] a, ToLongF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static LongVector fromArray(long[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 360e822e121..dab8ac0621a 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -373,6 +373,17 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { } } + static void assertArraysEquals(long[] r, long[] a, long b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { int i = 0; try { @@ -412,6 +423,21 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBi } } + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2973,6 +2999,112 @@ static void ROLLong512VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static LongVector bv_MIN = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MINLong512VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long512VectorTests::MIN); + } + + static LongVector bv_min = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void minLong512VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long512VectorTests::min); + } + + static LongVector bv_MIN_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MINLong512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, Long512VectorTests::MIN); + } + + static LongVector bv_MAX = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MAXLong512VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long512VectorTests::MAX); + } + + static LongVector bv_max = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void maxLong512VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long512VectorTests::max); + } + + static LongVector bv_MAX_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MAXLong512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, Long512VectorTests::MAX); + } + static long MIN(long a, long b) { return (long)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java index 398aec1981a..53df5e4e092 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static long[] fill(long[] a, ToLongF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static LongVector fromArray(long[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index 31f6fafea7c..f62ffc6554c 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -373,6 +373,17 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { } } + static void assertArraysEquals(long[] r, long[] a, long b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { int i = 0; try { @@ -412,6 +423,21 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBi } } + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2973,6 +2999,112 @@ static void ROLLong64VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static LongVector bv_MIN = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MINLong64VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long64VectorTests::MIN); + } + + static LongVector bv_min = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void minLong64VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long64VectorTests::min); + } + + static LongVector bv_MIN_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MINLong64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, Long64VectorTests::MIN); + } + + static LongVector bv_MAX = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MAXLong64VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long64VectorTests::MAX); + } + + static LongVector bv_max = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void maxLong64VectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, Long64VectorTests::max); + } + + static LongVector bv_MAX_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MAXLong64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, Long64VectorTests::MAX); + } + static long MIN(long a, long b) { return (long)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java index 48c2534b66c..e0f8b548228 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,6 +256,26 @@ static long[] fill(long[] a, ToLongF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static LongVector fromArray(long[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -689,18 +709,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index a3cacbe3251..70441d0d763 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -378,6 +378,17 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { } } + static void assertArraysEquals(long[] r, long[] a, long b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, FBinOp f) { int i = 0; try { @@ -417,6 +428,21 @@ static void assertArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBi } } + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(long[] r, long[] a, long b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(long[] r, long[] a, long[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2978,6 +3004,112 @@ static void ROLLongMaxVectorTestsScalarShiftMaskedConst(IntFunction fa, } + static LongVector bv_MIN = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MINLongMaxVectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, LongMaxVectorTests::MIN); + } + + static LongVector bv_min = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void minLongMaxVectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, LongMaxVectorTests::min); + } + + static LongVector bv_MIN_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MINLongMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, LongMaxVectorTests::MIN); + } + + static LongVector bv_MAX = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void MAXLongMaxVectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, LongMaxVectorTests::MAX); + } + + static LongVector bv_max = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpProvider") + static void maxLongMaxVectorTestsWithMemOp(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, LongMaxVectorTests::max); + } + + static LongVector bv_MAX_M = LongVector.broadcast(SPECIES, (long)10); + + @Test(dataProvider = "longUnaryOpMaskProvider") + static void MAXLongMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + long[] a = fa.apply(SPECIES.length()); + long[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + LongVector av = LongVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (long)10, mask, LongMaxVectorTests::MAX); + } + static long MIN(long a, long b) { return (long)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/PreferredSpeciesTest.java b/test/jdk/jdk/incubator/vector/PreferredSpeciesTest.java index f105df5756c..32d44d28ee1 100644 --- a/test/jdk/jdk/incubator/vector/PreferredSpeciesTest.java +++ b/test/jdk/jdk/incubator/vector/PreferredSpeciesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ /** * @test + * @bug 8356549 * @modules jdk.incubator.vector java.base/jdk.internal.vm.vector * @run testng PreferredSpeciesTest */ @@ -126,4 +127,33 @@ void testVectorShape(Class c) { Assert.assertEquals(largestSpecies.length(), maxLaneCount); Assert.assertEquals(largestSpecies.length(), Math.max(species.length(), maxLaneCount)); } + + // Testing VectorShape.largestShapeFor() for 8356549 + @Test(dataProvider = "classesProvider") + void testLargestShapeFor(Class c) { + final int S_64_BITS = 64; + int elemSize = 0; + if (c == byte.class) { + elemSize = Byte.SIZE; + } else if (c == short.class) { + elemSize = Short.SIZE; + } else if (c == int.class) { + elemSize = Integer.SIZE; + } else if (c == long.class) { + elemSize = Long.SIZE; + } else if (c == float.class) { + elemSize = Float.SIZE; + } else if (c == double.class) { + elemSize = Double.SIZE; + } else { + throw new IllegalArgumentException("Bad vector element type: " + c.getName()); + } + + VectorShape vs = VectorShape.largestShapeFor(c); + + int maxLaneCount = VectorSupport.getMaxLaneCount(c); + int max = Math.max(maxLaneCount * elemSize, S_64_BITS); + + Assert.assertEquals(vs.vectorBitSize(), max); + } } diff --git a/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java index 400b3c376a1..5a71c5550f3 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static short[] fill(short[] a, ToShortF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ShortVector fromArray(short[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(char[] a, char[] r, boolean[] mask) { int i = 0; diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index 967418181bf..b4240dabc87 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { } } + static void assertArraysEquals(short[] r, short[] a, short b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, } } + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2898,6 +2924,112 @@ static void ROLShort128VectorTestsScalarShiftMaskedConst(IntFunction fa } + static ShortVector bv_MIN = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MINShort128VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short128VectorTests::MIN); + } + + static ShortVector bv_min = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void minShort128VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short128VectorTests::min); + } + + static ShortVector bv_MIN_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MINShort128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, Short128VectorTests::MIN); + } + + static ShortVector bv_MAX = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXShort128VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short128VectorTests::MAX); + } + + static ShortVector bv_max = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void maxShort128VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short128VectorTests::max); + } + + static ShortVector bv_MAX_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MAXShort128VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, Short128VectorTests::MAX); + } + static short MIN(short a, short b) { return (short)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java index 92cecf534b5..335d51add59 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static short[] fill(short[] a, ToShortF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ShortVector fromArray(short[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(char[] a, char[] r, boolean[] mask) { int i = 0; diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 2386d89e53b..902cac11eb6 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { } } + static void assertArraysEquals(short[] r, short[] a, short b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, } } + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2898,6 +2924,112 @@ static void ROLShort256VectorTestsScalarShiftMaskedConst(IntFunction fa } + static ShortVector bv_MIN = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MINShort256VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short256VectorTests::MIN); + } + + static ShortVector bv_min = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void minShort256VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short256VectorTests::min); + } + + static ShortVector bv_MIN_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MINShort256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, Short256VectorTests::MIN); + } + + static ShortVector bv_MAX = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXShort256VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short256VectorTests::MAX); + } + + static ShortVector bv_max = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void maxShort256VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short256VectorTests::max); + } + + static ShortVector bv_MAX_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MAXShort256VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, Short256VectorTests::MAX); + } + static short MIN(short a, short b) { return (short)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java index a3d577afcdc..7a273986bef 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static short[] fill(short[] a, ToShortF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ShortVector fromArray(short[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(char[] a, char[] r, boolean[] mask) { int i = 0; diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index cb9fc1830b9..39ab2da2925 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { } } + static void assertArraysEquals(short[] r, short[] a, short b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, } } + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2898,6 +2924,112 @@ static void ROLShort512VectorTestsScalarShiftMaskedConst(IntFunction fa } + static ShortVector bv_MIN = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MINShort512VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short512VectorTests::MIN); + } + + static ShortVector bv_min = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void minShort512VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short512VectorTests::min); + } + + static ShortVector bv_MIN_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MINShort512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, Short512VectorTests::MIN); + } + + static ShortVector bv_MAX = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXShort512VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short512VectorTests::MAX); + } + + static ShortVector bv_max = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void maxShort512VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short512VectorTests::max); + } + + static ShortVector bv_MAX_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MAXShort512VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, Short512VectorTests::MAX); + } + static short MIN(short a, short b) { return (short)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java index dd420fd3613..952d71c80a6 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,26 @@ static short[] fill(short[] a, ToShortF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ShortVector fromArray(short[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -682,18 +702,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(char[] a, char[] r, boolean[] mask) { int i = 0; diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 64bb5f52329..ff3cea2e051 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -416,6 +416,17 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { } } + static void assertArraysEquals(short[] r, short[] a, short b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { int i = 0; try { @@ -455,6 +466,21 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, } } + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2898,6 +2924,112 @@ static void ROLShort64VectorTestsScalarShiftMaskedConst(IntFunction fa, } + static ShortVector bv_MIN = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MINShort64VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short64VectorTests::MIN); + } + + static ShortVector bv_min = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void minShort64VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short64VectorTests::min); + } + + static ShortVector bv_MIN_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MINShort64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, Short64VectorTests::MIN); + } + + static ShortVector bv_MAX = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXShort64VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short64VectorTests::MAX); + } + + static ShortVector bv_max = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void maxShort64VectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, Short64VectorTests::max); + } + + static ShortVector bv_MAX_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MAXShort64VectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, Short64VectorTests::MAX); + } + static short MIN(short a, short b) { return (short)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java index 90070d44389..91db367808a 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -256,6 +256,26 @@ static short[] fill(short[] a, ToShortF f) { return a; } + @DontInline + static VectorShuffle shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static ShortVector fromArray(short[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -689,18 +709,161 @@ static void loadStoreMask(IntFunction fm) { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } static void assertArraysEquals(char[] a, char[] r, boolean[] mask) { int i = 0; diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 6445443b9d6..25b219f8abc 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -421,6 +421,17 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { } } + static void assertArraysEquals(short[] r, short[] a, short b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, FBinOp f) { int i = 0; try { @@ -460,6 +471,21 @@ static void assertArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, } } + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals(short[] r, short[] a, short b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals(short[] r, short[] a, short[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } @@ -2903,6 +2929,112 @@ static void ROLShortMaxVectorTestsScalarShiftMaskedConst(IntFunction fa } + static ShortVector bv_MIN = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MINShortMaxVectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, ShortMaxVectorTests::MIN); + } + + static ShortVector bv_min = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void minShortMaxVectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.min(bv_min).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, ShortMaxVectorTests::min); + } + + static ShortVector bv_MIN_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MINShortMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MIN, bv_MIN_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, ShortMaxVectorTests::MIN); + } + + static ShortVector bv_MAX = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void MAXShortMaxVectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, ShortMaxVectorTests::MAX); + } + + static ShortVector bv_max = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpProvider") + static void maxShortMaxVectorTestsWithMemOp(IntFunction fa) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.max(bv_max).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, ShortMaxVectorTests::max); + } + + static ShortVector bv_MAX_M = ShortVector.broadcast(SPECIES, (short)10); + + @Test(dataProvider = "shortUnaryOpMaskProvider") + static void MAXShortMaxVectorTestsMaskedWithMemOp(IntFunction fa, IntFunction fm) { + short[] a = fa.apply(SPECIES.length()); + short[] r = fr.apply(SPECIES.length()); + boolean[] mask = fm.apply(SPECIES.length()); + VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + ShortVector av = ShortVector.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.MAX, bv_MAX_M, vmask).intoArray(r, i); + } + } + + assertArraysEquals(r, a, (short)10, mask, ShortMaxVectorTests::MAX); + } + static short MIN(short a, short b) { return (short)(Math.min(a, b)); } diff --git a/test/jdk/jdk/incubator/vector/gen-template.sh b/test/jdk/jdk/incubator/vector/gen-template.sh index 06e89b824cd..da5585b1305 100644 --- a/test/jdk/jdk/incubator/vector/gen-template.sh +++ b/test/jdk/jdk/incubator/vector/gen-template.sh @@ -42,6 +42,8 @@ ternary_double_broadcast_masked="Ternary-Double-Broadcast-Masked-op" ternary_scalar="Ternary-Scalar-op" binary="Binary-op" binary_masked="Binary-Masked-op" +binary_memop="Binary-mem-op" +binary_masked_memop="Binary-Masked-mem-op" saturating_binary="SaturatingBinary-op" saturating_binary_masked="SaturatingBinary-Masked-op" binary_broadcast="Binary-Broadcast-op" @@ -255,6 +257,12 @@ function gen_binary_alu_op { gen_op_tmpl $binary_masked "$@" } +function gen_binary_alu_mem_op { + echo "Generating binary op $1 ($2)..." + gen_op_tmpl $binary_memop "$@" + gen_op_tmpl $binary_masked_memop "$@" +} + function gen_binary_alu_bcst_op { echo "Generating binary broadcast op $1 ($2)..." gen_op_tmpl $binary_broadcast "$@" @@ -464,6 +472,10 @@ gen_shift_cst_op "ASHR" "(a >> CONST_SHIFT)" "BITWISE" gen_shift_cst_op "ROR" "ROR_scalar(a, CONST_SHIFT)" "BITWISE" gen_shift_cst_op "ROL" "ROL_scalar(a, CONST_SHIFT)" "BITWISE" +# Binary operation with one memory operand +gen_binary_alu_mem_op "MIN+min+withMask", "Math.min(a, b)" +gen_binary_alu_mem_op "MAX+max+withMask", "Math.max(a, b)" + # Masked reductions. gen_binary_op_no_masked "MIN+min" "Math.min(a, b)" gen_binary_op_no_masked "MAX+max" "Math.max(a, b)" diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Binary-Masked-mem-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Binary-Masked-mem-op.template new file mode 100644 index 00000000000..f42e5be6f39 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Binary-Masked-mem-op.template @@ -0,0 +1,11 @@ + $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); + + 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); + av.lanewise(VectorOperators.[[TEST]], bv_[[TEST]]_M, vmask).intoArray(r, i); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Binary-mem-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Binary-mem-op.template new file mode 100644 index 00000000000..a0231b3f653 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Binary-mem-op.template @@ -0,0 +1,9 @@ + $type$[] a = fa.apply(SPECIES.length()); + $type$[] r = fr.apply(SPECIES.length()); + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); + av.lanewise(VectorOperators.[[TEST]], bv_[[TEST]]).intoArray(r, i); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Binary-Masked-mem-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Binary-Masked-mem-op.template new file mode 100644 index 00000000000..3c2ffd68607 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Binary-Masked-mem-op.template @@ -0,0 +1,8 @@ + + static $abstractvectortype$ bv_[[TEST]]_M = $abstractvectortype$.broadcast(SPECIES, ($type$)10); + + @Test(dataProvider = "$type$UnaryOpMaskProvider") + static void [[TEST]]$vectorteststype$MaskedWithMemOp(IntFunction<$type$[]> fa, IntFunction fm) { +[[KERNEL]] + assertArraysEquals(r, a, ($type$)10, mask, $vectorteststype$::[[TEST]]); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Binary-mem-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Binary-mem-op.template new file mode 100644 index 00000000000..1fef6ddb989 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Binary-mem-op.template @@ -0,0 +1,8 @@ + + static $abstractvectortype$ bv_[[TEST]] = $abstractvectortype$.broadcast(SPECIES, ($type$)10); + + @Test(dataProvider = "$type$UnaryOpProvider") + static void [[TEST]]$vectorteststype$WithMemOp(IntFunction<$type$[]> fa) { +[[KERNEL]] + assertArraysEquals(r, a, ($type$)10, $vectorteststype$::[[TEST]]); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 991f82cc7cf..66646b15918 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -513,6 +513,17 @@ relativeError)); } } + static void assertArraysEquals($type$[] r, $type$[] a, $type$ b, FBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b)); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b), "(" + a[i] + ", " + b + ") at index #" + i); + } + } + static void assertBroadcastArraysEquals($type$[] r, $type$[] a, $type$[] b, FBinOp f) { int i = 0; try { @@ -552,6 +563,21 @@ relativeError)); } } + static void assertArraysEquals($type$[] r, $type$[] a, $type$ b, boolean[] mask, FBinOp f) { + assertArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); + } + + static void assertArraysEquals($type$[] r, $type$[] a, $type$ b, boolean[] mask, FBinMaskOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()])); + } + } catch (AssertionError err) { + Assert.assertEquals(r[i], f.apply(a[i], b, mask[i % SPECIES.length()]), "at index #" + i + ", input1 = " + a[i] + ", input2 = " + b + ", mask = " + mask[i % SPECIES.length()]); + } + } + static void assertBroadcastArraysEquals($type$[] r, $type$[] a, $type$[] b, boolean[] mask, FBinOp f) { assertBroadcastArraysEquals(r, a, b, mask, FBinMaskOp.lift(f)); } diff --git a/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template b/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template index 6473016a9a0..a68103e1060 100644 --- a/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template +++ b/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -269,6 +269,26 @@ public class $vectorteststype$ extends AbstractVectorLoadStoreTest { return a; } + @DontInline + static VectorShuffle<$Boxtype$> shuffleFromArray(int[] a, int i) { + return SPECIES.shuffleFromArray(a, i); + } + + @DontInline + static void shuffleIntoArray(VectorShuffle<$Boxtype$> s, int[] a, int i) { + s.intoArray(a, i); + } + + @DontInline + static VectorShuffle<$Boxtype$> shuffleFromMemorySegment(MemorySegment mem, int i, ByteOrder bo) { + return VectorShuffle.fromMemorySegment(SPECIES, mem, i, bo); + } + + @DontInline + static void shuffleIntoMemorySegment(VectorShuffle<$Boxtype$> s, MemorySegment mem, int i, ByteOrder bo) { + s.intoMemorySegment(mem, i, bo); + } + @DontInline static $abstractvectortype$ fromArray($type$[] a, int i) { // Tests the species method and the equivalent vector method it defers to @@ -702,18 +722,161 @@ public class $vectorteststype$ extends AbstractVectorLoadStoreTest { } - @Test - static void loadStoreShuffle() { - IntUnaryOperator fn = a -> a + 5; - for (int ic = 0; ic < INVOC_COUNT; ic++) { - var shuffle = VectorShuffle.fromOp(SPECIES, fn); - int [] r = shuffle.toArray(); + @Test(dataProvider = "shuffleIntProvider") + static void loadStoreShuffleArray(IntFunction fa) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; - int [] a = expectedShuffle(SPECIES.length(), fn); - Assert.assertEquals(r, a); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle<$Boxtype$> shuffle = VectorShuffle.fromArray(SPECIES, a, i); + shuffle.intoArray(r, i); + } } - } + for (int i = 0; i < a.length; i++) { + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, a[i]), r[i]); + } + + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void storeShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle<$Boxtype$> shuffle = shuffleFromArray(a, i); + shuffleIntoArray(shuffle, r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + VectorShuffle<$Boxtype$> shuffle = shuffleFromArray(a, index); + shuffleIntoArray(shuffle, r, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntProviderForIOOBE") + static void loadShuffleArrayIOOBE(IntFunction fa, IntFunction fi) { + int[] a = fa.apply(SPECIES.length()); + int[] r = new int[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorShuffle<$Boxtype$> shuffle = shuffleFromArray(a, i); + shuffle.intoArray(r, i); + } + } + + int index = fi.apply(a.length); + boolean shouldFail = isIndexOutOfBounds(SPECIES.length(), index, a.length); + try { + shuffleFromArray(a, index); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntMemorySegmentProvider") + static void loadStoreShuffleMemorySegment(IntFunction fa, + IntFunction fb, + ByteOrder bo) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), fb); + MemorySegment r = fb.apply((int) a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; //An integer for every lane is read out. So 4 bytes per lane + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle<$Boxtype$> shuffle = VectorShuffle.fromMemorySegment(SPECIES, a, i, bo); + shuffle.intoMemorySegment(r, i, bo); + } + } + + for (int i = 0; i < l / 4; i++) { + int ai = a.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + int ri = r.getAtIndex(ValueLayout.JAVA_INT_UNALIGNED.withOrder(bo), i); + Assert.assertEquals(testPartiallyWrapIndex(SPECIES, ai), ri); + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleLoadMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle<$Boxtype$> shuffle = shuffleFromMemorySegment(a, i, ByteOrder.nativeOrder()); + shuffle.intoMemorySegment(r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + shuffleFromMemorySegment(a, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } + + @Test(dataProvider = "shuffleIntByteProviderForIOOBE") + static void shuffleStoreMemorySegmentIOOBE(IntFunction fa, IntFunction fi) { + MemorySegment a = toShuffleSegment(SPECIES, fa.apply(SPECIES.length()), i -> Arena.ofAuto().allocate(i)); + MemorySegment r = Arena.ofAuto().allocate(a.byteSize()); + + int l = (int) a.byteSize(); + int s = SPECIES.length() * 4; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < l; i += s) { + VectorShuffle<$Boxtype$> shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, i, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, i, ByteOrder.nativeOrder()); + } + } + + int index = fi.apply((int) a.byteSize()); + boolean shouldFail = isIndexOutOfBounds(s, index, (int) a.byteSize()); + try { + VectorShuffle<$Boxtype$> shuffle = + VectorShuffle.fromMemorySegment(SPECIES, a, 0, ByteOrder.nativeOrder()); + shuffleIntoMemorySegment(shuffle, r, index, ByteOrder.nativeOrder()); + if (shouldFail) { + Assert.fail("Failed to throw IndexOutOfBoundsException"); + } + } catch (IndexOutOfBoundsException e) { + if (!shouldFail) { + Assert.fail("Unexpected IndexOutOfBoundsException"); + } + } + } #if[short] static void assertArraysEquals(char[] a, char[] r, boolean[] mask) { diff --git a/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java b/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java index a32f81b7a97..71590040685 100644 --- a/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java +++ b/test/jdk/jdk/internal/jline/JLineConsoleProviderTest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8331535 8351435 + * @bug 8331535 8351435 8347050 * @summary Verify the jdk.internal.le's console provider works properly. * @modules jdk.internal.le * @library /test/lib @@ -38,6 +38,8 @@ public class JLineConsoleProviderTest { + private static final String NL = System.getProperty("line.separator"); + public static void main(String... args) throws Throwable { for (Method m : JLineConsoleProviderTest.class.getDeclaredMethods()) { if (m.getName().startsWith("test")) { @@ -54,6 +56,12 @@ void testCorrectOutputReadPassword() throws Exception { doRunConsoleTest("testCorrectOutputReadPassword", "inp", "%s"); } + void testEvenExpansionDisabled() throws Exception { + doRunConsoleTest("readAndPrint", "a\\b\n", "'a\\b'" + NL); + doRunConsoleTest("readAndPrint2", "a\n!!\n", "1: 'a'" + NL + + "2: '!!'" + NL); + } + void doRunConsoleTest(String testName, String input, String expectedOut) throws Exception { @@ -95,6 +103,12 @@ public static void main(String... args) { System.console().readLine("%%s"); case "testCorrectOutputReadPassword" -> System.console().readPassword("%%s"); + case "readAndPrint" -> + System.out.println("'" + System.console().readLine() + "'"); + case "readAndPrint2" -> { + System.out.println("1: '" +System.console().readLine() + "'"); + System.out.println("2: '" + System.console().readLine() + "'"); + } default -> throw new UnsupportedOperationException(args[0]); } diff --git a/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java b/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java index 42579a8eba9..acf0c848b43 100644 --- a/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java +++ b/test/jdk/jdk/internal/jline/LazyJdkConsoleProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 8333086 + * @bug 8333086 8344706 * @summary Verify the JLine backend is not initialized for simple printing. * @enablePreview * @modules jdk.internal.le/jdk.internal.org.jline.reader @@ -32,7 +32,6 @@ * @run main LazyJdkConsoleProvider */ -import java.io.IO; import jdk.internal.org.jline.reader.LineReader; import jdk.internal.org.jline.terminal.Terminal; @@ -44,8 +43,8 @@ public class LazyJdkConsoleProvider { public static void main(String... args) throws Throwable { switch (args.length > 0 ? args[0] : "default") { case "write" -> { - System.console().println("Hello!"); - System.console().print("Hello!"); + System.console().printf("Hello!\n"); + System.console().printf("Hello!"); System.console().format("\nHello!\n"); System.console().flush(); IO.println("Hello!"); @@ -66,7 +65,7 @@ record TestCase(String testKey, String expected, String notExpected) {} TestCase[] testCases = new TestCase[] { new TestCase("write", null, Terminal.class.getName()), new TestCase("read", LineReader.class.getName(), null), - new TestCase("IO-read", LineReader.class.getName(), null) + new TestCase("IO-read", null, Terminal.class.getName()) }; for (TestCase tc : testCases) { ProcessBuilder builder = diff --git a/test/jdk/jdk/internal/loader/NativeLibraries/Main.java b/test/jdk/jdk/internal/loader/NativeLibraries/Main.java index 4709810b0cd..5d96777a6f1 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, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 8240975 8281335 + * @library /test/lib * @modules java.base/jdk.internal.loader * @build java.base/* p.Test Main * @run main/othervm/native -Xcheck:jni Main @@ -31,6 +32,7 @@ */ import jdk.internal.loader.NativeLibrariesTest; +import jdk.test.lib.Platform; import java.io.IOException; import java.nio.file.Files; @@ -55,7 +57,9 @@ public static void main(String... args) throws Exception { test.unload(); // load zip library from JDK - test.load(System.mapLibraryName("zip"), true /* succeed */); + if (!Platform.isStatic()) { + test.load(System.mapLibraryName("zip"), true /* succeed */); + } // load non-existent library test.load(System.mapLibraryName("NotExist"), false /* fail to load */); diff --git a/test/jdk/jdk/internal/math/FloatingDecimal/TestRandomFloatingDecimal.java b/test/jdk/jdk/internal/math/FloatingDecimal/TestRandomFloatingDecimal.java index ff904474c2c..5d16cf4ec77 100644 --- a/test/jdk/jdk/internal/math/FloatingDecimal/TestRandomFloatingDecimal.java +++ b/test/jdk/jdk/internal/math/FloatingDecimal/TestRandomFloatingDecimal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,8 @@ /* * @test * @bug 8345403 - * @summary FloatingDecimal parsing methods (use -Dseed=X to set seed) + * @summary FloatingDecimal parsing methods (use -Dseed=X to set seed, + * use -Dsamples=N to set the number of random samples per test) * @modules java.base/jdk.internal.math * @library /test/lib * @build jdk.test.lib.RandomFactory @@ -34,6 +35,7 @@ import jdk.internal.math.FloatingDecimal; import jdk.test.lib.RandomFactory; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -55,24 +57,40 @@ public class TestRandomFloatingDecimal { * Hence, the expected values are those computed by BigDecimal, * while the actual values are those returned by FloatingDecimal. */ - private static final int COUNT = 10_000; // random samples per test + private static final Random RANDOM = RandomFactory.getRandom(); + private static int samples; // random samples per test static Stream testRandomDecForFloat() { - return Stream.generate(() -> randomDec(false)).limit(COUNT); + return Stream.generate(() -> randomDec(false)).limit(samples); } static Stream testRandomDecForDouble() { - return Stream.generate(() -> randomDec(true)).limit(COUNT); + return Stream.generate(() -> randomDec(true)).limit(samples); } static Stream testRandomHexForFloat() { - return Stream.generate(() -> randomHex(false)).limit(COUNT); + return Stream.generate(() -> randomHex(false)).limit(samples); } static Stream testRandomHexForDouble() { - return Stream.generate(() -> randomHex(true)).limit(COUNT); + return Stream.generate(() -> randomHex(true)).limit(samples); + } + + private static final String SAMPLES_PROP = "samples"; + + @BeforeAll + static void setCount() { + String prop = System.getProperty(SAMPLES_PROP, "10000"); // 10_000 + try { + samples = Integer.parseInt(prop); + if (samples <= 0) { + throw new NumberFormatException(); + } + } catch (NumberFormatException _) { + throw new IllegalArgumentException("-D" + SAMPLES_PROP + "=" + prop + " must specify a valid positive decimal integer."); + } } @ParameterizedTest diff --git a/test/jdk/jdk/internal/misc/TerminatingThreadLocal/TestTerminatingThreadLocal.java b/test/jdk/jdk/internal/misc/TerminatingThreadLocal/TestTerminatingThreadLocal.java index 00bddec6b56..cf46c5b1d22 100644 --- a/test/jdk/jdk/internal/misc/TerminatingThreadLocal/TestTerminatingThreadLocal.java +++ b/test/jdk/jdk/internal/misc/TerminatingThreadLocal/TestTerminatingThreadLocal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ import jdk.internal.misc.TerminatingThreadLocal; import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.List; @@ -31,6 +32,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Stream; @@ -41,7 +43,7 @@ /* * @test - * @bug 8202788 8291897 + * @bug 8202788 8291897 8357637 * @summary TerminatingThreadLocal unit test * @modules java.base/java.lang:+open java.base/jdk.internal.misc * @requires vm.continuations @@ -154,6 +156,53 @@ protected T initialValue() { assertEquals(terminatedValues, expectedTerminatedValues); } + /** + * Test TerminatingThreadLocal when thread locals are "cleared" by null'ing the + * threadLocal field of the current Thread. + */ + @Test + public void testClearingThreadLocals() throws Throwable { + var terminatedValues = new CopyOnWriteArrayList(); + + var tl = new ThreadLocal(); + var ttl = new TerminatingThreadLocal() { + @Override + protected void threadTerminated(String value) { + terminatedValues.add(value); + } + }; + var throwableRef = new AtomicReference(); + + String tlValue = "abc"; + String ttlValue = "xyz"; + + Thread thread = Thread.ofPlatform().start(() -> { + try { + tl.set(tlValue); + ttl.set(ttlValue); + + assertEquals(tl.get(), tlValue); + assertEquals(ttl.get(), ttlValue); + + // set Thread.threadLocals to null + Field f = Thread.class.getDeclaredField("threadLocals"); + f.setAccessible(true); + f.set(Thread.currentThread(), null); + + assertNull(tl.get()); + assertEquals(ttl.get(), ttlValue); + } catch (Throwable t) { + throwableRef.set(t); + } + }); + thread.join(); + if (throwableRef.get() instanceof Throwable t) { + throw t; + } + + assertEquals(terminatedValues, List.of(ttlValue)); + } + /** * Returns a builder to create virtual threads that use the given scheduler. */ diff --git a/test/jdk/jdk/internal/misc/ThreadFlock/ThreadFlockTest.java b/test/jdk/jdk/internal/misc/ThreadFlock/ThreadFlockTest.java index e6bc191a3ba..ebc718d2203 100644 --- a/test/jdk/jdk/internal/misc/ThreadFlock/ThreadFlockTest.java +++ b/test/jdk/jdk/internal/misc/ThreadFlock/ThreadFlockTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -750,51 +750,6 @@ void testWakeupAwaitAll2(ThreadFactory factory) throws Exception { } } - /** - * Test wakeup is flock confined. - */ - @ParameterizedTest - @MethodSource("factories") - void testWakeupConfined(ThreadFactory factory) throws Exception { - try (var flock = ThreadFlock.open(null)) { - // thread in flock - testWakeupConfined(flock, task -> { - Thread thread = factory.newThread(task); - return flock.start(thread); - }); - - // thread not in flock - testWakeupConfined(flock, task -> { - Thread thread = factory.newThread(task); - thread.start(); - return thread; - }); - } - } - - /** - * Test that a thread created with the given factory cannot wakeup the - * given flock. - */ - private void testWakeupConfined(ThreadFlock flock, - Function factory) throws Exception { - var exception = new AtomicReference(); - Thread thread = factory.apply(() -> { - try { - flock.wakeup(); - } catch (Exception e) { - exception.set(e); - } - }); - thread.join(); - Throwable cause = exception.get(); - if (flock.containsThread(thread)) { - assertNull(cause); - } else { - assertTrue(cause instanceof WrongThreadException); - } - } - /** * Test close with no threads running. */ @@ -933,59 +888,6 @@ void testInterruptClose2(ThreadFactory factory) { assertNull(exception.get()); } - /** - * Test shutdown is confined to threads in the flock. - */ - @ParameterizedTest - @MethodSource("factories") - void testShutdownConfined(ThreadFactory factory) throws Exception { - try (var flock = ThreadFlock.open(null)) { - // thread in flock - testShutdownConfined(flock, task -> { - Thread thread = factory.newThread(task); - return flock.start(thread); - }); - - // thread in flock - try (var flock2 = ThreadFlock.open(null)) { - testShutdownConfined(flock, task -> { - Thread thread = factory.newThread(task); - return flock2.start(thread); - }); - } - - // thread not contained in flock - testShutdownConfined(flock, task -> { - Thread thread = factory.newThread(task); - thread.start(); - return thread; - }); - } - } - - /** - * Test that a thread created with the given factory cannot shut down the - * given flock. - */ - private void testShutdownConfined(ThreadFlock flock, - Function factory) throws Exception { - var exception = new AtomicReference(); - Thread thread = factory.apply(() -> { - try { - flock.shutdown(); - } catch (Exception e) { - exception.set(e); - } - }); - thread.join(); - Throwable cause = exception.get(); - if (flock.containsThread(thread)) { - assertNull(cause); - } else { - assertTrue(cause instanceof WrongThreadException); - } - } - /** * Test that closing an enclosing thread flock closes a nested thread flocks. */ diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java index 2ac79c173ef..c6b94370807 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java @@ -22,11 +22,13 @@ */ import jdk.internal.platform.Metrics; +import jdk.test.lib.Container; import jdk.test.lib.Utils; import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerfileConfig; import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; +import jdk.test.lib.containers.docker.ContainerRuntimeVersionTestUtils; import java.util.ArrayList; @@ -49,6 +51,19 @@ public class TestDockerMemoryMetricsSubgroup { DockerfileConfig.getBaseImageName() + ":" + DockerfileConfig.getBaseImageVersion(); + static String getEngineInfo(String format) throws Exception { + return DockerTestUtils.execute(Container.ENGINE_COMMAND, "info", "-f", format) + .getStdout(); + } + + static boolean isRootless() throws Exception { + // Docker and Podman have different INFO structures. + // The node path for Podman is .Host.Security.Rootless, that also holds for + // Podman emulating Docker CLI. The node path for Docker is .SecurityOptions. + return (getEngineInfo("{{.Host.Security.Rootless}}").contains("true") || + getEngineInfo("{{.SecurityOptions}}").contains("name=rootless")); + } + public static void main(String[] args) throws Exception { Metrics metrics = Metrics.systemMetrics(); if (metrics == null) { @@ -59,6 +74,13 @@ public static void main(String[] args) throws Exception { System.out.println("Unable to run docker tests."); return; } + + ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); + + if (isRootless()) { + throw new SkippedException("Test skipped in rootless mode"); + } + if ("cgroupv1".equals(metrics.getProvider())) { testMemoryLimitSubgroupV1("200m", "400m", false); testMemoryLimitSubgroupV1("500m", "1G", false); diff --git a/test/jdk/jdk/jfr/api/metadata/annotations/TestOverrideWithDefaultValue.java b/test/jdk/jdk/jfr/api/metadata/annotations/TestOverrideWithDefaultValue.java new file mode 100644 index 00000000000..d0e6f007983 --- /dev/null +++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestOverrideWithDefaultValue.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.api.metadata.annotations; + +import java.io.IOException; +import java.util.List; + +import jdk.jfr.Enabled; +import jdk.jfr.Event; +import jdk.jfr.Recording; +import jdk.jfr.Registered; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Tests that annotations can be overridden with the default value. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.metadata.annotations.TestOverrideWithDefaultValue + */ +public class TestOverrideWithDefaultValue { + + @Enabled(false) + static class Mammal extends Event { + } + + @Enabled + static class Cat extends Mammal { + } + + @Registered(false) + static class Animal extends Event { + } + + @Registered + static class Dog extends Animal { + } + + public static void main(String[] args) throws IOException { + testEnabled(); + testRegistered(); + } + + private static void testEnabled() throws IOException { + try (Recording r = new Recording()) { + r.start(); + Cat cat = new Cat(); + cat.commit(); + List events = Events.fromRecording(r); + Events.hasEvents(events); + } + } + + private static void testRegistered() throws IOException { + try (Recording r = new Recording()) { + r.start(); + Dog dog = new Dog(); + dog.commit(); + List events = Events.fromRecording(r); + Events.hasEvents(events); + } + } +} diff --git a/test/jdk/jdk/jfr/api/metadata/annotations/TestThrottle.java b/test/jdk/jdk/jfr/api/metadata/annotations/TestThrottle.java new file mode 100644 index 00000000000..da3bd311abb --- /dev/null +++ b/test/jdk/jdk/jfr/api/metadata/annotations/TestThrottle.java @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.api.metadata.annotations; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Constructor; +import java.time.Duration; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +import jdk.jfr.AnnotationElement; +import jdk.jfr.Event; +import jdk.jfr.EventType; +import jdk.jfr.MetadataDefinition; +import jdk.jfr.Name; +import jdk.jfr.Threshold; +import jdk.jfr.Enabled; +import jdk.jfr.Recording; +import jdk.jfr.SettingDefinition; +import jdk.jfr.SettingDescriptor; +import jdk.jfr.Throttle; +import jdk.jfr.ValueDescriptor; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingStream; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.Events; +import jdk.jfr.SettingControl; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.metadata.annotations.TestThrottle + */ +public class TestThrottle { + + @Throttle("off") + @Enabled(false) + public static class ThrottledDisabledEvent extends Event { + } + + @Throttle("off") + public static class ThrottledOffEvent extends Event { + } + + @Throttle("0/s") + public static class ThrottledZeroRateEvent extends Event { + } + + @Throttle("10000000/s") + public static class ThrottledHighRateEvent extends Event { + } + + @Throttle("off") + @Threshold("5 h") + public static class ThrottledThresholdedEvent extends Event { + } + + @Throttle("50/s") + public static class ThrottledNormalRateEvent extends Event { + public int index; + } + + static class TestSetting extends SettingControl { + private boolean value; + + @Override + public String combine(Set values) { + if (values.contains("true")) { + return "true"; + } + if (values.contains("false")) { + return "false"; + } + return "true"; + } + + @Override + public void setValue(String text) { + value = Boolean.parseBoolean(text); + } + + @Override + public String getValue() { + return "" + value; + } + } + + @Throttle("10000000/s") + public static class ThrottledUserdefinedEvent extends Event { + @SettingDefinition + public boolean test(TestSetting control) { + return control.value; + } + } + + @Throttle("50/s") + public static class ThrottledReuseEvent extends Event { + public int index; + } + + public static void main(String[] args) throws Exception { + testThrottleDisabled(); + testThrottledOff(); + testThottleZeroRate(); + testThrottleHighRate(); + testThrottleThresholded(); + testThrottleNormalRate(); + testThrottleUserdefined(); + } + + private static void testThrottleDisabled() throws Exception { + testEvent(ThrottledDisabledEvent.class, false); + } + + private static void testThrottledOff() throws Exception { + testEvent(ThrottledOffEvent.class, true); + } + + private static void testThottleZeroRate() throws Exception { + testEvent(ThrottledZeroRateEvent.class, false); + } + + private static void testThrottleHighRate() throws Exception { + testEvent(ThrottledHighRateEvent.class, true); + } + + private static void testThrottleThresholded() throws Exception { + testEvent(ThrottledThresholdedEvent.class, false); + } + + private static void testThrottleNormalRate() throws Exception { + try (RecordingStream rs = new RecordingStream()) { + AtomicInteger lastIndex = new AtomicInteger(); + AtomicInteger throttled = new AtomicInteger(); + rs.onEvent(ThrottledNormalRateEvent.class.getName(), e -> { + int index = e.getInt("index"); + if (lastIndex.get() + 1 != index) { + throttled.incrementAndGet(); + } + lastIndex.set(index); + }); + rs.startAsync(); + int index = 1; + while (throttled.get() < 30) { + ThrottledNormalRateEvent e = new ThrottledNormalRateEvent(); + e.index = index; + e.commit(); + index++; + Thread.sleep(3); + } + } + } + + private static void testThrottleUserdefined() throws Exception { + testThrottleUserdefined("false", "1000000/s", false); + testThrottleUserdefined("true", "10000000/s", true); + testThrottleUserdefined("true", "0/s", false); + testThrottleUserdefined("true", "off", true); + testThrottleUserdefined("false", "off", false); + } + + private static void testThrottleUserdefined(String test, String throttle, boolean emit) throws Exception { + String eventName = ThrottledUserdefinedEvent.class.getName(); + try (Recording r = new Recording()) { + r.enable(eventName).with("test", test).with("throttle", throttle); + r.start(); + + ThrottledUserdefinedEvent e1 = new ThrottledUserdefinedEvent(); + e1.commit(); + + ThrottledUserdefinedEvent e2 = new ThrottledUserdefinedEvent(); + e2.begin(); + e2.commit(); + + ThrottledUserdefinedEvent e3 = new ThrottledUserdefinedEvent(); + e3.begin(); + e3.end(); + e3.commit(); + + ThrottledUserdefinedEvent e4 = new ThrottledUserdefinedEvent(); + if (e4.shouldCommit()) { + e4.commit(); + } + assertShouldCommit(e4, emit); + + ThrottledUserdefinedEvent e5 = new ThrottledUserdefinedEvent(); + assertShouldCommit(e5, emit); + if (e5.shouldCommit()) { + e5.commit(); + } + + r.stop(); + assertEvents(r, eventName, emit ? 5 : 0); + } + } + + @SuppressWarnings("unchecked") + private static void testEvent(Class eventClass, boolean shouldCommit) throws Exception { + try (Recording r = new Recording()) { + r.start(); + Constructor c = (Constructor) eventClass.getConstructor(); + for (int i = 0; i < 17; i++) { + Event e = c.newInstance(); + if (i % 5 == 0) { + assertShouldCommit(e, shouldCommit); + } + e.commit(); + if (i % 3 == 0) { + assertShouldCommit(e, shouldCommit); + } + } + for (int i = 0; i < 50; i++) { + Event e = c.newInstance(); + e.begin(); + if (i % 5 == 0) { + assertShouldCommit(e, shouldCommit); + } + e.end(); + if (i % 3 == 0) { + assertShouldCommit(e, shouldCommit); + } + e.commit(); + if (i % 7 == 0) { + assertShouldCommit(e, shouldCommit); + } + } + for (int i = 0; i < 11; i++) { + Event e = c.newInstance(); + e.begin(); + e.commit(); + if (i % 7 == 0) { + assertShouldCommit(e, shouldCommit); + } + } + if (shouldCommit) { + assertEvents(r, eventClass.getName(), 17 + 50 + 11); + } + } + } + + private static void assertEvents(Recording r, String name, int expected) throws Exception { + int count = 0; + for (RecordedEvent event : Events.fromRecording(r)) { + if (event.getEventType().getName().equals(name)) { + count++; + } + } + if (count != expected) { + throw new Exception("Expected " + expected + " " + name + " events, but found " + count); + } + } + + private static void assertShouldCommit(Event e, boolean expected) throws Exception { + if (e.shouldCommit() != expected) { + throw new Exception("Expected " + e.getClass() + "::shouldCommit() to return " + expected); + } + } +} diff --git a/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java b/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java index dc22644b4d0..7c6e6fa276b 100644 --- a/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java +++ b/test/jdk/jdk/jfr/api/recording/settings/TestSettingsAvailability.java @@ -66,7 +66,7 @@ private static void testSettingPersistence() throws IOException, Exception { for (EventType parsedType : rf.readEventTypes()) { EventType inMem = inMemoryTypes.get(parsedType.getName()); if (inMem == null) { - throw new Exception("Superflous event type " + parsedType.getName() + " in recording"); + throw new Exception("Superfluous event type " + parsedType.getName() + " in recording"); } Set inMemsettings = new HashSet<>(); for (SettingDescriptor sd : inMem.getSettingDescriptors()) { @@ -75,7 +75,7 @@ private static void testSettingPersistence() throws IOException, Exception { for (SettingDescriptor parsedSetting : parsedType.getSettingDescriptors()) { if (!inMemsettings.contains(parsedSetting.getName())) { - throw new Exception("Superflous setting " + parsedSetting.getName() + " in " + parsedType.getName()); + throw new Exception("Superfluous setting " + parsedSetting.getName() + " in " + parsedType.getName()); } inMemsettings.remove(parsedSetting.getName()); } @@ -89,14 +89,14 @@ private static void testSettingPersistence() throws IOException, Exception { private static void testKnownSettings() throws Exception { testSetting(EventNames.JVMInformation, "enabled", "period"); - testSetting(EventNames.FileRead, "enabled", "threshold", "stackTrace"); - testSetting(EventNames.FileWrite, "enabled", "threshold","stackTrace"); + testSetting(EventNames.FileRead, "enabled", "threshold", "stackTrace", "throttle"); + testSetting(EventNames.FileWrite, "enabled", "threshold", "stackTrace", "throttle"); testSetting(EventNames.ExceptionStatistics, "enabled", "period"); - testSetting(EventNames.SocketRead, "enabled", "threshold", "stackTrace"); - testSetting(EventNames.SocketWrite, "enabled", "threshold", "stackTrace"); + testSetting(EventNames.SocketRead, "enabled", "threshold", "stackTrace", "throttle"); + testSetting(EventNames.SocketWrite, "enabled", "threshold", "stackTrace", "throttle"); testSetting(EventNames.ActiveRecording, "enabled"); testSetting(EventNames.ActiveSetting, "enabled"); - testSetting(EventNames.JavaExceptionThrow, "enabled", "stackTrace"); + testSetting(EventNames.JavaExceptionThrow, "enabled", "stackTrace", "throttle"); } private static void testSetting(String eventName, String... settingNames) throws Exception { diff --git a/test/jdk/jdk/jfr/api/settings/TestSettingControl.java b/test/jdk/jdk/jfr/api/settings/TestSettingControl.java index ef38626eedb..e1c9ff1ea47 100644 --- a/test/jdk/jdk/jfr/api/settings/TestSettingControl.java +++ b/test/jdk/jdk/jfr/api/settings/TestSettingControl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,8 @@ public String eventSettingName() { new SettingTest("level", "forRemoval", "jdk.DeprecatedInvocation", List.of("off", "forRemoval")), new SettingTest("period", "everyChunk", "jdk.ExceptionStatistics", List.of("everyChunk", "60 s", "1 s")), new SettingTest("cutoff", "infinity", "jdk.OldObjectSample", List.of("0 ms", "1 s", "infinity")), - new SettingTest("throttle", "off", "jdk.ObjectAllocationSample", List.of("off", "100/s", "10/ms")) + new SettingTest("throttle", "off", "jdk.ObjectAllocationSample", List.of("off", "100/s", "10/ms")), + new SettingTest("filter", "", "jdk.MethodTrace", List.of("", "foo.bar::Baz", "com.example.Test;foo.bar::Baz")) ); public static void main(String... args) throws Exception { diff --git a/test/jdk/jdk/jfr/event/metadata/TestLookForUntestedEvents.java b/test/jdk/jdk/jfr/event/metadata/TestLookForUntestedEvents.java index 5b8aacfb1d2..d6e126a493f 100644 --- a/test/jdk/jdk/jfr/event/metadata/TestLookForUntestedEvents.java +++ b/test/jdk/jdk/jfr/event/metadata/TestLookForUntestedEvents.java @@ -89,7 +89,10 @@ public class TestLookForUntestedEvents { // Experimental events private static final Set experimentalEvents = Set.of( - "Flush", "SyncOnValueBasedClass"); + "Flush", "SyncOnValueBasedClass", "CPUTimeSample", "CPUTimeSamplesLost"); + + // Subset of the experimental events that should have tests + private static final Set experimentalButTestedEvents = Set.of("CPUTimeSample"); public static void main(String[] args) throws Exception { for (EventType type : FlightRecorder.getFlightRecorder().getEventTypes()) { @@ -110,7 +113,9 @@ private static void lookForEventsNotCoveredByTests() throws Exception { .collect(Collectors.toList()); Set eventsNotCoveredByTest = new HashSet<>(jfrEventTypes); - for (String event : jfrEventTypes) { + Set checkedEvents = new HashSet<>(jfrEventTypes); + checkedEvents.addAll(experimentalButTestedEvents); + for (String event : checkedEvents) { for (Path p : paths) { if (findStringInFile(p, event)) { eventsNotCoveredByTest.remove(event); diff --git a/test/jdk/jdk/jfr/event/os/TestProcessStart.java b/test/jdk/jdk/jfr/event/os/TestProcessStart.java index 2d1d80f5941..caca8bd443e 100644 --- a/test/jdk/jdk/jfr/event/os/TestProcessStart.java +++ b/test/jdk/jdk/jfr/event/os/TestProcessStart.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,11 +51,12 @@ public static void main(String[] args) throws Throwable { recording.start(); List commandList = new ArrayList<>(); if (Platform.isWindows()) { + commandList.add("help"); commandList.add("dir"); } else { commandList.add("ls"); + commandList.add("*.jfr"); } - commandList.add("*.jfr"); ProcessBuilder pb = new ProcessBuilder(commandList); pb.directory(new File(".").getAbsoluteFile()); Process p = pb.start(); diff --git a/test/jdk/jdk/jfr/event/profiling/BaseTestFullStackTrace.java b/test/jdk/jdk/jfr/event/profiling/BaseTestFullStackTrace.java new file mode 100644 index 00000000000..de211b8c454 --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/BaseTestFullStackTrace.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.profiling; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; +import jdk.jfr.consumer.RecordedStackTrace; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; +import jdk.test.lib.jfr.RecurseThread; + +public class BaseTestFullStackTrace { + private final static int MAX_DEPTH = 64; // currently hardcoded in jvm + + private final String eventName; + private final String threadFieldName; + + public BaseTestFullStackTrace(String eventName, String threadFieldName) { + this.eventName = eventName; + this.threadFieldName = threadFieldName; + } + + public void run() throws Throwable { + RecurseThread[] threads = new RecurseThread[3]; + for (int i = 0; i < threads.length; ++i) { + int depth = MAX_DEPTH - 1 + i; + threads[i] = new RecurseThread(depth); + threads[i].setName("recursethread-" + depth); + threads[i].start(); + } + + for (RecurseThread thread : threads) { + while (!thread.isInRunLoop()) { + Thread.sleep(20); + } + } + + assertStackTraces(threads); + + for (RecurseThread thread : threads) { + thread.quit(); + thread.join(); + } + } + + private void assertStackTraces(RecurseThread[] threads) throws Throwable { + while (true) { + try (Recording recording = new Recording()) { + if (eventName.equals(EventNames.CPUTimeSample)) { + recording.enable(eventName).with("throttle", "50ms"); + } else { + recording.enable(eventName).withPeriod(Duration.ofMillis(50)); + } + recording.start(); + Thread.sleep(500); + recording.stop(); + if (hasValidStackTraces(recording, threads)) { + break; + } + } + }; + } + + private boolean hasValidStackTraces(Recording recording, RecurseThread[] threads) throws Throwable { + boolean[] isEventFound = new boolean[threads.length]; + + for (RecordedEvent event : Events.fromRecording(recording)) { + System.out.println("Event: " + event); + String threadName = Events.assertField(event, threadFieldName + ".javaName").getValue(); + long threadId = Events.assertField(event, threadFieldName + ".javaThreadId").getValue(); + + for (int threadIndex = 0; threadIndex < threads.length; ++threadIndex) { + RecurseThread currThread = threads[threadIndex]; + if (threadId == currThread.getId()) { + System.out.println("ThreadName=" + currThread.getName() + ", depth=" + currThread.totalDepth); + Asserts.assertEquals(threadName, currThread.getName(), "Wrong thread name"); + if ("recurseEnd".equals(getTopMethodName(event))) { + isEventFound[threadIndex] = true; + checkEvent(event, currThread.totalDepth); + break; + } + } + } + } + + for (int i = 0; i < threads.length; ++i) { + String msg = "threadIndex=%d, recurseDepth=%d, isEventFound=%b%n"; + System.out.printf(msg, i, threads[i].totalDepth, isEventFound[i]); + } + for (int i = 0; i < threads.length; ++i) { + if(!isEventFound[i]) { + // no assertion, let's retry. + // Could be race condition, i.e safe point during Thread.sleep + System.out.println("Failed to validate all threads, will retry."); + return false; + } + } + return true; + } + + public String getTopMethodName(RecordedEvent event) { + List frames = event.getStackTrace().getFrames(); + Asserts.assertFalse(frames.isEmpty(), "JavaFrames was empty"); + return frames.getFirst().getMethod().getName(); + } + + private void checkEvent(RecordedEvent event, int expectedDepth) throws Throwable { + RecordedStackTrace stacktrace = null; + try { + stacktrace = event.getStackTrace(); + List frames = stacktrace.getFrames(); + Asserts.assertEquals(Math.min(MAX_DEPTH, expectedDepth), frames.size(), "Wrong stacktrace depth. Expected:" + expectedDepth); + List expectedMethods = getExpectedMethods(expectedDepth); + Asserts.assertEquals(expectedMethods.size(), frames.size(), "Wrong expectedMethods depth. Test error."); + + for (int i = 0; i < frames.size(); ++i) { + String name = frames.get(i).getMethod().getName(); + String expectedName = expectedMethods.get(i); + System.out.printf("method[%d]=%s, expected=%s%n", i, name, expectedName); + Asserts.assertEquals(name, expectedName, "Wrong method name"); + } + + boolean isTruncated = stacktrace.isTruncated(); + boolean isTruncateExpected = expectedDepth > MAX_DEPTH; + Asserts.assertEquals(isTruncated, isTruncateExpected, "Wrong value for isTruncated. Expected:" + isTruncateExpected); + + String firstMethod = frames.getLast().getMethod().getName(); + boolean isFullTrace = "run".equals(firstMethod); + String msg = String.format("Wrong values for isTruncated=%b, isFullTrace=%b", isTruncated, isFullTrace); + Asserts.assertTrue(isTruncated != isFullTrace, msg); + } catch (Throwable t) { + System.out.println(String.format("stacktrace:%n%s", stacktrace)); + throw t; + } + } + + private List getExpectedMethods(int depth) { + List methods = new ArrayList<>(); + methods.add("recurseEnd"); + for (int i = 0; i < depth - 2; ++i) { + methods.add((i % 2) == 0 ? "recurseA" : "recurseB"); + } + methods.add("run"); + if (depth > MAX_DEPTH) { + methods = methods.subList(0, MAX_DEPTH); + } + return methods; + } +} diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeAndExecutionSample.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeAndExecutionSample.java new file mode 100644 index 00000000000..eb8d33832b5 --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeAndExecutionSample.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.profiling; + +import java.time.Duration; + +import jdk.jfr.consumer.RecordingStream; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.RecurseThread; + +/* + * @test + * @requires vm.hasJFR & os.family == "linux" + * @library /test/lib + * @modules jdk.jfr/jdk.jfr.internal + * @run main/timeout=30 jdk.jfr.event.profiling.TestCPUTimeAndExecutionSample + */ +public class TestCPUTimeAndExecutionSample { + + static String sampleEvent = EventNames.CPUTimeSample; + + // The period is set to 1100 ms to provoke the 1000 ms + // threshold in the JVM for os::naked_short_sleep(). + public static void main(String[] args) throws Exception { + run(EventNames.ExecutionSample); + run(EventNames.CPUTimeSample); + run(EventNames.ExecutionSample); + run(EventNames.CPUTimeSample); + } + + private static void run(String eventType) { + RecurseThread t = new RecurseThread(50); + t.setDaemon(true); + try (RecordingStream rs = new RecordingStream()) { + rs.enable(sampleEvent).with("throttle", "1000/s"); + rs.onEvent(sampleEvent, e -> { + t.quit(); + rs.close(); + }); + t.start(); + rs.start(); + } + } +} diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleFullStackTrace.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleFullStackTrace.java new file mode 100644 index 00000000000..0d1108346ab --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleFullStackTrace.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.profiling; + +import jdk.test.lib.jfr.EventNames; + +/** + * @test + * @requires vm.hasJFR & os.family == "linux" + * @library /test/lib + * @build jdk.jfr.event.profiling.BaseTestFullStackTrace + * @run main/othervm jdk.jfr.event.profiling.TestCPUTimeSampleFullStackTrace + */ +public class TestCPUTimeSampleFullStackTrace { + + public static void main(String[] args) throws Throwable { + new BaseTestFullStackTrace(EventNames.CPUTimeSample, "eventThread").run(); + } + +} diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java new file mode 100644 index 00000000000..133df36684c --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleMultipleRecordings.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.profiling; + +import java.time.Duration; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingStream; +import jdk.jfr.internal.JVM; +import jdk.test.lib.jfr.EventNames; + +/* + * Tests that creating multiple recordings after another is possible. + * @test + * @requires vm.hasJFR & os.family == "linux" + * @library /test/lib + * @modules jdk.jfr/jdk.jfr.internal + * @run main jdk.jfr.event.profiling.TestCPUTimeSampleMultipleRecordings + */ +public class TestCPUTimeSampleMultipleRecordings { + + static String nativeEvent = EventNames.CPUTimeSample; + + static volatile boolean alive = true; + + public static void main(String[] args) throws Exception { + Thread t = new Thread(TestCPUTimeSampleMultipleRecordings::nativeMethod); + t.setDaemon(true); + t.start(); + for (int i = 0; i < 2; i++) { + try (RecordingStream rs = new RecordingStream()) { + rs.enable(nativeEvent).with("throttle", "1ms"); + rs.onEvent(nativeEvent, e -> { + alive = false; + rs.close(); + }); + + rs.start(); + } + } + alive = false; + } + + public static void nativeMethod() { + while (alive) { + JVM.getPid(); + } + } +} diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleNative.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleNative.java new file mode 100644 index 00000000000..1617bce4ba3 --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleNative.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.profiling; + +import java.time.Duration; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingStream; +import jdk.jfr.internal.JVM; +import jdk.test.lib.jfr.EventNames; + +/* + * @test + * @requires vm.hasJFR & os.family == "linux" + * @library /test/lib + * @modules jdk.jfr/jdk.jfr.internal + * @run main jdk.jfr.event.profiling.TestCPUTimeSampleNative + */ +public class TestCPUTimeSampleNative { + + static String nativeEvent = EventNames.CPUTimeSample; + + static volatile boolean alive = true; + + public static void main(String[] args) throws Exception { + try (RecordingStream rs = new RecordingStream()) { + rs.enable(nativeEvent).with("throttle", "1ms"); + rs.onEvent(nativeEvent, e -> { + alive = false; + rs.close(); + }); + Thread t = new Thread(TestCPUTimeSampleNative::nativeMethod); + t.setDaemon(true); + t.start(); + rs.start(); + } + + } + + public static void nativeMethod() { + while (alive) { + JVM.getPid(); + } + } +} diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleThrottling.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleThrottling.java new file mode 100644 index 00000000000..55b350ad096 --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSampleThrottling.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.profiling; +import java.lang.management.ManagementFactory; +import java.time.Duration; +import java.time.Instant; +import java.util.List; +import java.util.Comparator; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @requires vm.hasJFR & os.family == "linux" + * @library /test/lib + * @run main/othervm jdk.jfr.event.profiling.TestCPUTimeSampleThrottling + */ +public class TestCPUTimeSampleThrottling { + + public static void main(String[] args) throws Exception { + testZeroPerSecond(); + testThrottleSettings(); + testThrottleSettingsPeriod(); + } + + private static void testZeroPerSecond() throws Exception { + Asserts.assertTrue(0L == countEvents(1000, "0/s").count()); + } + + private static void testThrottleSettings() throws Exception { + long count = countEvents(1000, + Runtime.getRuntime().availableProcessors() * 2 + "/s").count(); + Asserts.assertTrue(count > 0 && count < 3, + "Expected between 0 and 3 events, got " + count); + } + + private static void testThrottleSettingsPeriod() throws Exception { + float rate = countEvents(1000, "10ms").rate(); + Asserts.assertTrue(rate > 90 && rate < 110, "Expected around 100 events per second, got " + rate); + } + + private record EventCount(long count, float time) { + float rate() { + return count / time; + } + } + + private static EventCount countEvents(int timeMs, String rate) throws Exception { + try(Recording recording = new Recording()) { + recording.enable(EventNames.CPUTimeSample) + .with("throttle", rate); + + var bean = ManagementFactory.getThreadMXBean(); + + recording.start(); + + long startThreadCpuTime = bean.getCurrentThreadCpuTime(); + + wasteCPU(timeMs); + + long spendCPUTime = bean.getCurrentThreadCpuTime() - startThreadCpuTime; + + recording.stop(); + + long eventCount = Events.fromRecording(recording).stream() + .filter(e -> e.getThread().getJavaName() + .equals(Thread.currentThread().getName())) + .count(); + + System.out.println("Event count: " + eventCount + ", CPU time: " + spendCPUTime / 1_000_000_000f + "s"); + + return new EventCount(eventCount, spendCPUTime / 1_000_000_000f); + } + } + + private static void wasteCPU(int durationMs) { + long start = System.currentTimeMillis(); + double i = 0; + while (System.currentTimeMillis() - start < durationMs) { + for (int j = 0; j < 100000; j++) { + i = Math.sqrt(i * Math.pow(Math.sqrt(Math.random()), Math.random())); + } + } + } + +} diff --git a/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSamplingLongPeriod.java b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSamplingLongPeriod.java new file mode 100644 index 00000000000..69d32d48282 --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/TestCPUTimeSamplingLongPeriod.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.profiling; + +import java.time.Duration; + +import jdk.jfr.consumer.RecordingStream; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.RecurseThread; + +/* + * @test + * @requires vm.hasJFR & os.family == "linux" + * @library /test/lib + * @modules jdk.jfr/jdk.jfr.internal + * @run main jdk.jfr.event.profiling.TestCPUTimeSamplingLongPeriod + */ +public class TestCPUTimeSamplingLongPeriod { + + static String sampleEvent = EventNames.CPUTimeSample; + + // The period is set to 1100 ms to provoke the 1000 ms + // threshold in the JVM for os::naked_short_sleep(). + public static void main(String[] args) throws Exception { + RecurseThread t = new RecurseThread(50); + t.setDaemon(true); + try (RecordingStream rs = new RecordingStream()) { + rs.enable(sampleEvent).with("throttle", "1100ms"); + rs.onEvent(sampleEvent, e -> { + t.quit(); + rs.close(); + }); + t.start(); + rs.start(); + } + } +} diff --git a/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java b/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java index b06f9eed03d..c337a8128ab 100644 --- a/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java +++ b/test/jdk/jdk/jfr/event/profiling/TestFullStackTrace.java @@ -23,147 +23,20 @@ package jdk.jfr.event.profiling; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; - -import jdk.jfr.Recording; -import jdk.jfr.consumer.RecordedEvent; -import jdk.jfr.consumer.RecordedFrame; -import jdk.jfr.consumer.RecordedStackTrace; -import jdk.test.lib.Asserts; import jdk.test.lib.jfr.EventNames; -import jdk.test.lib.jfr.Events; -import jdk.test.lib.jfr.RecurseThread; /** * @test * @requires vm.hasJFR * @requires vm.opt.DeoptimizeALot != true * @library /test/lib + * @build jdk.jfr.event.profiling.BaseTestFullStackTrace * @run main/othervm jdk.jfr.event.profiling.TestFullStackTrace */ public class TestFullStackTrace { - private final static String EVENT_NAME = EventNames.ExecutionSample; - private final static int MAX_DEPTH = 64; // currently hardcoded in jvm public static void main(String[] args) throws Throwable { - RecurseThread[] threads = new RecurseThread[3]; - for (int i = 0; i < threads.length; ++i) { - int depth = MAX_DEPTH - 1 + i; - threads[i] = new RecurseThread(depth); - threads[i].setName("recursethread-" + depth); - threads[i].start(); - } - - for (RecurseThread thread : threads) { - while (!thread.isInRunLoop()) { - Thread.sleep(20); - } - } - - assertStackTraces(threads); - - for (RecurseThread thread : threads) { - thread.quit(); - thread.join(); - } - } - - private static void assertStackTraces( RecurseThread[] threads) throws Throwable { - Recording recording= null; - do { - recording = new Recording(); - recording.enable(EVENT_NAME).withPeriod(Duration.ofMillis(50)); - recording.start(); - Thread.sleep(500); - recording.stop(); - } while (!hasValidStackTraces(recording, threads)); + new BaseTestFullStackTrace(EventNames.ExecutionSample, "sampledThread").run(); } - private static boolean hasValidStackTraces(Recording recording, RecurseThread[] threads) throws Throwable { - boolean[] isEventFound = new boolean[threads.length]; - - for (RecordedEvent event : Events.fromRecording(recording)) { - //System.out.println("Event: " + event); - String threadName = Events.assertField(event, "sampledThread.javaName").getValue(); - long threadId = Events.assertField(event, "sampledThread.javaThreadId").getValue(); - - for (int threadIndex = 0; threadIndex < threads.length; ++threadIndex) { - RecurseThread currThread = threads[threadIndex]; - if (threadId == currThread.getId()) { - System.out.println("ThreadName=" + currThread.getName() + ", depth=" + currThread.totalDepth); - Asserts.assertEquals(threadName, currThread.getName(), "Wrong thread name"); - if ("recurseEnd".equals(getTopMethodName(event))) { - isEventFound[threadIndex] = true; - checkEvent(event, currThread.totalDepth); - break; - } - } - } - } - - for (int i = 0; i < threads.length; ++i) { - String msg = "threadIndex=%d, recurseDepth=%d, isEventFound=%b%n"; - System.out.printf(msg, i, threads[i].totalDepth, isEventFound[i]); - } - for (int i = 0; i < threads.length; ++i) { - if(!isEventFound[i]) { - // no assertion, let's retry. - // Could be race condition, i.e safe point during Thread.sleep - System.out.println("Failed to validate all threads, will retry."); - return false; - } - } - return true; - } - - public static String getTopMethodName(RecordedEvent event) { - List frames = event.getStackTrace().getFrames(); - Asserts.assertFalse(frames.isEmpty(), "JavaFrames was empty"); - return frames.getFirst().getMethod().getName(); - } - - private static void checkEvent(RecordedEvent event, int expectedDepth) throws Throwable { - RecordedStackTrace stacktrace = null; - try { - stacktrace = event.getStackTrace(); - List frames = stacktrace.getFrames(); - Asserts.assertEquals(Math.min(MAX_DEPTH, expectedDepth), frames.size(), "Wrong stacktrace depth. Expected:" + expectedDepth); - List expectedMethods = getExpectedMethods(expectedDepth); - Asserts.assertEquals(expectedMethods.size(), frames.size(), "Wrong expectedMethods depth. Test error."); - - for (int i = 0; i < frames.size(); ++i) { - String name = frames.get(i).getMethod().getName(); - String expectedName = expectedMethods.get(i); - System.out.printf("method[%d]=%s, expected=%s%n", i, name, expectedName); - Asserts.assertEquals(name, expectedName, "Wrong method name"); - } - - boolean isTruncated = stacktrace.isTruncated(); - boolean isTruncateExpected = expectedDepth > MAX_DEPTH; - Asserts.assertEquals(isTruncated, isTruncateExpected, "Wrong value for isTruncated. Expected:" + isTruncateExpected); - - String firstMethod = frames.getLast().getMethod().getName(); - boolean isFullTrace = "run".equals(firstMethod); - String msg = String.format("Wrong values for isTruncated=%b, isFullTrace=%b", isTruncated, isFullTrace); - Asserts.assertTrue(isTruncated != isFullTrace, msg); - } catch (Throwable t) { - System.out.println(String.format("stacktrace:%n%s", stacktrace)); - throw t; - } - } - - private static List getExpectedMethods(int depth) { - List methods = new ArrayList<>(); - methods.add("recurseEnd"); - for (int i = 0; i < depth - 2; ++i) { - methods.add((i % 2) == 0 ? "recurseA" : "recurseB"); - } - methods.add("run"); - if (depth > MAX_DEPTH) { - methods = methods.subList(0, MAX_DEPTH); - } - return methods; - } } diff --git a/test/jdk/jdk/jfr/event/profiling/TestSafepointLatency.java b/test/jdk/jdk/jfr/event/profiling/TestSafepointLatency.java new file mode 100644 index 00000000000..d9fbc16d4e9 --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/TestSafepointLatency.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.event.profiling; + +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.Random; + +import jdk.jfr.consumer.RecordingStream; +import jdk.test.lib.jfr.EventNames; + +/* + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @modules jdk.jfr/jdk.jfr.internal + * @run main jdk.jfr.event.profiling.TestSafepointLatency + */ +public class TestSafepointLatency { + // The SafepointLatency event is parasitic on the ExecutionSample mechanism. + final static String EXECUTION_SAMPLE_EVENT = EventNames.ExecutionSample; + final static String SAFEPOINT_LATENCY_EVENT = EventNames.SafepointLatency; + final static CountDownLatch latch = new CountDownLatch(10); + final static Random random = new Random(); + public static int publicizedValue = 4711; + + public static void main(String[] args) throws Exception { + try (RecordingStream rs = new RecordingStream()) { + rs.enable(EXECUTION_SAMPLE_EVENT).withPeriod(Duration.ofMillis(1)); + rs.enable(SAFEPOINT_LATENCY_EVENT); + rs.onEvent(SAFEPOINT_LATENCY_EVENT, e -> latch.countDown()); + rs.startAsync(); + Thread t = new Thread(TestSafepointLatency::callMethods); + t.setDaemon(true); + t.start(); + latch.await(); + } + } + + public static void callMethods() { + while (latch.getCount() > 0) { + publicizedValue += bar(publicizedValue); + } + } + + private static int bar(int value) { + return baz(value); + } + + private static int baz(int value) { + return qux(value); + } + + private static int qux(int value) { + return (value << 4) * random.nextInt(); + } +} diff --git a/test/jdk/jdk/jfr/event/profiling/classes/test/RecursiveMethods.java b/test/jdk/jdk/jfr/event/profiling/classes/test/RecursiveMethods.java new file mode 100644 index 00000000000..8dc77fd38da --- /dev/null +++ b/test/jdk/jdk/jfr/event/profiling/classes/test/RecursiveMethods.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + package test; + + import java.time.Duration; + + /* + * A class used to create a simple deep call stack for testing purposes + */ + public class RecursiveMethods { + + /** Method that uses recursion to produce a call stack of at least {@code depth} depth */ + public static int entry(int depth) { + return method2(--depth); + } + + private static int method2(int depth) { + return method3(--depth); + } + + private static int method3(int depth) { + return method4(--depth); + } + + private static int method4(int depth) { + return method5(--depth); + } + + private static int method5(int depth) { + return method6(--depth); + } + + private static int method6(int depth) { + return method7(--depth); + } + + private static int method7(int depth) { + return method8(--depth); + } + + private static int method8(int depth) { + return method9(--depth); + } + + private static int method9(int depth) { + return method10(--depth); + } + + private static int method10(int depth) { + if (depth > 0) { + return entry(--depth); + } + return depth; + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/Apple.java b/test/jdk/jdk/jfr/event/tracing/Apple.java new file mode 100644 index 00000000000..b88f3933947 --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/Apple.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ TYPE, METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Apple { +} diff --git a/test/jdk/jdk/jfr/event/tracing/Banana.java b/test/jdk/jdk/jfr/event/tracing/Banana.java new file mode 100644 index 00000000000..072e6a5955f --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/Banana.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ TYPE, METHOD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface Banana { +} diff --git a/test/jdk/jdk/jfr/event/tracing/Car.java b/test/jdk/jdk/jfr/event/tracing/Car.java new file mode 100644 index 00000000000..2f3f5a5802a --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/Car.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +public final class Car implements Runnable { + + public void run() { + System.out.println("Car is running. Class loader name " + this.getClass().getClassLoader().getName()); + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/StaticInitializer.java b/test/jdk/jdk/jfr/event/tracing/StaticInitializer.java new file mode 100644 index 00000000000..15485660bf4 --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/StaticInitializer.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +public final class StaticInitializer { + public static String TRIGGERED; + static { + System.out.println("Executing StaticInitializer::"); + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestClinit.java b/test/jdk/jdk/jfr/event/tracing/TestClinit.java new file mode 100644 index 00000000000..f2356fb8d9f --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestClinit.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.util.List; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Tests that can be instrumented. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @build jdk.jfr.event.tracing.StaticInitializer + * @run main/othervm -Xlog:jfr+methodtrace=trace + * jdk.jfr.event.tracing.TestClinit + **/ +public class TestClinit { + private static final String PACKAGE_NAME = TestClinit.class.getPackageName(); + private static final String CLINIT_CLASS_NAME = PACKAGE_NAME + ".StaticInitializer"; + private static final String CLINIT_METHOD_NAME = CLINIT_CLASS_NAME + "::"; + + public static void main(String... args) throws Exception { + try (Recording r = new Recording()) { + r.enable("jdk.MethodTrace") + .with("filter", CLINIT_CLASS_NAME); + r.enable("jdk.MethodTiming") + .with("filter", CLINIT_METHOD_NAME) + .with("period", "endChunk"); + + r.start(); + StaticInitializer.TRIGGERED = "true"; + r.stop(); + + List events = Events.fromRecording(r); + Events.assertEventCount(events, 2); + + RecordedEvent traceEvent = Events.getFirst(events, "jdk.MethodTrace"); + Events.assertTopFrame(traceEvent, TestClinit.class.getName(), "main"); + assertClinitMethod(traceEvent); + + RecordedEvent timingEvent = Events.getFirst(events, "jdk.MethodTiming"); + assertClinitMethod(timingEvent); + } + } + + private static void assertClinitMethod(RecordedEvent event) throws Exception { + RecordedMethod method = event.getValue("method"); + if (!method.getName().equals("")) { + System.out.println(event); + throw new Exception("Expected , was " + method.getName()); + } + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestCombinedFilters.java b/test/jdk/jdk/jfr/event/tracing/TestCombinedFilters.java new file mode 100644 index 00000000000..d794a694555 --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestCombinedFilters.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import jdk.jfr.EventType; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedClass; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.event.tracing.Apple; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Tests that the union of annotation-based, class-based and + * method-based filters can be used simultaneously. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @build jdk.jfr.event.tracing.Apple + * @run main/othervm -Xlog:jfr+methodtrace=trace + * jdk.jfr.event.tracing.TestCombinedFilters + **/ +public class TestCombinedFilters { + private static final String APPLE_ANNOTATION = Apple.class.getName(); + private static final String TRACE_EVENT = "jdk.MethodTrace"; + private static final String TIMING_EVENT = "jdk.MethodTiming"; + private static final String FOO_CLASS = Foo.class.getName(); + + public static class Foo { + @Apple + static void bar() { + System.out.println("Executing Foo:bar"); + } + + static void baz() { + System.out.println("Executing Foo:baz"); + } + + static void qux() { + System.out.println("Executing Foo:qux"); + } + } + + record TestEvent(String event, String type, String method) { + } + + public static void main(String... args) throws Exception { + String traceFilter = "@" + APPLE_ANNOTATION + ";" + FOO_CLASS + "::bar"; + String timingFilter = Foo.class.getName(); + try (Recording r = new Recording()) { + r.enable(TRACE_EVENT).with("filter", traceFilter); + r.enable(TIMING_EVENT).with("filter", timingFilter).with("period", "endChunk"); + for (var entry : r.getSettings().entrySet()) { + System.out.println(entry.getKey() + "=" + entry.getValue()); + } + r.start(); + Foo.bar(); + Foo.baz(); + Foo.qux(); + r.stop(); + var list = List.of(new TestEvent(TRACE_EVENT, FOO_CLASS, "bar"), + new TestEvent(TIMING_EVENT, FOO_CLASS, ""), + new TestEvent(TIMING_EVENT, FOO_CLASS, "bar"), + new TestEvent(TIMING_EVENT, FOO_CLASS, "baz"), + new TestEvent(TIMING_EVENT, FOO_CLASS, "qux")); + List expected = new ArrayList<>(list); + List events = Events.fromRecording(r); + for (RecordedEvent event : events) { + System.out.println(event); + } + Events.hasEvents(events); + for (RecordedEvent e : events) { + RecordedMethod method = e.getValue("method"); + String className = method.getType().getName(); + String eventTypeName = e.getEventType().getName(); + TestEvent testEvent = new TestEvent(eventTypeName, className, method.getName()); + if (!expected.remove(testEvent)) { + throw new Exception("Unexpected event " + testEvent); + } + } + if (!expected.isEmpty()) { + throw new Exception("Missing events " + expected); + } + } + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestFilterClass.java b/test/jdk/jdk/jfr/event/tracing/TestFilterClass.java new file mode 100644 index 00000000000..e89813d444f --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestFilterClass.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; + +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Tests that class filters work as expected. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm -Xlog:jfr+methodtrace=trace + * jdk.jfr.event.tracing.TestFilterClass + **/ +public class TestFilterClass { + private static final String THIS_CLASS = TestFilterClass.class.getName(); + private static final String EVENT_NAME = "jdk.MethodTrace"; + + interface Interface { + void foo(); + + void bar(); + + public static void baz() { + System.out.println("Executing Interface::baz"); + } + } + + static class Implementation implements Interface { + public void foo() { + System.out.println("Executing Implementation::foo"); + } + + @Override + public void bar() { + throw new Error("Should not happen"); + } + } + + enum Enum { + VALUE; + + public void bar() { + System.out.println("Executing Enum::bar"); + } + } + + record Record(int value) { + } + + public static void main(String... args) throws Exception { + try (Recording r = new Recording()) { + r.enable(EVENT_NAME) + .with("filter", THIS_CLASS + "$Implementation;" + + THIS_CLASS + "$Interface;" + + THIS_CLASS + "$Enum;" + + THIS_CLASS + "$Record"); + r.start(); + Interface.baz(); + new Implementation().foo(); + Enum.VALUE.bar(); + new Record(4711).value(); + r.stop(); + var list = new ArrayList<>(List.of(THIS_CLASS + "$Interface::baz", THIS_CLASS + "$Implementation::", THIS_CLASS + "$Implementation::foo", THIS_CLASS + "$Enum::", + THIS_CLASS + "$Enum::", THIS_CLASS + "$Enum::bar", THIS_CLASS + "$Record::", THIS_CLASS + "$Record::value")); + var events = Events.fromRecording(r); + System.out.println(list); + Events.hasEvents(events); + for (RecordedEvent event : events) { + System.out.println(event); + RecordedMethod method = event.getValue("method"); + String name = method.getType().getName() + "::" + method.getName(); + if (!list.remove(name)) { + throw new Exception("Unexpected method '" + name + "' in event"); + } + } + if (!list.isEmpty()) { + throw new Exception("Expected events for the methods " + list); + } + } + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestFilterClassAnnotation.java b/test/jdk/jdk/jfr/event/tracing/TestFilterClassAnnotation.java new file mode 100644 index 00000000000..fddf82ca419 --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestFilterClassAnnotation.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + + +import jdk.jfr.event.tracing.Apple; +import jdk.jfr.event.tracing.Banana; + + +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +import java.lang.annotation.Target; +import java.util.HashSet; +import java.util.Set; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; +import jdk.jfr.consumer.RecordedMethod; + +/** + * @test + * @summary Tests class-annotation-based filtering. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main/othervm + * -Xlog:jfr+methodtrace=trace + * jdk.jfr.event.tracing.TestFilterClassAnnotation + */ + +// @Banana and Apple tests multiple annotations and that the target is not the first annotation +@Banana +@Apple +public class TestFilterClassAnnotation { + private static final String EVENT_NAME = "jdk.MethodTrace"; + + // Class Foo tests inner and interface classes + @Apple + interface Foo { + // Method duck() tests that static methods in interfaces can be instrumented + private static void duck() { + System.out.println("Executing method: duck()"); + } + + // Method eggplant() tests that abstract method doesn't interfere in the + // instrumentation + void eggplant(); + } + + // Method ant() tests that the same method annotation as the class doesn't + // interfere + @Apple + private static void ant() { + System.out.println("Executing method: ant()"); + } + + // Method bear() tests that other method annotation doesn't interfere + @Banana + private static void bear() { + System.out.println("Executing method: bear()"); + } + + // Method cat() tests that a method in an annotated class is instrumented + private static void cat() { + System.out.println("Executing method: cat()"); + } + + public static void main(String... args) throws Exception { + try (Recording r = new Recording()) { + r.enable(EVENT_NAME) + .with("filter", "@" + Apple.class.getName()); + r.start(); + ant(); + bear(); + cat(); + Foo.duck(); + r.stop(); + + var set = new HashSet<>(Set.of("ant", "bear", "cat", "duck")); + var events = Events.fromRecording(r); + Events.hasEvents(events); + for (RecordedEvent e : events) { + System.out.println(e); + RecordedMethod method = e.getValue("method"); + if (!set.remove(method.getName())) { + throw new Exception("Unexpected method '" + method.getName() + "' in event"); + } + RecordedFrame topFrame = e.getStackTrace().getFrames().get(0); + String topMethod = topFrame.getMethod().getName(); + if (!topMethod.equals("main")) { + throw new Exception("Expected method to be called from main"); + } + } + if (!set.isEmpty()) { + throw new Exception("Expected events for the methods " + set); + } + } + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestFilterMethod.java b/test/jdk/jdk/jfr/event/tracing/TestFilterMethod.java new file mode 100644 index 00000000000..82356ac1bfd --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestFilterMethod.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; +import jdk.jfr.consumer.RecordedMethod; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Tests that a method filter (e.g., class::method) works as expected. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm -Xlog:jfr+methodtrace=trace + * jdk.jfr.event.tracing.TestFilterMethod + */ +public class TestFilterMethod { + private static final String THIS_CLASS = TestFilterMethod.class.getName(); + private static final String EVENT_NAME = "jdk.MethodTrace"; + + // Tests implicit constructor + static public class SomeClass { + public void override() { + throw new Error("Should not happen"); + } + } + + // Tests explicit constructor + static public class OtherClass extends SomeClass { + public OtherClass() { + System.out.println("Executing Otherclass::Otherclass()"); + } + } + + // Tests method override + static public class SomeSubclass extends SomeClass { + public void override() { + System.out.println("Executing SomeSubclass::override()"); + } + } + + // Tests method in enum + enum Enum { + VALUE; + + static void enumMethod() { + System.out.println("Executing Enum:enumMethod"); + } + } + + // Tests method in interface + interface Interface { + public static void staticMethod() { + System.out.println("Executing Interface::staticMethod"); + } + + public void instanceMethod(); + } + + static class Implementation implements Interface { + @Override + public void instanceMethod() { + } + } + + // Tests normal method + public static void overload() { + System.out.println("Executing overload()"); + } + + // Tests overloaded method + public static void overload(int value) { + System.out.println("Executing overload(" + value + ")"); + } + + public static void main(String... args) throws Exception { + try (Recording r = new Recording()) { + r.enable(EVENT_NAME) + .with("filter", THIS_CLASS + "$SomeSubclass::override;" + + THIS_CLASS + "$OtherClass::;" + + THIS_CLASS + "::overload;" + + THIS_CLASS + "$Enum::enumMethod;" + + THIS_CLASS + "$Interface::staticMethod;" + + THIS_CLASS + "$Implementation::instanceMethod"); + r.start(); + new SomeSubclass().override(); + new OtherClass(); + overload(); + overload(1); + Enum.enumMethod(); + Interface.staticMethod(); + new Implementation().instanceMethod(); + r.stop(); + + var set = new ArrayList<>(List.of( + "", // OtherClass: + "override", + "overload", // overload() + "overload", // overload(int) + "enumMethod", + "staticMethod", + "instanceMethod")); + var events = Events.fromRecording(r); + Events.hasEvents(events); + for (RecordedEvent event : events) { + System.out.println(event); + RecordedMethod m = event.getValue("method"); + if (!set.remove(m.getName())) { + throw new Exception("Unexpected method '" + m.getName() + "' in event"); + } + RecordedFrame topFrame = event.getStackTrace().getFrames().get(0); + String topMethod = topFrame.getMethod().getName(); + if (!topMethod.equals("main")) { + throw new Exception("Expected method to be called from main"); + } + } + if (!set.isEmpty()) { + throw new Exception("Expected events for the methods " + set); + } + } + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestFilterMethodAnnotation.java b/test/jdk/jdk/jfr/event/tracing/TestFilterMethodAnnotation.java new file mode 100644 index 00000000000..62420e3900a --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestFilterMethodAnnotation.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.HashSet; +import java.util.Set; + +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.event.tracing.Apple; +import jdk.jfr.event.tracing.Banana; +import jdk.jfr.event.tracing.TestFilterMethodAnnotation.Foo; + +/** + * @test + * @summary Tests method-annotation-based filtering. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib /test/jdk + * @run main/othervm -Xlog:jfr+methodtrace=trace + * jdk.jfr.event.tracing.TestFilterMethodAnnotation + */ +public class TestFilterMethodAnnotation { + + static String EVENT_NAME = "jdk.MethodTrace"; + + // Tests that abstract method is ignored + static abstract class Foo { + @Apple + abstract void baz(); + } + + // Tests tracing of an inner class + static class Bar extends Foo { + @Override + // Tests method override + @Apple + void baz() { + System.out.println("Executing Bar::baz()"); + } + + @Apple + void qux() { + System.out.println("Executing Bar::qux()"); + } + } + + // Tests tracing of method with multiple annotations and the target not being + // first + @Banana + @Apple + private static void ant() { + System.out.println("Executing method: ant()"); + } + + // Tests that overloaded method with the same name is not traced + private static void ant(int i) { + System.out.println("Executing method: apple(" + i + ")"); + } + + // Tests that non-annotated method is not traced + private static void bear() { + System.out.println("Executing method: bear()"); + } + + public static void main(String... args) throws Exception { + try (Recording r = new Recording()) { + r.enable(EVENT_NAME) + .with("filter", "@" + Apple.class.getName()); + r.start(); + ant(); + ant(4711); + bear(); + Bar bar = new Bar(); + bar.baz(); + bar.qux(); + r.stop(); + var set = new HashSet<>(Set.of("ant", "baz", "qux")); + var events = Events.fromRecording(r); + Events.hasEvents(events); + for (RecordedEvent event : events) { + System.out.println(event); + RecordedMethod method = event.getValue("method"); + String methodName = method.getName(); + if (!set.remove(methodName)) { + throw new Exception("Unexpected method " + methodName + "() in event"); + } + RecordedFrame topFrame = event.getStackTrace().getFrames().get(0); + if (!topFrame.getMethod().getName().equals("main")) { + throw new Exception("Expected method to be called from main"); + } + } + if (!set.isEmpty()) { + throw new Exception("Expected events for the methods " + set); + } + } + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestInstrumentation.java b/test/jdk/jdk/jfr/event/tracing/TestInstrumentation.java new file mode 100644 index 00000000000..834d4ab4989 --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestInstrumentation.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.CopyOnWriteArrayList; + +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.consumer.RecordingStream; + +/** + * @test + * @summary Tests that methods are instrumented correctly. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm + * -Xlog:jfr+methodtrace=debug + * jdk.jfr.event.tracing.TestInstrumentation + **/ +public class TestInstrumentation { + private static Object nullObject; + + public static void main(String... args) throws Exception { + List traceEvents = new CopyOnWriteArrayList<>(); + List timingEvents = new CopyOnWriteArrayList<>(); + try (RecordingStream r = new RecordingStream()) { + r.setReuse(false); + String filter = TestInstrumentation.class.getName(); + r.enable("jdk.MethodTrace") + .with("filter", filter); + r.enable("jdk.MethodTiming") + .with("filter", filter) + .with("period", "endChunk"); + r.onEvent("jdk.MethodTrace", traceEvents::add); + r.onEvent("jdk.MethodTiming", timingEvents::add); + r.startAsync(); + try { + whileTrue(); + } catch (NullPointerException npe) { + // As expected + } + recursive(3); + switchExpression(0); + switchExpression(1); + switchExpression(2); + multipleReturns(); + multipleReturns(); + multipleReturns(); + multipleReturns(); + multipleReturns(); + try { + exception(); + } catch (Exception e) { + } + try { + deepException(); + } catch (Exception e) { + } + r.stop(); + } + verifyTracing(traceEvents); + verifyTiming(timingEvents); + } + + private static void verifyTracing(List events) throws Exception { + Map map = buildMethodMap(events, false); + printMap("Tracing:", map); + assertMethod(map, "exception", 2); + assertMethod(map, "switchExpression", 3); + assertMethod(map, "recursive", 4); + assertMethod(map, "multipleReturns", 5); + if (!map.isEmpty()) { + throw new Exception("Found unexpected methods " + map.keySet()); + } + } + + private static void verifyTiming(List events) throws Exception { + Map map = buildMethodMap(events, true); + printMap("Timing:", map); + assertMethod(map, "exception", 2); + assertMethod(map, "switchExpression", 3); + assertMethod(map, "recursive", 4); + assertMethod(map, "multipleReturns", 5); + for (var entry : map.entrySet()) { + long invocations = entry.getValue(); + if (invocations != 0L) { + throw new Exception("Unexpected " + invocations + " invocations for method " + entry.getKey()); + } + } + } + + private static void printMap(String caption, Map map) { + System.out.println(caption); + for (var entry : map.entrySet()) { + System.out.println(entry.getKey() + " = " + entry.getValue()); + } + System.out.println(); + } + + private static void assertMethod(Map map, String method, long value) throws Exception { + if (!map.containsKey(method)) { + throw new Exception("Missing method " + method); + } + if (!map.get(method).equals(value)) { + throw new Exception("Expected value " + value + " for method " + method); + } + map.remove(method); + } + + private static Map buildMethodMap(List events, boolean invocations) { + Map map = new HashMap<>(); + for (RecordedEvent e : events) { + RecordedMethod m = e.getValue("method"); + String name = m.getName(); + long add = invocations ? e.getLong("invocations") : 1; + map.compute(name, (key, value) -> (value == null) ? add : value + add); + } + return map; + } + + public static void whileTrue() { + while (true) { + nullObject.toString(); + } + } + + public static void recursive(int depth) { + if (depth > 0) { + recursive(depth - 1); + } else { + return; + } + } + + public static String switchExpression(int value) { + return switch (value) { + case 0 -> "zero"; + case 1 -> "one"; + default -> "number"; + }; + } + + public static void multipleReturns() { + Random r = new Random(); + int v = r.nextInt(5); + if (v == 0) { + return; + } + switch (v) { + case 1: + return; + case 2: + return; + } + return; + } + + public static void exception() throws Exception { + throw new Exception(""); + } + + public static void deepException() throws Exception { + exception(); + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestMethodTiming.java b/test/jdk/jdk/jfr/event/tracing/TestMethodTiming.java new file mode 100644 index 00000000000..1de0e5e20eb --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestMethodTiming.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.time.Duration; +import java.util.List; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.Event; +import jdk.jfr.StackTrace; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Basic test of the MethodTiming event. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.event.tracing.TestMethodTiming + **/ +public class TestMethodTiming { + private static final String EVENT_NAME = "jdk.MethodTiming"; + + @StackTrace(false) + static class TimeMeasureEvent extends Event { + public String id; + } + + public static void main(String... args) throws Exception { + testCount(); + testDuration(); + } + + private static void testDuration() throws Exception { + try (Recording r = new Recording()) { + String filter = TestMethodTiming.class.getName() + "::takeNap"; + r.enable(EVENT_NAME).with("period", "endChunk").with("filter", filter); + r.start(); + + TimeMeasureEvent maxEvent = new TimeMeasureEvent(); + maxEvent.id = "max"; + maxEvent.begin(); + takeNap(); + maxEvent.commit(); + r.stop(); + List events = Events.fromRecording(r); + for (var e : events) { + System.out.println(e); + } + if (events.size() != 3) { + throw new Exception("Expected three events: TimeMeasureEvent::id=max, TimeMeasureEventid=min and MethodTiming::method=takeNap()"); + } + RecordedEvent max = findWitdId(events, "max"); + RecordedEvent min = findWitdId(events, "min"); + + events.remove(min); + events.remove(max); + Duration minDuration = min.getDuration(); + Duration maxDuration = max.getDuration(); + RecordedEvent timingEvent = events.get(0); + Duration d = timingEvent.getDuration("average"); + if (d.compareTo(min.getDuration()) < 0) { + throw new Exception("Expected duration to be at least " + minDuration + ", was " + d); + } + if (d.compareTo(max.getDuration()) > 0) { + throw new Exception("Expected duration to be at most " + maxDuration + ", was " + d); + } + RecordedMethod method = timingEvent.getValue("method"); + String methodName = method.getType().getName() + "::" + method.getName() + " " + method.getDescriptor(); + String expected = TestMethodTiming.class.getName() + "::takeNap ()V"; + if (!methodName.equals(expected)) { + System.out.println(expected); + throw new Exception("Expected method " + expected + " in event, but was " +methodName); + } + if (timingEvent.getLong("invocations") != 1) { + throw new Exception("Expected one invocation"); + } + } + } + + private static RecordedEvent findWitdId(List events, String id) throws Exception { + for (RecordedEvent event : events) { + if (event.hasField("id")) { + if (event.getString("id").equals(id)) { + return event; + } + } + } + throw new Exception("Could not find event with ID " + id); + } + + private static void takeNap() throws Exception { + TimeMeasureEvent minEvent = new TimeMeasureEvent(); + minEvent.begin(); + minEvent.id = "min"; + Thread.sleep(10); + minEvent.commit(); + } + + private static void testCount() throws Exception { + long invocations = 100_000; + try (Recording r = new Recording()) { + zebra(); + String filter = TestMethodTiming.class.getName() + "::zebra"; + r.enable(EVENT_NAME).with("period", "endChunk").with("filter", filter); + r.start(); + for (int i = 0; i < invocations; i++) { + zebra(); + } + r.stop(); + List events = Events.fromRecording(r); + Events.hasEvents(events); + for (RecordedEvent event : events) { + Events.assertField(event, "invocations").equal(invocations); + } + } + } + + private static void zebra() { + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestMethodTrace.java b/test/jdk/jdk/jfr/event/tracing/TestMethodTrace.java new file mode 100644 index 00000000000..a5fd1430627 --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestMethodTrace.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.util.concurrent.atomic.AtomicReference; + +import jdk.jfr.Event; +import jdk.jfr.StackTrace; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.consumer.RecordingStream; + +/** + * @test + * @summary Basic test of the MethodTrace event. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm -Xlog:jfr+methodtrace=trace + * jdk.jfr.event.tracing.TestMethodTrace + **/ +public class TestMethodTrace { + private static final String EVENT_NAME = "jdk.MethodTrace"; + private static final String CLASS_NAME = TestMethodTrace.class.getName(); + + @StackTrace(false) + private static class OuterMeasurement extends Event { + } + + @StackTrace(false) + private static class InnerMeasurement extends Event { + } + + public static void main(String... args) throws Exception { + AtomicReference o = new AtomicReference<>(); + AtomicReference i = new AtomicReference<>(); + AtomicReference e = new AtomicReference<>(); + try (RecordingStream s = new RecordingStream()) { + s.enable(EVENT_NAME).with("filter", CLASS_NAME + "::bar"); + s.onEvent(EVENT_NAME, e::set); + s.onEvent(OuterMeasurement.class.getName(), o::set); + s.onEvent(InnerMeasurement.class.getName(), i::set); + s.startAsync(); + foo(); + s.stop(); + } + RecordedEvent event = e.get(); + RecordedEvent outer = o.get(); + RecordedEvent inner = i.get(); + System.out.println(event); + + System.out.println("Outer start : " + outer.getStartTime()); + System.out.println(" Method Trace start : " + event.getStartTime()); + System.out.println(" Inner start : " + inner.getStartTime()); + System.out.println(" Inner end : " + inner.getEndTime()); + System.out.println(" Method Trace end : " + event.getEndTime()); + System.out.println("Outer end : " + outer.getEndTime()); + + if (event.getStartTime().isBefore(outer.getStartTime())) { + throw new Exception("Too early start time"); + } + if (event.getStartTime().isAfter(inner.getStartTime())) { + throw new Exception("Too late start time"); + } + if (event.getEndTime().isBefore(inner.getEndTime())) { + throw new Exception("Too early end time"); + } + if (event.getEndTime().isAfter(outer.getEndTime())) { + throw new Exception("Too late end time"); + } + RecordedMethod method = event.getValue("method"); + if (!method.getName().equals("bar")) { + throw new Exception("Expected method too be bar()"); + } + RecordedMethod topMethod = event.getStackTrace().getFrames().get(0).getMethod(); + if (!topMethod.getName().equals("foo")) { + throw new Exception("Expected top frame too be foo()"); + } + } + + private static void foo() { + OuterMeasurement event = new OuterMeasurement(); + event.begin(); + bar(); + event.commit(); + } + + private static void bar() { + InnerMeasurement event = new InnerMeasurement(); + event.begin(); + event.commit(); + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestMultipleRecordings.java b/test/jdk/jdk/jfr/event/tracing/TestMultipleRecordings.java new file mode 100644 index 00000000000..b06fe019810 --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestMultipleRecordings.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.io.IOException; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.test.lib.jfr.Events; +import jdk.test.lib.jfr.EventNames; +/** + * @test + * @summary Tests that method tracing can be used with multiple recordings. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm + * -Xlog:jfr+methodtrace=debug + * jdk.jfr.event.tracing.TestMultipleRecordings + **/ +public class TestMultipleRecordings { + private static final String METHOD_TRACE = "jdk.MethodTrace"; + private static final String METHOD_TIMING = "jdk.MethodTiming"; + private static final String CLASS_NAME = TestMultipleRecordings.class.getName(); + + public static void main(String... args) throws Exception { + testNestedMethodTrace(); + testNestedMethodTiming(); + } + + private static void testNestedMethodTiming() throws Exception { + List outerEvents = new ArrayList<>(); + List innerEvents = new ArrayList<>(); + + runNested(METHOD_TIMING, outerEvents, innerEvents); + var outerBatches = groupByEndTime(outerEvents); + System.out.println("Number of outer batches: " + outerBatches.size()); + // Outer started + assertTimingBatch("outer: started", outerBatches.get(0), Map.of("foo", 0, "baz", 0)); + assertTimingBatch("outer: initial to bestarted", outerBatches.get(1), Map.of("foo", 1, "baz", 1)); + // Inner started + assertTimingBatch("outer: inner started", outerBatches.get(2), Map.of("foo", 1, "baz", 1, "bar", 0)); + assertTimingBatch("outer: inner ended", outerBatches.get(3), Map.of("foo", 2, "baz", 2, "bar", 1)); + // Inner stopped + assertTimingBatch("outer: only outer", outerBatches.get(4), Map.of("foo", 2, "baz", 2)); + assertTimingBatch("outer: ending", outerBatches.get(5), Map.of("foo", 3, "baz", 3)); + // Outer stopped + + var innerBatches = groupByEndTime(innerEvents); + System.out.println("Number of inner batches: " + innerBatches.size()); + assertTimingBatch("inner: started", innerBatches.get(0), Map.of("foo", 1, "baz", 1, "bar", 0)); + assertTimingBatch("inner: ended", innerBatches.get(1), Map.of("foo", 2, "baz", 2, "bar", 1)); + } + + private static void assertTimingBatch(String batchName, List events, Map expected) throws Exception { + Map map = new HashMap<>(); + for (RecordedEvent e : events) { + RecordedMethod m = e.getValue("method"); + String name = m.getName(); + int invocations = (int) e.getLong("invocations"); + map.put(name, invocations); + } + if (!map.equals(expected)) { + printBatch("Expected:", expected); + printBatch("Was:", map); + throw new Exception("Batch '" + batchName + "' not as expected"); + } + } + + private static void printBatch(String name, Map batch) { + System.out.println(name); + for (var entry : batch.entrySet()) { + System.out.println(entry.getKey() + " = " + entry.getValue()); + } + } + + private static List> groupByEndTime(List events) { + var listList = new ArrayList>(); + List list = null; + Instant last = null; + while (!events.isEmpty()) { + RecordedEvent event = removeEarliest(events); + Instant timestamp = event.getEndTime(); + if (last == null || !timestamp.equals(last)) { + list = new ArrayList(); + listList.add(list); + } + list.add(event); + last = event.getEndTime(); + } + return listList; + } + + private static RecordedEvent removeEarliest(List events) { + RecordedEvent earliest = null; + for (RecordedEvent event : events) { + if (earliest == null || event.getEndTime().isBefore(earliest.getEndTime())) { + earliest = event; + } + } + events.remove(earliest); + return earliest; + } + + private static void testNestedMethodTrace() throws Exception { + List outerEvents = new ArrayList<>(); + List innerEvents = new ArrayList<>(); + + runNested(METHOD_TRACE, outerEvents, innerEvents); + + assertMethodTraceEvents(outerEvents, "Outer", "foo", 3); + assertMethodTraceEvents(outerEvents, "Outer", "bar", 1); + assertMethodTraceEvents(outerEvents, "Outer", "baz", 3); + assertMethodTraceEvents(innerEvents, "Inner", "foo", 1); + assertMethodTraceEvents(innerEvents, "Inner", "bar", 1); + assertMethodTraceEvents(innerEvents, "Inner", "baz", 1); + } + + private static void runNested(String eventName, List outerEvents, List innerEvents) + throws IOException { + try (Recording outer = new Recording()) { + outer.enable(eventName).with("filter", + CLASS_NAME + "::foo;" + + CLASS_NAME + "::baz"); + outer.start(); + foo(); + bar(); + baz(); + nap(); + try (Recording inner = new Recording()) { + inner.enable(eventName).with("filter", + CLASS_NAME + "::foo;" + + CLASS_NAME + "::bar"); + inner.start(); + foo(); + bar(); + baz(); + inner.stop(); + innerEvents.addAll(Events.fromRecording(inner)); + nap(); + } + foo(); + bar(); + baz(); + nap(); + outer.stop(); + outerEvents.addAll(Events.fromRecording(outer)); + } + } + + // Ensure that periodic events at endChunk get a different + // timestamp than periodic events at beginChunk + private static void nap() { + Instant time = Instant.now(); + do { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + // ignore + } + } while (time.plus(Duration.ofMillis(10)).isAfter(Instant.now())); + } + + private static void assertMethodTraceEvents(List events, String context, String methodName, int expected) throws Exception { + int actual = 0; + for (RecordedEvent event : events) { + RecordedMethod method = event.getValue("method"); + if (method.getName().equals(methodName)) { + actual++; + } + } + if (actual != expected) { + System.out.println(context); + for (RecordedEvent event : events) { + System.out.println(event); + } + throw new Exception(context + ": expected " + expected + " events for method " + methodName + ", got actual " + actual); + } + } + + private static void foo() { + System.out.println("Executing: foo()"); + } + + private static void bar() { + System.out.println("Executing: bar()"); + } + + private static void baz() { + System.out.println("Executing: baz()"); + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestMultipleThreads.java b/test/jdk/jdk/jfr/event/tracing/TestMultipleThreads.java new file mode 100644 index 00000000000..5b51d234661 --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestMultipleThreads.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.util.ArrayList; +import java.util.List; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.consumer.RecordingStream; + +/** + * @test + * @summary Tests that tracing and timing work when using multiple threads. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm + * -Xlog:jfr+methodtrace=trace + * jdk.jfr.event.tracing.TestMultipleThreads + **/ +public class TestMultipleThreads { + private static final String METHOD_PREFIX = TestMultipleThreads.class.getName() + "::method"; + private static final String TRACE_EVENT = "jdk.MethodTrace"; + private static final String TIMING_EVENT = "jdk.MethodTiming"; + private static int METHOD_COUNT = 5; + private static int THREAD_COUNT = 5; + private static int INVOCATIONS_PER_THREAD = 25_000; // Low enough to fit one chunk + private static int INVOCATIONS_PER_METHOD = THREAD_COUNT * INVOCATIONS_PER_THREAD / METHOD_COUNT; + + public static class TestThread extends Thread { + public void run() { + for (int i = 0; i < INVOCATIONS_PER_THREAD; i++) { + switch (i % METHOD_COUNT) { + case 0 -> method0(); + case 1 -> method1(); + case 2 -> method2(); + case 3 -> method3(); + case 4 -> method4(); + } + } + } + } + + public static void main(String... args) throws Exception { + List traceEvents = new ArrayList<>(); + List timingEvents = new ArrayList<>(); + try (RecordingStream r = new RecordingStream()) { + r.enable(TRACE_EVENT).with("filter", + METHOD_PREFIX + "0;" + + METHOD_PREFIX + "2;"); + r.enable(TIMING_EVENT).with("filter", + METHOD_PREFIX + "0;" + + METHOD_PREFIX + "1;" + + METHOD_PREFIX + "2;" + + METHOD_PREFIX + "3;" + + METHOD_PREFIX + "4;") + .with("period", "endChunk"); + List threads = new ArrayList<>(); + for (int i = 0; i < THREAD_COUNT; i++) { + threads.add(new TestThread()); + } + r.setReuse(false); + r.onEvent(TRACE_EVENT, traceEvents::add); + r.onEvent(TIMING_EVENT, timingEvents::add); + r.startAsync(); + for (TestThread t : threads) { + t.start(); + } + for (TestThread t : threads) { + t.join(); + } + r.stop(); + verifyTraceEvents(traceEvents); + for (RecordedEvent event : timingEvents) { + System.out.println(event); + } + verifyTimingEvents(timingEvents); + } + } + + private static void verifyTimingEvents(List events) throws Exception { + for (RecordedEvent e : events) { + long invocations = e.getLong("invocations"); + if (invocations != INVOCATIONS_PER_METHOD) { + RecordedMethod method = e.getValue("method"); + String msg = "Expected " + INVOCATIONS_PER_METHOD + " invocations for "; + msg += method.getName() + ", but got " + invocations; + throw new Exception(msg); + } + } + if (events.size() != METHOD_COUNT) { + throw new Exception("Expected " + METHOD_COUNT + " timing events, one per method"); + } + } + + private static void verifyTraceEvents(List events) throws Exception { + int expected = 2 * INVOCATIONS_PER_METHOD; + if (events.size() != expected) { + throw new Exception("Expected " + expected + " event, but got " + events.size()); + } + } + + private static void method0() { + } + + private static void method1() { + } + + private static void method2() { + } + + private static void method3() { + } + + private static void method4() { + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestRestrictedClasses.java b/test/jdk/jdk/jfr/event/tracing/TestRestrictedClasses.java new file mode 100644 index 00000000000..2bc567e23f1 --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestRestrictedClasses.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import jdk.jfr.FlightRecorder; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +/** + * @test + * @summary Tests that restricted classes cannot be timed or traced. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.event.tracing.TestRestrictedClasses + **/ +public class TestRestrictedClasses { + + public static void main(String... args) throws Exception { + testJdkJfr(); + testConcurrentHashMap(); + testConcurrentHashMapNode(); + testAtomicLong(); + } + + private static void testJdkJfr() throws Exception { + testDebug(FlightRecorder.class.getName(), null); + } + + private static void testConcurrentHashMapNode() throws Exception { + testDebug(ConcurrentHashMap.class.getName() + "$Node", "Risk of recursion, skipping bytecode generation for java.util.concurrent.ConcurrentHashMap$Node"); + } + + private static void testConcurrentHashMap() throws Exception { + testDebug(ConcurrentHashMap.class.getName(), "Risk of recursion, skipping bytecode generation for java.util.concurrent.ConcurrentHashMap"); + } + + private static void testAtomicLong() throws Exception { + testDebug(AtomicLong.class.getName(), "Risk of recursion, skipping bytecode generation for java.util.concurrent.atomic.AtomicLong"); + } + + private static void testDebug(String clazz, String expected) throws Exception { + List cmds = new ArrayList<>(); + cmds.add("-Xlog:jfr+methodtrace=debug"); + cmds.add("-XX:StartFlightRecording:method-trace=" + clazz); + cmds.add("-version"); + OutputAnalyzer out = ProcessTools.executeTestJava(cmds); + out.shouldHaveExitValue(0); + if (expected != null) { + out.shouldContain(expected); + } + // Check that bytecode was not generated + out.shouldNotMatch("Bytecode generation"); + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestRetransformFalse.java b/test/jdk/jdk/jfr/event/tracing/TestRetransformFalse.java new file mode 100644 index 00000000000..60bcda4e40b --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestRetransformFalse.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.util.List; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Tests that tracing doesn't work retransformation disabled. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm + * -Xlog:jfr+methodtrace=info + * -XX:FlightRecorderOptions:retransform=false + * jdk.jfr.event.tracing.TestRetransformFalse false + * @run main/othervm -Xlog:jfr+methodtrace=info + * -Xlog:jfr+methodtrace=info + * -XX:FlightRecorderOptions:retransform=true + * jdk.jfr.event.tracing.TestRetransformFalse true + **/ +public class TestRetransformFalse { + private static final String FILTER = "jdk.jfr.event.tracing.TestRetransformFalse::foo"; + public static void main(String... args) throws Exception { + boolean retransform = switch (args[0]) { + case "true" -> true; + case "false" -> false; + default -> throw new Exception("Test error, expected 'true' or 'false' argument to test."); + }; + System.out.println("Testing -XX:FlightRecorderOptions:retransform=" + retransform); + try (Recording r = new Recording()) { + r.enable("jdk.MethodTrace") + .with("filter", FILTER); + r.enable("jdk.MethodTiming") + .with("filter", FILTER) + .with("period", "endChunk"); + r.start(); + foo(); + r.stop(); + List events = Events.fromRecording(r); + System.out.println(events); + if (retransform) { + Events.assertEventCount(events, 2); + } else { + Events.assertEventCount(events, 0); + } + } + } + + private static void foo() { + System.out.println("Running Foo"); + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestWithClassLoaders.java b/test/jdk/jdk/jfr/event/tracing/TestWithClassLoaders.java new file mode 100644 index 00000000000..0dca1aa97cc --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestWithClassLoaders.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.io.IOException; +import java.util.concurrent.CopyOnWriteArrayList; + +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.consumer.RecordingStream; + +/** + * @test + * @summary Tests that filters can be applied to classes across multiple class loaders and that + * method tracing works after class unloading. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @build jdk.jfr.event.tracing.Car + * @run main/othervm -XX:-DisableExplicitGC -Xlog:jfr+methodtrace=trace + * jdk.jfr.event.tracing.TestWithClassLoaders + **/ +public class TestWithClassLoaders { + private static final String METHOD_TRACE = "jdk.MethodTrace"; + private static final String METHOD_TIMING = "jdk.MethodTiming"; + private static final String CLASS_NAME = "jdk.jfr.event.tracing.Car"; + + public static void main(String... args) throws Exception { + var traceEvents = new CopyOnWriteArrayList(); + var timingEvents = new CopyOnWriteArrayList(); + try (var r = new RecordingStream()) { + Runnable beforeCar = createCar("before"); + r.setReuse(false); + r.enable(METHOD_TRACE) + .with("filter", CLASS_NAME + "::run"); + r.enable(METHOD_TIMING) + .with("filter", CLASS_NAME + "::run").with("period", "endChunk"); + r.onEvent(METHOD_TRACE, traceEvents::add); + r.onEvent(METHOD_TIMING, timingEvents::add); + r.startAsync(); + Runnable duringCar = createCar("during"); + Runnable garbageCar = createCar("garbage"); + beforeCar.run(); + duringCar.run(); + garbageCar.run(); + garbageCar = null; + System.gc(); + System.gc(); + r.stop(); + System.out.println("Method Trace events:"); + System.out.println(traceEvents); + if (traceEvents.size() != 3) { + throw new Exception("Expected 3 Method Trace events, one for each class loader"); + } + for (RecordedEvent event : traceEvents) { + RecordedMethod method = event.getValue("method"); + String methodName = method.getName(); + if (!methodName.equals("run")) { + throw new Exception("Expected method name to be 'run'"); + } + } + System.out.println("Method Timing events:"); + System.out.println(timingEvents); + if (timingEvents.size() != 3) { + throw new Exception("Expected 3 Method Timing events, one for each class loader"); + } + int totalInvocations = 0; + for (RecordedEvent event : timingEvents) { + totalInvocations += event.getLong("invocations"); + } + if (totalInvocations != 3) { + throw new Exception("Expected three invocations in total, was " + totalInvocations); + } + } + } + + public static Runnable createCar(String name) throws Exception { + byte[] bytes = loadCarBytes(); + ClassLoader parent = TestWithClassLoaders.class.getClassLoader(); + CarLoader loader = new CarLoader(name, bytes, parent); + Class clazz = loader.loadClass(CLASS_NAME); + Object instance = clazz.getConstructor().newInstance(); + return (Runnable) instance; + } + + private static byte[] loadCarBytes() throws IOException { + String location = "/" + CLASS_NAME.replaceAll("\\.", "/").concat(".class"); + try (var is = TestWithClassLoaders.class.getResourceAsStream(location)) { + return is.readAllBytes(); + } + } + + public static class CarLoader extends ClassLoader { + private final byte[] bytes; + + public CarLoader(String name, byte[] bytes, ClassLoader parent) { + super(name, parent); + this.bytes = bytes; + } + + protected Class loadClass(String className, boolean resolve) throws ClassNotFoundException { + Class clazz = findLoadedClass(className); + if (clazz == null && className.equals(CLASS_NAME)) { + clazz = defineClass(className, bytes, 0, bytes.length); + } else { + clazz = super.loadClass(className, resolve); + } + if (resolve) { + resolveClass(clazz); + } + return clazz; + } + } +} diff --git a/test/jdk/jdk/jfr/event/tracing/TestWithModules.java b/test/jdk/jdk/jfr/event/tracing/TestWithModules.java new file mode 100644 index 00000000000..2b115a6b65c --- /dev/null +++ b/test/jdk/jdk/jfr/event/tracing/TestWithModules.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.tracing; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.jfr.Recording; +import java.util.spi.ToolProvider; + +import jdk.jfr.consumer.EventStream; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedMethod; +import jdk.jfr.consumer.RecordingStream; + +/** + * @test + * @summary Tests applying filters to methods in both exported and unexported packages + * of a named module. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.event.tracing.TestWithModules + **/ +public class TestWithModules { + + /** Directory structure: + |-src + |-application + | |-Main.java + |-module + |-module-info.java + |-test + |-exported + | |- Exported.java + |-unexported + |- UnExported.java + **/ + private static String MODULE_INFO = + """ + module test.exported { + exports test.exported; + } + """; + + private static String EXPORTED_CLASS = + """ + package test.exported; + + import test.unexported.Unexported; + + public class Exported { + public static void run() { + System.out.println("Exported::run executed!"); + Unexported.run(); + } + } + """; + + private static String UNEXPORTED_CLASS = + """ + package test.unexported; + + public class Unexported { + public static void run() { + System.out.println("Unexported::run executed!"); + } + } + """; + + private static String MAIN_CLASS = + """ + import test.exported.Exported; + import jdk.jfr.Recording; + import java.nio.file.Path; + + public class Main { + public static void main(String... args) throws Exception { + Path file = Path.of(args[0]); + boolean before = args[1].equals("run-before"); + System.out.println("Main before=" + before); + try(Recording r = new Recording()) { + if (before) { + // Load class before JFR starts + Exported.run(); + } + r.enable("jdk.MethodTrace").with("filter", "test.unexported.Unexported::run"); + r.enable("jdk.MethodTiming").with("filter", "test.unexported.Unexported::run").with("period", "endChunk"); + r.start(); + System.out.println("About to run with instrumented"); + Exported.run(); + r.stop(); + r.dump(file); + System.out.println("Dump written " + file); + } + } + } + """; + + public static void main(String... args) throws Exception { + Path src = Path.of("src").toAbsolutePath(); + Path modulePath = materializeModule(src); + Path mainFile = materializeMain(src); + Path output = Files.createDirectory(Path.of("output").toAbsolutePath()); + List srcFiles = Files.walk(modulePath).filter(Files::isRegularFile).toList(); + List arguments = new ArrayList<>(); + arguments.add("-d"); + arguments.add(output.toString()); + for (Path p : srcFiles) { + arguments.add(p.toAbsolutePath().toString()); + } + if (!compile(arguments)) { + throw new Exception("Could not compile classes"); + } + testClassloadBefore(mainFile, output); + testClassloadDuring(mainFile, output); + } + + private static Path materializeMain(Path src) throws IOException { + Path srcApplication = Files.createDirectories(src.resolve("application")); + Path mainFile = srcApplication.resolve("Main.java"); + Files.writeString(mainFile, MAIN_CLASS); + return mainFile; + } + + private static void testClassloadBefore(Path mainFile, Path modulePath) throws Exception { + Path file = Path.of("before.jfr").toAbsolutePath(); + execute(file, mainFile, modulePath, true); + verifyRecording("already loaded class", file); + } + + private static void testClassloadDuring(Path mainFile, Path modulePath) throws Exception { + Path file = Path.of("during.jfr").toAbsolutePath(); + execute(file, mainFile, modulePath, false); + verifyRecording("loading of class", file); + } + + private static void verifyRecording(String title, Path file) throws Exception { + List traceEvents = new ArrayList<>(); + List timingEvents = new ArrayList<>(); + System.out.println("********* Verifying " + title + " ********"); + try (EventStream s = EventStream.openFile(file)) { + s.setReuse(false); + s.onEvent("jdk.MethodTrace", traceEvents::add); + s.onEvent("jdk.MethodTiming", timingEvents::add); + s.onEvent(System.out::println); + s.start(); + } + assertMethod(traceEvents, "test.unexported.Unexported", "run"); + assertMethod(timingEvents, "test.unexported.Unexported", "run"); + assertMethodTimingCount(timingEvents.get(0), 1); + } + + private static void assertMethodTimingCount(RecordedEvent event, int expected) throws Exception { + long invocations = event.getLong("invocations"); + if (invocations != expected) { + throw new Exception("Expected invocations to be " + expected + ", but was " + invocations); + } + } + + private static void assertMethod(List events, String className, String methodName) throws Exception { + for (RecordedEvent event : events) { + RecordedMethod method = event.getValue("method"); + if (method.getName().equals(methodName) && method.getType().getName().equals(className)) { + return; + } + } + throw new Exception("Expected method named " + className + "::" + methodName); + } + + private static void execute(Path jfrFile, Path mainFile, Path modulePath, boolean before) throws Exception { + String[] c = new String[7]; + c[0] = "--module-path"; + c[1] = modulePath.toString(); + c[2] = "--add-modules"; + c[3] = "test.exported"; + c[4] = mainFile.toString(); + c[5] = jfrFile.toString(); + c[6] = before ? "run-before" : "not-run-before"; + OutputAnalyzer oa = ProcessTools.executeTestJava(c); + oa.waitFor(); + oa.shouldHaveExitValue(0); + } + + private static Path materializeModule(Path src) throws IOException { + Path srcModule = Files.createDirectories(src.resolve("module")); + Path moduleFile = srcModule.resolve("module-info.java"); + Files.writeString(moduleFile, MODULE_INFO); + + Path exported = Files.createDirectories(srcModule.resolve("test").resolve("exported")); + Path exportedJava = exported.resolve("Exported.java"); + Files.writeString(exportedJava, EXPORTED_CLASS); + + Path unexported = Files.createDirectories(srcModule.resolve("test").resolve("unexported")); + Path unexportedJava = unexported.resolve("Unexported.java"); + Files.writeString(unexportedJava, UNEXPORTED_CLASS); + + return srcModule; + } + + private static boolean compile(List arguments) { + Optional tp = ToolProvider.findFirst("javac"); + if (tp.isEmpty()) { + return false; + } + var tool = tp.get(); + String[] options = arguments.toArray(String[]::new); + int ret = tool.run(System.out, System.err, options); + return ret == 0; + } +} diff --git a/test/jdk/jdk/jfr/startupargs/TestEventSettings.java b/test/jdk/jdk/jfr/startupargs/TestEventSettings.java index 37af394affd..c86a6331c52 100644 --- a/test/jdk/jdk/jfr/startupargs/TestEventSettings.java +++ b/test/jdk/jdk/jfr/startupargs/TestEventSettings.java @@ -51,7 +51,7 @@ * jdk.jfr.startupargs.TestEventSettings multipleSettings * * @run main/othervm - * -XX:StartFlightRecording:class-loading=true,socket-threshold=100ms + * -XX:StartFlightRecording:class-loading=true,locking-threshold=100ms * jdk.jfr.startupargs.TestEventSettings jfcOptions */ public class TestEventSettings { @@ -70,7 +70,7 @@ public static void main(String... args) throws Exception { } case "jfcOptions" -> { assertSetting("jdk.ClassDefine#enabled","true"); - assertSetting("jdk.SocketRead#threshold", "100 ms"); + assertSetting("jdk.JavaMonitorEnter#threshold", "100 ms"); } default -> throw new Exception("Uknown tes " + subTest); } diff --git a/test/jdk/jdk/jfr/tool/TestPrintContextual.java b/test/jdk/jdk/jfr/tool/TestPrintContextual.java new file mode 100644 index 00000000000..efecc31cb16 --- /dev/null +++ b/test/jdk/jdk/jfr/tool/TestPrintContextual.java @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.tool; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import jdk.jfr.Contextual; +import jdk.jfr.Event; +import jdk.jfr.Name; +import jdk.jfr.Recording; +import jdk.jfr.StackTrace; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +/** + * @test + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.tool.TestPrintContextual + */ +public class TestPrintContextual { + private static final int WINDOW_SIZE = 1_000_000; + private static final String CONTEXT_MARKER = "Context: "; + + private static final class PrintedEvent { + private final List> contextValues = new ArrayList<>(); + private final List> values = new ArrayList<>(); + private final String name; + + public PrintedEvent(String name) { + this.name = name; + } + + public void addValue(String key, String value) { + values.add(new AbstractMap.SimpleEntry<>(key, value)); + } + + public void addContextValue(String key, String value) { + contextValues.add(new AbstractMap.SimpleEntry<>(key, value)); + } + + public List> getContextValues() { + return contextValues; + } + + public String getContextValue(String key) { + for (var entry : contextValues) { + if (entry.getKey().equals(key)) { + return entry.getValue(); + } + } + return null; + } + } + + @Name("Span") + static class SpanEvent extends Event { + @Contextual + String name; + @Contextual + long spanId; + } + + @Name("Trace") + static class TraceEvent extends Event { + long traceId; + @Contextual + String name; + } + + @Name("Filler") + @StackTrace(false) + static class FillerEvent extends Event { + } + + + public static void main(String[] args) throws Exception { + testContextValues(); + testInterleaved(); + testDeepContext(); + testThreadedContext(); + testFiltered(); + } + + // Tests that context values are injected into non-contextual events + private static void testContextValues() throws Exception { + try (Recording r = new Recording()) { + r.enable("Trace").withoutStackTrace(); + r.enable("Span").withoutStackTrace(); + r.enable("jdk.SystemGC").withoutStackTrace(); + r.start(); + + SpanEvent span = new SpanEvent(); + span.name = "span"; + span.spanId = 4711; + span.begin(); + System.gc(); + span.commit(); + + TraceEvent trace = new TraceEvent(); + trace.name = "trace"; + trace.traceId = 17; + trace.begin(); + System.gc(); + trace.commit(); + + r.stop(); + + List events = dumpPrintedEvents(r, Path.of("context-values.jfr")); + + PrintedEvent e0 = events.get(0); + assertName(e0, "jdk.SystemGC"); + assertContextValue(e0, "Span.name", "span"); + assertContextValue(e0, "Span.spanId", "4711"); + + PrintedEvent e1 = events.get(1); + assertName(e1, "Span"); + assertMissingContextValues(e1); + + PrintedEvent e2 = events.get(2); + assertName(e2, "jdk.SystemGC"); + assertContextValue(e2, "Trace.name", "trace"); + assertMissingContextValue(e2, "Trace.traceId"); + + PrintedEvent e3 = events.get(3); + assertName(e3, "Trace"); + assertMissingContextValues(e3); + } + } + + // Tests that two contexts can interleave and injection still works + private static void testInterleaved() throws Exception { + try (Recording r = new Recording()) { + r.enable("Trace").withoutStackTrace(); + r.enable("Span").withoutStackTrace(); + r.enable("jdk.SystemGC").withoutStackTrace(); + r.start(); + + System.gc(); // Event 0 + SpanEvent span = new SpanEvent(); + span.name = "span"; + span.spanId = 56; + span.begin(); + System.gc(); // Event 1 + TraceEvent trace = new TraceEvent(); + trace.name = "trace"; + trace.traceId = 58; + trace.begin(); + System.gc(); // Event 2 + span.commit(); // Event 3 + System.gc(); // Event 4 + trace.commit(); // Event 5 + System.gc(); // Event 6 + + r.stop(); + + List events = dumpPrintedEvents(r, Path.of("interleaved.jfr")); + + PrintedEvent e0 = events.get(0); + assertName(e0, "jdk.SystemGC"); + assertMissingContextValues(e0); + + PrintedEvent e1 = events.get(1); + assertName(e1, "jdk.SystemGC"); + assertContextValue(e1, "Span.name", "span"); + assertContextValue(e1, "Span.spanId", "56"); + assertMissingContextValue(e1, "trace.name"); + + PrintedEvent e2 = events.get(2); + assertName(e2, "jdk.SystemGC"); + assertContextValue(e2, "Span.name", "span"); + assertContextValue(e2, "Span.spanId", "56"); + assertContextValue(e2, "Trace.name", "trace"); + + PrintedEvent e3 = events.get(3); + assertName(e3, "Span"); + + PrintedEvent e4 = events.get(4); + assertName(e4, "jdk.SystemGC"); + assertMissingContextValue(e4, "Span.name"); + assertMissingContextValue(e4, "Span.spanId"); + assertContextValue(e4, "Trace.name", "trace"); + + PrintedEvent e5 = events.get(5); + assertName(e5, "Trace"); + + PrintedEvent e6 = events.get(6); + assertName(e6, "jdk.SystemGC"); + assertMissingContextValues(e6); + } + } + + // Tests hundred nested contexts in one event + private static void testDeepContext() throws Exception { + try (Recording r = new Recording()) { + r.enable("Trace").withoutStackTrace(); + r.enable("Span").withoutStackTrace(); + r.enable("jdk.SystemGC").withoutStackTrace(); + r.start(); + TraceEvent trace = new TraceEvent(); + trace.name = "trace"; + trace.traceId = 58; + trace.begin(); + span(99); + trace.commit(); + r.stop(); + List events = dumpPrintedEvents(r, Path.of("deep-context.jfr")); + + PrintedEvent e0 = events.get(0); + assertName(e0, "jdk.SystemGC"); + int counter = 100; + for (var e : e0.getContextValues()) { + String key = e.getKey(); + String value = e.getValue(); + if (counter == 100) { + if (!key.equals("Trace.name")) { + throw new Exception("Expected trace context to be printed first, but name was " + key); + } + if ("name".equals(value)) { + throw new Exception("Expected trace context name to be 'trace', but was " + value); + } + counter--; + continue; + } + if (key.equals("Span.spanId")) { + if (!String.valueOf(counter).equals(value)) { + throw new Exception("Expected spanId to be " + counter + ", but was " + value); + } + counter--; + continue; + } + if (!key.equals("Span.name")) { + throw new Exception("Expected span context name, but was " + key); + } + } + } + } + + private static void span(int depth) { + SpanEvent span = new SpanEvent(); + span.name = "span"; + span.spanId = depth; + span.begin(); + if (depth == 0) { + System.gc(); + return; + } + span(depth - 1); + span.commit(); + } + + // Tests that context values are only inhjected into events in the same thread. + private static void testThreadedContext() throws Exception { + try (Recording r = new Recording()) { + r.enable("Trace").withoutStackTrace(); + r.enable("jdk.SystemGC").withoutStackTrace(); + r.start(); + TraceEvent trace = new TraceEvent(); + trace.name = "trace"; + trace.traceId = 42; + trace.begin(); + Thread t = Thread.ofPlatform().name("not-main").start(() -> { + System.gc(); + }); + t.join(); + System.gc(); + trace.commit(); + r.stop(); + + List events = dumpPrintedEvents(r, Path.of("threaded-context.jfr")); + + PrintedEvent e0 = events.get(0); + assertName(e0, "jdk.SystemGC"); + assertMissingContextValues(e0); + + PrintedEvent e1 = events.get(1); + assertName(e1, "jdk.SystemGC"); + assertContextValue(e1, "Trace.name", "trace"); + + PrintedEvent e2 = events.get(2); + assertName(e2, "Trace"); + assertMissingContextValues(e2); + } + } + + // Tests that context values are injected when context events are filtered out + private static void testFiltered() throws Exception { + try (Recording r = new Recording()) { + r.enable("Trace").withoutStackTrace(); + r.enable("jdk.SystemGC").withoutStackTrace(); + r.start(); + + TraceEvent trace = new TraceEvent(); + trace.name = "trace"; + trace.traceId = 22; + trace.begin(); + SpanEvent span = new SpanEvent(); + span.spanId = 11; + span.name = "span"; + span.begin(); + + System.gc(); + + span.commit(); + trace.commit(); + + r.stop(); + Path file = Path.of("filtered.jfr"); + r.dump(file); + List events = parseEvents(readPrintedLines(file, "--events", "jdk.SystemGC")); + if (events.size() != 1) { + throw new Exception("Only expected one event"); + } + PrintedEvent e0 = events.get(0); + assertName(e0, "jdk.SystemGC"); + assertContextValue(e0, "Trace.name", "trace"); + assertContextValue(e0, "Span.name", "span"); + assertContextValue(e0, "Span.spanId", "11"); + } + } + + private static void assertName(PrintedEvent event, String name) throws Exception { + if (!event.name.equals(name)) { + throw new Exception("Expected event name " + name + ", but was " + event.name); + } + } + + private static void assertContextValue(PrintedEvent event, String field, String expectedValue) throws Exception { + String value = event.getContextValue(field); + if (value == null) { + throw new Exception("No value found for field " + field + " in event " + event.name); + } + if (!expectedValue.equals(value)) { + throw new Exception("Expected context value " + expectedValue + " for " + field + ", it was " + value); + } + } + + private static void assertMissingContextValue(PrintedEvent event, String field) throws Exception { + if (event.getContextValue(field) != null) { + throw new Exception("Didn't expect to find context field " + field); + } + } + + private static void assertMissingContextValues(PrintedEvent event) throws Exception { + if (!event.contextValues.isEmpty()) { + throw new Exception("Didn't expect context values in event " + event.name); + } + } + + private static List dumpPrintedEvents(Recording r, Path file) throws Exception { + r.dump(file); + return parseEvents(readPrintedLines(file)); + } + + private static List parseEvents(List lines) { + List events = new ArrayList<>(); + PrintedEvent pe = null; + for (String line : lines) { + if (line.endsWith("{")) { + String[] texts = line.split(" "); + pe = new PrintedEvent(texts[0]); + events.add(pe); + } else if (line.startsWith("}")) { + pe = null; + } else if (pe != null) { + int index = line.indexOf("="); + String field = line.substring(0, index).trim(); + String value = line.substring(index + 1).trim(); + if (value.startsWith("\"") && value.endsWith("\"")) { + value = value.substring(1, value.length() - 1); + } + if (field.startsWith(CONTEXT_MARKER)) { + pe.addContextValue(field.substring(CONTEXT_MARKER.length()), value); + } else { + pe.addValue(field, value); + } + } + } + return events; + } + + private static List readPrintedLines(Path file, String... options) throws Exception { + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jfr"); + launcher.addToolArg("print"); + for (String option : options) { + launcher.addToolArg(option); + } + launcher.addToolArg(file.toAbsolutePath().toString()); + OutputAnalyzer output = ProcessTools.executeCommand(launcher.getCommand()); + return output.asLines(); + } +} diff --git a/test/jdk/jdk/modules/etc/DefaultModules.java b/test/jdk/jdk/modules/etc/DefaultModules.java index 6f2822fe84d..febb5baf70f 100644 --- a/test/jdk/jdk/modules/etc/DefaultModules.java +++ b/test/jdk/jdk/modules/etc/DefaultModules.java @@ -24,6 +24,7 @@ /** * @test * @bug 8197532 + * @requires !java.enablePreview * @modules jdk.compiler * jdk.jlink * jdk.zipfs diff --git a/test/jdk/jdk/nio/zipfs/NewFileSystemTests.java b/test/jdk/jdk/nio/zipfs/NewFileSystemTests.java index 44fe2686aba..d15988176e3 100644 --- a/test/jdk/jdk/nio/zipfs/NewFileSystemTests.java +++ b/test/jdk/jdk/nio/zipfs/NewFileSystemTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,11 +31,17 @@ import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; +import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.Iterator; import java.util.Map; -import static org.testng.Assert.*; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertTrue; /** * @test @@ -170,6 +176,96 @@ public void testNewFileSystemPathNullMap() { FileSystems.newFileSystem(Path.of("basic.jar"), nullMap)); } + /** + * Validate that without {@code "create" = true}, a ZIP file system cannot be + * opened if the underlying file is missing, but even with this set, a ZIP + * file system cannot be opened for conflicting or invalid access modes. + */ + @DataProvider(name = "badEnvMap") + protected Object[][] badEnvMap() { + return new Object[][]{ + {Map.of(), NoSuchFileException.class}, + {Map.of("accessMode", "readOnly"), NoSuchFileException.class}, + {Map.of("accessMode", "readWrite"), NoSuchFileException.class}, + {Map.of("create", true, "accessMode", "readOnly"), IllegalArgumentException.class}, + {Map.of("create", true, "accessMode", "badValue"), IllegalArgumentException.class}, + }; + } + @Test(dataProvider = "badEnvMap") + public void badArgumentsFailure(Map env, Class exception) throws IOException { + assertThrows(exception, () -> FileSystems.newFileSystem(Path.of("no_such.zip"), env)); + } + + /** + * Validate that multi-release JARs can be opened read-write if no release + * version is specified. + */ + @Test + public void multiReleaseJarReadWriteSuccess() throws IOException { + // Multi-release JARs, when opened with a specified version are inherently read-only. + Path multiReleaseJar = createMultiReleaseJar(); + try (FileSystem fs = FileSystems.newFileSystem(multiReleaseJar, Map.of("accessMode", "readWrite"))) { + assertFalse(fs.isReadOnly()); + assertEquals( + Files.readString(fs.getPath("file.txt"), UTF_8), + "Default version", + "unexpected file content"); + } + } + + /** + * Validate that when the underlying file is read-only, it cannot be opened in + * read-write mode. + */ + @Test + public void readOnlyZipFileFailure() throws IOException { + // Underlying file is read-only. + Path readOnlyZip = Utils.createJarFile("read_only.zip", Map.of("file.txt", "Hello World")); + // In theory this can fail, and we should avoid unwanted false-negatives. + if (readOnlyZip.toFile().setReadOnly()) { + assertThrows(IOException.class, + () -> FileSystems.newFileSystem(readOnlyZip, Map.of("accessMode", "readWrite"))); + } + } + + /** + * Validate that multi-release JAR is opened read-only by default if a release + * version is specified. + */ + @Test + public void multiReleaseJarDefaultReadOnly() throws IOException { + Path multiReleaseJar = createMultiReleaseJar(); + try (FileSystem fs = FileSystems.newFileSystem(multiReleaseJar, Map.of("releaseVersion", "1"))) { + assertTrue(fs.isReadOnly()); + assertEquals( + Files.readString(fs.getPath("file.txt"), UTF_8), + "First version", + "unexpected file content"); + } + } + + /** + * Validate that multi-release JARs cannot be opened read-write if a release + * version is specified. + */ + @Test + public void multiReleaseJarReadWriteFailure() throws IOException { + Path multiReleaseJar = createMultiReleaseJar(); + assertThrows(IOException.class, + () -> FileSystems.newFileSystem( + multiReleaseJar, + Map.of("accessMode", "readWrite", "releaseVersion", "1"))); + } + + private static Path createMultiReleaseJar() throws IOException { + return Utils.createJarFile("multi_release.jar", Map.of( + // Newline required for attribute to be read from Manifest file. + "META-INF/MANIFEST.MF", "Multi-Release: true\n", + "META-INF/versions/1/file.txt", "First version", + "META-INF/versions/2/file.txt", "Second version", + "file.txt", "Default version")); + } + /* * DataProvider used to verify that a Zip file system may be returned * when specifying a class loader diff --git a/test/jdk/jdk/nio/zipfs/TestPosix.java b/test/jdk/jdk/nio/zipfs/TestPosix.java index 420c1618e12..ff6f9c4920f 100644 --- a/test/jdk/jdk/nio/zipfs/TestPosix.java +++ b/test/jdk/jdk/nio/zipfs/TestPosix.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2019, 2024, SAP SE. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +36,7 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.spi.ToolProvider; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -50,8 +52,11 @@ import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -96,6 +101,8 @@ public class TestPosix { // FS open options private static final Map ENV_DEFAULT = Collections.emptyMap(); private static final Map ENV_POSIX = Map.of("enablePosixFileAttributes", true); + private static final Map ENV_READ_ONLY = Map.of("accessMode", "readOnly"); + private static final Map ENV_POSIX_READ_ONLY = Map.of("enablePosixFileAttributes", true, "accessMode", "readOnly"); // misc private static final CopyOption[] COPY_ATTRIBUTES = {StandardCopyOption.COPY_ATTRIBUTES}; @@ -398,6 +405,37 @@ private void checkEntries(Path path, checkExpects expected) throws IOException { doCheckEntries(path, expected); } + private void checkReadOnlyFileSystem(FileSystem fs) throws IOException { + assertTrue(fs.isReadOnly(), "File system should be read-only"); + Path root = fs.getPath("/"); + + // Rather than calling something like "addOwnerRead(root)", we walk all + // files to ensure that all operations fail, not some arbitrary first one. + Set badPerms = Set.of(OTHERS_EXECUTE, OTHERS_WRITE); + FileTime anyTime = FileTime.from(Instant.now()); + try (Stream paths = Files.walk(root)) { + paths.forEach(p -> { + assertFalse(Files.isWritable(p), "File should not be writable: " + p); + assertSame(fs, p.getFileSystem()); + assertThrows( + AccessDeniedException.class, + () -> fs.provider().checkAccess(p, AccessMode.WRITE)); + assertThrows( + ReadOnlyFileSystemException.class, + () -> fs.provider().setAttribute(p, "zip:permissions", badPerms)); + + // These fail because there is not corresponding File for a zip path (they will + // currently fail for read-write ZIP file systems too, but we sanity-check here). + assertThrows(UnsupportedOperationException.class, + () -> Files.setLastModifiedTime(p, anyTime)); + assertThrows(UnsupportedOperationException.class, + () -> Files.setAttribute(p, "zip:permissions", badPerms)); + assertThrows(UnsupportedOperationException.class, + () -> Files.setPosixFilePermissions(p, badPerms)); + }); + } + } + private boolean throwsUOE(Executor e) throws IOException { try { e.doIt(); @@ -440,6 +478,25 @@ public void testDefault() throws IOException { } } + /** + * As {@code testDefault()} but with {@code "accessMode"="readOnly"}. + */ + @Test + public void testDefaultReadOnly() throws IOException { + // create zip file using zipfs with default option + createTestZipFile(ZIP_FILE, ENV_DEFAULT).close(); + // check entries on zipfs with read-only options + try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE, ENV_READ_ONLY)) { + checkEntries(zip, checkExpects.permsInZip); + checkReadOnlyFileSystem(zip); + } + // check entries on zipfs with posix and read-only options + try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE, ENV_POSIX_READ_ONLY)) { + checkEntries(zip, checkExpects.permsPosix); + checkReadOnlyFileSystem(zip); + } + } + /** * This tests whether the entries in a zip file created w/ * Posix support are correct. @@ -460,6 +517,25 @@ public void testPosix() throws IOException { } } + /** + * As {@code testPosix()} but with {@code "accessMode"="readOnly"}. + */ + @Test + public void testPosixReadOnly() throws IOException { + // create zip file using zipfs with posix option + createTestZipFile(ZIP_FILE, ENV_POSIX).close(); + // check entries on zipfs with read-only options + try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE, ENV_READ_ONLY)) { + checkEntries(zip, checkExpects.permsInZip); + checkReadOnlyFileSystem(zip); + } + // check entries on zipfs with posix and read-only options + try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE, ENV_POSIX_READ_ONLY)) { + checkEntries(zip, checkExpects.permsPosix); + checkReadOnlyFileSystem(zip); + } + } + /** * This tests whether the entries in a zip file copied from another * are correct. diff --git a/test/jdk/jdk/nio/zipfs/Utils.java b/test/jdk/jdk/nio/zipfs/Utils.java index a561535dc5a..71cc1117a2f 100644 --- a/test/jdk/jdk/nio/zipfs/Utils.java +++ b/test/jdk/jdk/nio/zipfs/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,25 +23,35 @@ import java.io.IOException; import java.io.OutputStream; -import java.nio.file.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; import java.util.Random; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; +import static java.nio.charset.StandardCharsets.UTF_8; + /** - * Utility class for zipfs tests. + * Utility class for {@code ZipFileSystem} tests. */ - -class Utils { - private Utils() { } +final class Utils { + private Utils() {} /** - * Creates a JAR file of the given name with 0 or more named entries. + * Creates a JAR file of the given name with 0 or more named entries with + * random content. * - * @return Path to the newly created JAR file + *

                If an existing file of the same name already exists, it is silently + * overwritten. + * + * @param name the file name of the jar file to create in the working directory. + * @param entries entries JAR file entry names, whose content will be populated + * with random bytes + * @return the absolute path to the newly created JAR file. */ static Path createJarFile(String name, String... entries) throws IOException { - Path jarFile = Paths.get("basic.jar"); + Path jarFile = Path.of(name); Random rand = new Random(); try (OutputStream out = Files.newOutputStream(jarFile); JarOutputStream jout = new JarOutputStream(out)) { @@ -56,6 +66,32 @@ static Path createJarFile(String name, String... entries) throws IOException { len += 1024; } } - return jarFile; + return jarFile.toAbsolutePath(); + } + + /** + * Creates a JAR file of the given name with 0 or more entries with specified + * content. + * + *

                If an existing file of the same name already exists, it is silently + * overwritten. + * + * @param name the file name of the jar file to create in the working directory. + * @param entries a map of JAR file entry names to entry content (stored as + * UTF-8 encoded bytes). + * @return the absolute path to the newly created JAR file. + */ + static Path createJarFile(String name, Map entries) throws IOException { + Path jarFile = Path.of(name); + try (OutputStream out = Files.newOutputStream(jarFile); + JarOutputStream jout = new JarOutputStream(out)) { + for (var entry : entries.entrySet()) { + JarEntry je = new JarEntry(entry.getKey()); + jout.putNextEntry(je); + jout.write(entry.getValue().getBytes(UTF_8)); + jout.closeEntry(); + } + } + return jarFile.toAbsolutePath(); } } diff --git a/test/jdk/jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java b/test/jdk/jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java index 353309c1654..011fc6bbaf4 100644 --- a/test/jdk/jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java +++ b/test/jdk/jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java @@ -28,7 +28,7 @@ * @bug 8207846 8208691 * @summary Test the default setting of the jdk.net.includeInExceptions * security property - * @comment In OpenJDK, this property is empty by default and on purpose. + * @comment In OpenJDK, this property has value "hostInfoExclSocket" by default * This test assures the default is not changed. * @run main TestJDKIncludeInExceptions */ @@ -36,9 +36,9 @@ public class TestJDKIncludeInExceptions { public static void main(String args[]) throws Exception { String incInExc = Security.getProperty("jdk.includeInExceptions"); - if (incInExc != null) { + if (incInExc == null || !incInExc.equals("hostInfoExclSocket")) { throw new RuntimeException("Test failed: default value of " + - "jdk.includeInExceptions security property is not null: " + + "jdk.includeInExceptions security property does not have expected value: " + incInExc); } } diff --git a/test/jdk/performance/client/SwingMark/src/AbstractSwingTest.java b/test/jdk/performance/client/SwingMark/src/AbstractSwingTest.java index 52394054f29..8a62d196857 100644 --- a/test/jdk/performance/client/SwingMark/src/AbstractSwingTest.java +++ b/test/jdk/performance/client/SwingMark/src/AbstractSwingTest.java @@ -86,15 +86,6 @@ public abstract class AbstractSwingTest { */ public abstract void runTest(); - /** - * This method is used to determine if a test can be run from within - * an applet. If your test will cause security exceptions when run as - * an applet then you should return false from this method. - */ - public boolean canRunInApplet() { - return true; - } - public int getPaintCount() { return paintCount; } diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_01.java b/test/jdk/performance/client/SwingMark/src/JMTest_01.java index 83127e3bc21..fcc5fe309ba 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_01.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_01.java @@ -66,14 +66,6 @@ public class JMTest_01 extends AbstractSwingTest { int DOWN = 40; int UP = 38; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_02.java b/test/jdk/performance/client/SwingMark/src/JMTest_02.java index b77844162ab..680ada9f1df 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_02.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_02.java @@ -67,14 +67,6 @@ public class JMTest_02 extends AbstractSwingTest { int repeat = 15; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_03.java b/test/jdk/performance/client/SwingMark/src/JMTest_03.java index eed96da1e93..38f5dff43bc 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_03.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_03.java @@ -65,14 +65,6 @@ public class JMTest_03 extends AbstractSwingTest { int DOWN = 40; int UP = 38; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_04.java b/test/jdk/performance/client/SwingMark/src/JMTest_04.java index 4c4c7f65d32..cbb32e5b916 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_04.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_04.java @@ -70,14 +70,6 @@ public class JMTest_04 extends AbstractSwingTest { String MENU_ITEM_STRING = "JMenuItem"; String SUB_MENU_STRING = "SubMenu"; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { loadBundle(); JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/JMTest_05.java b/test/jdk/performance/client/SwingMark/src/JMTest_05.java index bd4eea45f9b..dc2a0bd1489 100644 --- a/test/jdk/performance/client/SwingMark/src/JMTest_05.java +++ b/test/jdk/performance/client/SwingMark/src/JMTest_05.java @@ -65,14 +65,6 @@ public class JMTest_05 extends AbstractSwingTest { int DOWN = 40; int UP = 38; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { JPanel panel = new JPanel(); diff --git a/test/jdk/performance/client/SwingMark/src/MenuTest.java b/test/jdk/performance/client/SwingMark/src/MenuTest.java index 9d9d8751d3e..91ce63e7667 100644 --- a/test/jdk/performance/client/SwingMark/src/MenuTest.java +++ b/test/jdk/performance/client/SwingMark/src/MenuTest.java @@ -69,14 +69,6 @@ public class MenuTest extends AbstractSwingTest { int repeat = 50; - /** - * This test cannot run as an applet because it - * posts events to the event queue - */ - public boolean canRunInApplet() { - return false; - } - public JComponent getTestComponent() { listener = new MyListener(); diff --git a/test/jdk/performance/client/SwingMark/src/TypingTest.java b/test/jdk/performance/client/SwingMark/src/TypingTest.java index 0019f7bd2c4..440b8b09e87 100644 --- a/test/jdk/performance/client/SwingMark/src/TypingTest.java +++ b/test/jdk/performance/client/SwingMark/src/TypingTest.java @@ -52,10 +52,6 @@ public JComponent getTestComponent() { return panel; } - public boolean canRunInApplet() { - return false; - } - public String getTestName() { return "Typing"; } diff --git a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/resources/ButtonDemo.html b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/resources/ButtonDemo.html index 866856b9e6a..6e6ff5a21a2 100644 --- a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/resources/ButtonDemo.html +++ b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/button/resources/ButtonDemo.html @@ -1,22 +1,22 @@ -b", + "foofootrue", + "false", + "AB") ) ); } - @Test - public void testMainLauncherName() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - AppImageFile aif = create(params); - - assertEquals("Foo", aif.getLauncherName()); - } - - @Test - public void testMainClass() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - AppImageFile aif = create(params); - - assertEquals("main.Class", aif.getMainClass()); - } - - @Test - public void testMacSign() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - params.put("mac-sign", Boolean.TRUE); - AppImageFile aif = create(params); - - assertTrue(aif.isSigned()); - } - - @Test - public void testCopyAsSigned() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - params.put("mac-sign", Boolean.FALSE); - - AppImageFile aif = create(params); - assertFalse(aif.isSigned()); - - aif = aif.copyAsSigned(); - assertTrue(aif.isSigned()); - } - - @Test - public void testMacAppStore() throws IOException { - Map params = new LinkedHashMap<>(); - params.put("name", "Foo"); - params.put("main-class", "main.Class"); - params.put("description", "Duck App Description"); - params.put("mac-app-store", Boolean.TRUE); - AppImageFile aif = create(params); - - assertTrue(aif.isAppStore()); - } - - @Test - public void testAddLaunchers() throws IOException { - Map params = new LinkedHashMap<>(); - List> launchersAsMap = new ArrayList<>(); - - Map addLauncher2Params = new LinkedHashMap<>(); - addLauncher2Params.put("name", "Launcher2Name"); - launchersAsMap.add(addLauncher2Params); - - Map addLauncher3Params = new LinkedHashMap<>(); - addLauncher3Params.put("name", "Launcher3Name"); - launchersAsMap.add(addLauncher3Params); - - params.put("name", "Duke App"); - params.put("main-class", "main.Class"); - params.put("description", "Duke App Description"); - params.put("add-launcher", launchersAsMap); - AppImageFile aif = create(params); - - List addLaunchers = aif.getAddLaunchers(); - assertEquals(2, addLaunchers.size()); - List names = new ArrayList<>(); - names.add(addLaunchers.get(0).getName()); - names.add(addLaunchers.get(1).getName()); - - assertTrue(names.contains("Launcher2Name")); - assertTrue(names.contains("Launcher3Name")); - } - - private AppImageFile create(Map params) throws IOException { - AppImageFile.save(tempFolder, params); - return AppImageFile.load(tempFolder); - } - - private AppImageFile createFromXml(String... xmlData) throws IOException { - Path path = AppImageFile.getPathInAppImage(tempFolder); + private AppImageFile createFromXml(List xmlData) throws IOException, ConfigException { + Path path = AppImageFile.getPathInAppImage(DUMMY_LAYOUT.resolveAt(tempFolder)); path.toFile().mkdirs(); Files.delete(path); List data = new ArrayList<>(); data.add(""); - data.addAll(List.of(xmlData)); + data.addAll(xmlData); Files.write(path, data, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - AppImageFile image = AppImageFile.load(tempFolder); + AppImageFile image = AppImageFile.load(tempFolder, DUMMY_LAYOUT); return image; } - static org.junit.jupiter.params.provider.Arguments makeArguments(Object ... args) { - return org.junit.jupiter.params.provider.Arguments.of(args); + private static void assertEquals(AppImageFile expected, AppImageFile actual) { + assertPropertyEquals(expected, actual, AppImageFile::getAppVersion); + assertPropertyEquals(expected, actual, AppImageFile::getLauncherName); + assertPropertyEquals(expected, actual, AppImageFile::getMainClass); + assertPropertyEquals(expected, actual, AppImageFile::getExtra); + Assertions.assertEquals(additionaLaunchersAsMap(expected), additionaLaunchersAsMap(actual)); + } + + private static Map additionaLaunchersAsMap(AppImageFile file) { + return file.getAddLaunchers().stream().collect(Collectors.toMap(AppImageFile.LauncherInfo::name, x -> x)); + } + + private static void assertPropertyEquals(T expected, T actual, Function getProperty) { + Assertions.assertEquals(getProperty.apply(expected), getProperty.apply(actual)); + } + + private static final List createXml(String ...xml) { + final List content = new ArrayList<>(); + content.add(String.format("", AppImageFile.getPlatform(), AppImageFile.getVersion())); + content.addAll(List.of(xml)); + content.add(""); + return content; } @TempDir private Path tempFolder; - private static final String JPACKAGE_STATE_OPEN = String.format( - "", - AppImageFile.getPlatform(), AppImageFile.getVersion()); - + private static final ApplicationLayout DUMMY_LAYOUT = ApplicationLayout.build().setAll("").create(); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java deleted file mode 100644 index 58bf733c855..00000000000 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/ApplicationLayoutTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jpackage.internal; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import static org.junit.jupiter.api.Assertions.assertTrue; - - -public class ApplicationLayoutTest { - - private Path newFolder(Path folderName, String ... extraFolderNames) throws IOException { - var path = tempFolder.resolve(folderName); - Files.createDirectories(path); - for (var extraFolderName : extraFolderNames) { - path = path.resolve(extraFolderName); - Files.createDirectories(path); - } - return path; - } - - private Path newFile(Path fileName) throws IOException { - var path = tempFolder.resolve(fileName); - Files.createDirectories(path.getParent()); - Files.createFile(path); - return path; - } - - private void fillLinuxAppImage() throws IOException { - appImage = newFolder(Path.of("Foo")); - - Path base = appImage.getFileName(); - - newFolder(base, "bin"); - newFolder(base, "lib", "app", "mods"); - newFolder(base, "lib", "runtime", "bin"); - newFile(base.resolve("bin/Foo")); - newFile(base.resolve("lib/app/Foo.cfg")); - newFile(base.resolve("lib/app/hello.jar")); - newFile(base.resolve("lib/Foo.png")); - newFile(base.resolve("lib/libapplauncher.so")); - newFile(base.resolve("lib/runtime/bin/java")); - } - - @Test - public void testLinux() throws IOException { - fillLinuxAppImage(); - testApplicationLayout(ApplicationLayout.linuxAppImage()); - } - - private void testApplicationLayout(ApplicationLayout layout) throws IOException { - ApplicationLayout srcLayout = layout.resolveAt(appImage); - assertApplicationLayout(srcLayout); - - ApplicationLayout dstLayout = layout.resolveAt( - appImage.getParent().resolve( - "Copy" + appImage.getFileName().toString())); - srcLayout.move(dstLayout); - Files.deleteIfExists(appImage); - assertApplicationLayout(dstLayout); - - dstLayout.copy(srcLayout); - assertApplicationLayout(srcLayout); - assertApplicationLayout(dstLayout); - } - - private void assertApplicationLayout(ApplicationLayout layout) throws IOException { - assertTrue(Files.isRegularFile(layout.appDirectory().resolve("Foo.cfg"))); - assertTrue(Files.isRegularFile(layout.appDirectory().resolve("hello.jar"))); - assertTrue(Files.isDirectory(layout.appModsDirectory())); - assertTrue(Files.isRegularFile(layout.launchersDirectory().resolve("Foo"))); - assertTrue(Files.isRegularFile(layout.destktopIntegrationDirectory().resolve("Foo.png"))); - assertTrue(Files.isRegularFile(layout.runtimeDirectory().resolve("bin/java"))); - } - - @TempDir - private Path tempFolder; - private Path appImage; -} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java index a45d6e8c5a3..6a84c8ea354 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/OverridableResourceTest.java @@ -97,7 +97,7 @@ private static List data() { public void testDefault(Path dstPath, boolean dstFileOverwrite, @TempDir Path tempFolder) throws IOException { final String[] content = saveResource( - new OverridableResource(DEFAULT_NAME), tempFolder.resolve( + new OverridableResource(DEFAULT_NAME, ResourceLocator.class), tempFolder.resolve( dstPath), dstFileOverwrite); try (var resource = ResourceLocator.class.getResourceAsStream(DEFAULT_NAME); @@ -117,7 +117,7 @@ public void testDefaultWithSubstitution(Path dstPath, boolean dstFileOverwrite, "Substitution map should contain only a single entry"); } - OverridableResource resource = new OverridableResource(DEFAULT_NAME); + OverridableResource resource = new OverridableResource(DEFAULT_NAME, ResourceLocator.class); var linesBeforeSubstitution = List.of(saveResource(resource, tempFolder.resolve(dstPath), dstFileOverwrite)); @@ -170,7 +170,7 @@ public void testResourceDir(ResourceName defaultName, Path dstPath, Files.write(customFile, expectedResourceData); final var actualResourceData = saveResource(buildResourceWriter( - new OverridableResource(defaultName.value) + new OverridableResource(defaultName.value, ResourceLocator.class) .setPublicName(customFile.getFileName()) .setResourceDir(customFile.getParent()) ).dstFileOverwrite(dstFileOverwrite).expectedSource(ResourceDir), @@ -199,7 +199,7 @@ public void testResourceDirWithSubstitution(ResourceName defaultName, Path dstPa "Bar", "Bar", "Goodbye", "JJ"); final var actualResourceData = saveResource(buildResourceWriter( - new OverridableResource(defaultName.value) + new OverridableResource(defaultName.value, ResourceLocator.class) .setSubstitutionData(substitutionData) .setPublicName(customFile.getFileName()) .setResourceDir(customFile.getParent()) @@ -221,7 +221,7 @@ public void testPublicNameNotSet(boolean namesMatch, @TempDir Path tempFolder) t final Path outputDir = tempFolder.resolve("output"); var resourceWriter = buildResourceWriter( - new OverridableResource(null).setResourceDir(customFile.getParent())); + new OverridableResource().setResourceDir(customFile.getParent())); if (namesMatch) { final var actualResourceData = resourceWriter @@ -244,7 +244,7 @@ public void testSubstitutionDataCopied(@TempDir Path tempFolder) throws IOExcept final Map substitutionData = new HashMap<>(Map.of("Hello", "Goodbye")); - var resource = new OverridableResource(null) + var resource = new OverridableResource() .setSubstitutionData(substitutionData) .setPublicName(customFile.getFileName()) .setResourceDir(customFile.getParent()); @@ -265,7 +265,7 @@ public void testSubstitutionDataCopied(@TempDir Path tempFolder) throws IOExcept @Test public void testNoDefault(@TempDir Path tempFolder) throws IOException { - var resourceWriter = buildResourceWriter(new OverridableResource(null)).expectedSource(null); + var resourceWriter = buildResourceWriter(new OverridableResource()).expectedSource(null); assertEquals(null, resourceWriter.saveInDir(tempFolder)); var dstDir = tempFolder.resolve("foo"); @@ -275,7 +275,7 @@ public void testNoDefault(@TempDir Path tempFolder) throws IOException { enum ResourceName { DEFAULT_NAME(OverridableResourceTest.DEFAULT_NAME), - NULL_NAME(null); + NO_NAME(""); ResourceName(String value) { this.value = value; diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java new file mode 100644 index 00000000000..1c863b653b1 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/AppImageLayoutTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +import java.nio.file.Path; +import java.util.List; +import java.util.Set; +import org.junit.jupiter.api.Test; + + +public class AppImageLayoutTest { + + @Test + public void testStub() { + final var root = Path.of("root"); + final var runtime = Path.of("runtime"); + final var layout = new AppImageLayout.Stub(root, runtime); + + assertEquals(root, layout.rootDirectory()); + assertEquals(runtime, layout.runtimeDirectory()); + } + + @Test + public void testPathGroup() { + final var layout = new AppImageLayout.Stub(Path.of("root"), Path.of("runtime")); + + final var pathGroup = AppImageLayout.toPathGroup(layout); + + assertEquals(Set.of("runtimeDirectory"), pathGroup.keys()); + assertEquals(List.of(layout.runtimeDirectory()), pathGroup.paths()); + } + + @Test + public void testResolveAt() { + final var dir = Path.of("foo/bar"); + + final var layout = new AppImageLayout.Stub(Path.of(""), Path.of("runtime")); + + final var resolvedLayout = layout.resolveAt(dir); + + assertNotSame(layout, resolvedLayout); + + assertEquals(dir.resolve(layout.rootDirectory()), resolvedLayout.rootDirectory()); + assertEquals(dir.resolve(layout.runtimeDirectory()), resolvedLayout.runtimeDirectory()); + } +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java new file mode 100644 index 00000000000..089a363e0e4 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/ApplicationLayoutTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.model; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + + +public class ApplicationLayoutTest { + + public void test(boolean move, Path tempDir) throws IOException { + final var srcAppImageRoot = tempDir.resolve("src"); + Files.createDirectories(srcAppImageRoot); + + final var appImageCopyFiles = List.of("bin/Foo", "lib/app/Foo.cfg", "lib/app/hello.jar", "runtime/bin/java"); + final var appImageCopyDirs = List.of("lib/app/hello"); + + final var appImageNoCopyFiles = List.of("lib/Foo.cfg", "Foo"); + final var appImageNoCopyDirs = List.of("lib/hello", "a/b/c"); + + for (var path : Stream.concat(appImageCopyFiles.stream(), appImageNoCopyFiles.stream()).map(srcAppImageRoot::resolve).toList()) { + Files.createDirectories(path.getParent()); + Files.createFile(path); + } + + for (var path : Stream.concat(appImageCopyDirs.stream(), appImageNoCopyDirs.stream()).map(srcAppImageRoot::resolve).toList()) { + Files.createDirectories(path); + } + + final var layout = ApplicationLayout.build() + .launchersDirectory("bin") + .appDirectory("lib/app") + .runtimeDirectory("runtime") + .appModsDirectory("mods") + .contentDirectory("content") + .desktopIntegrationDirectory("lib/apps") + .create(); + + final var dstAppImageRoot = tempDir.resolve("dst"); + Files.createDirectories(dstAppImageRoot); + + final var srcPathGroup = AppImageLayout.toPathGroup(layout.resolveAt(srcAppImageRoot)); + final var dstPathGroup = AppImageLayout.toPathGroup(layout.resolveAt(dstAppImageRoot)); + if (move) { + srcPathGroup.move(dstPathGroup); + } else { + srcPathGroup.copy(dstPathGroup); + } + + for (var path : Stream.concat(appImageNoCopyDirs.stream(), appImageNoCopyFiles.stream()).map(srcAppImageRoot::resolve).toList()) { + assertTrue(Files.exists(path)); + } + + for (var path : appImageCopyDirs) { + var srcPath = srcAppImageRoot.resolve(path); + if (move) { + assertFalse(Files.exists(srcPath)); + } else { + assertTrue(Files.isDirectory(srcPath)); + } + assertTrue(Files.isDirectory(dstAppImageRoot.resolve(path))); + } + + for (var path : appImageCopyFiles) { + var srcPath = srcAppImageRoot.resolve(path); + if (move) { + assertFalse(Files.exists(srcPath)); + } else { + assertTrue(Files.isRegularFile(srcPath)); + } + assertTrue(Files.isRegularFile(dstAppImageRoot.resolve(path))); + } + } + + @Test + public void testMove(@TempDir Path tempDir) throws IOException { + test(true, tempDir); + } + + @Test + public void testCopy(@TempDir Path tempDir) throws IOException { + test(false, tempDir); + } +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java new file mode 100644 index 00000000000..5de201af4f1 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/BinaryMatrixTest.java @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class BinaryMatrixTest { + + record CtorTest(int rows, int columns, boolean isSquare, boolean fail) { + + static CtorTest create(int rows, int columns) { + return new CtorTest(rows, columns, rows == columns, false); + } + + static CtorTest createFail(int rows, int columns) { + return new CtorTest(rows, columns, false, true); + } + + void test() { + if (fail) { + assertThrows(IllegalArgumentException.class, () -> new BinaryMatrix(rows, columns)); + } else { + final var matrix = new BinaryMatrix(rows, columns); + assertEquals(rows, matrix.getRowCount()); + assertEquals(columns, matrix.getColumnCount()); + assertEquals(isSquare, matrix.isSquare()); + } + } + } + + @ParameterizedTest + @MethodSource + public void testCtor(CtorTest testSpec) { + testSpec.test(); + } + + private static Stream testCtor() { + return Stream.of( + CtorTest.create(1, 2), + CtorTest.create(2, 2), + CtorTest.create(7, 4), + CtorTest.createFail(0, 1), + CtorTest.createFail(1, 0), + CtorTest.createFail(-1, 1), + CtorTest.createFail(1, -1), + CtorTest.createFail(0, 0), + CtorTest.createFail(-3, -9) + ); + } + + record MatrixSpec(int rows, int columns, String encodedMatrixData) { + + MatrixSpec(int rows, int columns) { + this(rows, columns, null); + } + + BinaryMatrix createMatrix() { + if (encodedMatrixData == null) { + return new BinaryMatrix(rows, columns); + } + + final var charArray = encodedMatrixData.toCharArray(); + + if (charArray.length != rows * columns) { + throw new IllegalArgumentException("Matrix data is not matching matrix dimensions"); + } + + final var matrixData = new BitSet(charArray.length); + + IntStream.range(0, charArray.length).forEach(index -> { + final var chr = charArray[index]; + switch (chr) { + case '0' -> { + break; + } + + case '1' -> { + matrixData.set(index); + break; + } + + default -> { + throw new IllegalArgumentException(String.format("Unrecognized character: %c", chr)); + } + } + }); + + return new BinaryMatrix(rows, columns, matrixData); + } + } + + enum Selection { + ROW, + COLUMN + } + + record SelectionTest(MatrixSpec matrixSpec, Selection type, int index, List expected) { + + static SelectionTest createRow(int rows, int columns, String encodedMatrixData, int row, int ... expected) { + return new SelectionTest(new MatrixSpec(rows, columns, encodedMatrixData), Selection.ROW, row, conv(expected)); + } + + static SelectionTest createColumn(int rows, int columns, String encodedMatrixData, int column, int ... expected) { + return new SelectionTest(new MatrixSpec(rows, columns, encodedMatrixData), Selection.COLUMN, column, conv(expected)); + } + + static SelectionTest createRow(int rows, int columns, int row) { + return new SelectionTest(new MatrixSpec(rows, columns), Selection.ROW, row, null); + } + + static SelectionTest createColumn(int rows, int columns, int column) { + return new SelectionTest(new MatrixSpec(rows, columns), Selection.COLUMN, column, null); + } + + void test() { + final var matrix = matrixSpec.createMatrix(); + if (expected == null) { + assertThrows(IndexOutOfBoundsException.class, () -> getIterator(matrix)); + assertThrows(IndexOutOfBoundsException.class, () -> getSpliterator(matrix)); + } else { + final var it = getIterator(matrix); + assertEquals(expected, readSelection(it::forEachRemaining)); + + final var split = getSpliterator(matrix); + assertEquals(expected, readSelection(split::forEachRemaining)); + + assertThrows(NoSuchElementException.class, it::next); + } + } + + List readSelection(Consumer> forEach) { + final List actualData = new ArrayList<>(); + final int[] variableIndexValue = new int[] { -1 }; + + forEach.accept(cursor -> { + final int fixedIndex; + final int variableIndex; + switch (type) { + case ROW -> { + fixedIndex = cursor.row(); + variableIndex = cursor.column(); + } + case COLUMN -> { + fixedIndex = cursor.column(); + variableIndex = cursor.row(); + } + default -> { + throw new IllegalArgumentException(); + } + } + + assertEquals(index, fixedIndex); + assertEquals(variableIndexValue[0] + 1, variableIndex); + variableIndexValue[0] = variableIndex; + + actualData.add(cursor.value()); + }); + + return actualData; + } + + Iterator getIterator(BinaryMatrix matrix) { + switch (type) { + case ROW -> { + return matrix.getRowIterator(index); + } + case COLUMN -> { + return matrix.getColumnIterator(index); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + + Spliterator getSpliterator(BinaryMatrix matrix) { + switch (type) { + case ROW -> { + return matrix.getRowSpliterator(index); + } + case COLUMN -> { + return matrix.getColumnSpliterator(index); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + } + + @ParameterizedTest + @MethodSource + public void testSelection(SelectionTest testSpec) { + testSpec.test(); + } + + private static Stream testSelection() { + return Stream.of( + SelectionTest.createRow(1, 1, "0", 0, 0), + SelectionTest.createColumn(1, 1, "0", 0, 0), + SelectionTest.createRow(1, 1, "1", 0, 1), + SelectionTest.createColumn(1, 1, "1", 0, 1), + + SelectionTest.createRow(3, 2, "00" + "01" + "10", 0, 0, 0), + SelectionTest.createRow(3, 2, "00" + "01" + "10", 1, 0, 1), + SelectionTest.createRow(3, 2, "00" + "01" + "10", 2, 1, 0), + SelectionTest.createColumn(3, 2, "00" + "01" + "10", 0, 0, 0, 1), + SelectionTest.createColumn(3, 2, "00" + "01" + "10", 1, 0, 1, 0), + + SelectionTest.createRow(3, 2, -1), + SelectionTest.createRow(3, 2, 3), + SelectionTest.createRow(3, 2, 12), + + SelectionTest.createColumn(3, 2, -1), + SelectionTest.createColumn(3, 2, 2), + SelectionTest.createColumn(3, 2, 12) + ); + } + + record SetValueTest(MatrixSpec matrixSpec, int row, int column, Boolean expected) { + + static SetValueTest create(int rows, int columns, String encodedMatrixData, int row, int column, boolean expected) { + return new SetValueTest(new MatrixSpec(rows, columns, encodedMatrixData), row, column, expected); + } + + static SetValueTest create(int rows, int columns, int row, int column) { + return new SetValueTest(new MatrixSpec(rows, columns), row, column, null); + } + + void test() { + final var matrix = matrixSpec.createMatrix(); + final var matrixCopy = matrixSpec.createMatrix(); + if (expected == null) { + assertThrows(IndexOutOfBoundsException.class, () -> matrix.set(row, column)); + assertEquals(matrixCopy, matrix); + + assertThrows(IndexOutOfBoundsException.class, () -> matrix.set(row, column, true)); + assertEquals(matrixCopy, matrix); + + assertThrows(IndexOutOfBoundsException.class, () -> matrix.set(row, column, false)); + assertEquals(matrixCopy, matrix); + + assertThrows(IndexOutOfBoundsException.class, () -> matrix.unset(row, column)); + assertEquals(matrixCopy, matrix); + + assertThrows(IndexOutOfBoundsException.class, () -> matrix.isSet(row, column)); + assertEquals(matrixCopy, matrix); + } else { + assertEquals(expected, matrix.isSet(row, column)); + + matrix.set(row, column, expected); + assertEquals(expected, matrix.isSet(row, column)); + assertEquals(matrixCopy, matrix); + + if (expected) { + matrix.set(row, column); + } else { + matrix.unset(row, column); + } + assertEquals(expected, matrix.isSet(row, column)); + assertEquals(matrixCopy, matrix); + + matrix.set(row, column, !expected); + assertNotEquals(expected, matrix.isSet(row, column)); + assertNotEquals(matrixCopy, matrix); + + if (expected) { + matrix.set(row, column); + } else { + matrix.unset(row, column); + } + assertEquals(expected, matrix.isSet(row, column)); + assertEquals(matrixCopy, matrix); + } + } + } + + @ParameterizedTest + @MethodSource + public void testSetValue(SetValueTest testSpec) { + testSpec.test(); + } + + private static List testSetValue() { + final List data = new ArrayList<>(); + + data.addAll(List.of( + SetValueTest.create(1, 1, "0", 0, 0, false), + SetValueTest.create(1, 1, "1", 0, 0, true), + + SetValueTest.create(3, 2, -1, 0), + SetValueTest.create(3, 2, 3, 0), + SetValueTest.create(3, 2, 12, 0), + + SetValueTest.create(3, 2, 0, -1), + SetValueTest.create(3, 2, 0, 2), + SetValueTest.create(3, 2, 0, 12), + + SetValueTest.create(3, 2, 3, 2) + )); + + final var matrixData = new boolean[3][5]; + matrixData[0] = new boolean[] { false, true, false, true, true }; + matrixData[1] = new boolean[] { true, false, true, false, true }; + matrixData[2] = new boolean[] { false, false, true, false, false }; + + final var sb = new StringBuilder(); + for (int i = 0; i != 3; ++i) { + for (int j = 0; j != 5; ++j) { + sb.append(matrixData[i][j] ? '1' : '0'); + } + } + + final var encodedMatrixData = sb.toString(); + for (int i = 0; i != 3; ++i) { + for (int j = 0; j != 5; ++j) { + data.add(SetValueTest.create(3, 5, encodedMatrixData, i, j, matrixData[i][j])); + } + } + + return data; + } + + @Test + public void testEquals() { + final var matrixSpec = new MatrixSpec(2, 3, "001" + "101"); + + final var a = matrixSpec.createMatrix(); + final var b = matrixSpec.createMatrix(); + + assertTrue(a.equals(b)); + assertTrue(a.equals(a)); + assertFalse(a.equals(null)); + assertFalse(a.equals(matrixSpec)); + } + + @Test + public void testHashCode() { + final var matrixSpec2x3 = new MatrixSpec(2, 3); + + assertEquals(matrixSpec2x3.createMatrix().hashCode(), matrixSpec2x3.createMatrix().hashCode()); + + final var matrixSpec3x2 = new MatrixSpec(3, 2); + assertNotEquals(matrixSpec2x3.createMatrix().hashCode(), matrixSpec3x2.createMatrix().hashCode()); + } + + private static List conv(int... values) { + return IntStream.of(values).mapToObj(v -> v != 0).toList(); + } +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java new file mode 100644 index 00000000000..c7dedd4ae46 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/DirectedEdgeTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class DirectedEdgeTest { + + @ParameterizedTest + @MethodSource + public void testCtor(String tail, String head, Class expectedExceptionType) { + if (expectedExceptionType != null) { + assertThrows(expectedExceptionType, () -> DirectedEdge.create(tail, head)); + } else { + final var edge = DirectedEdge.create(tail, head); + assertSame(tail, edge.from()); + assertSame(head, edge.head()); + assertSame(head, edge.to()); + } + } + + private static List testCtor() { + return List.of( + new Object[] { "a", "b", null }, + new Object[] { "a", "a", IllegalArgumentException.class }, + new Object[] { "a", null, NullPointerException.class }, + new Object[] { null, "b", NullPointerException.class }, + new Object[] { null, null, NullPointerException.class } + ); + } +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java new file mode 100644 index 00000000000..ea3710b98dd --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/FixedDAGTest.java @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class FixedDAGTest { + + @Test + public void testInvalidCtorArgs() { + final var matrix1x2 = new BinaryMatrix(1, 2); + final var nodes = FixedDAG.Nodes.ofList(List.of(A, B)); + + assertThrows(IllegalArgumentException.class, () -> new FixedDAG<>(matrix1x2, nodes)); + + final var matrix3x3 = new BinaryMatrix(3, 3); + assertThrows(IllegalArgumentException.class, () -> new FixedDAG<>(matrix3x3, nodes)); + } + + @Test + public void testNodesToList() { + final var nodes = FixedDAG.Nodes.ofList(List.of(A, B)); + + assertEquals(2, nodes.size()); + + assertEquals(A, nodes.get(0)); + assertEquals(B, nodes.get(1)); + assertThrows(IndexOutOfBoundsException.class, () -> nodes.get(2)); + + assertEquals(0, nodes.indexOf(A)); + assertEquals(1, nodes.indexOf(B)); + assertThrows(NoSuchElementException.class, () -> nodes.indexOf(C)); + + final var copy = new ArrayList(); + for (var n : nodes) { + copy.add(n); + } + assertEquals(copy, List.of(A, B)); + } + + @ParameterizedTest + @MethodSource + public void testCyclic(List> edges) { + assertThrows(UnsupportedOperationException.class, () -> create(edges)); + } + + private static Stream>> testCyclic() { + return Stream.of( + List.of(edge(A, B), edge(B, A)), + + List.of(edge(A, B), edge(B, C), edge(C, D), edge(D, A)), + + List.of(edge(A, B), edge(B, C), edge(C, D), edge(D, B)), + + // A <- B -> L + // | ^ | + // | | | + // + <- D <- + + // | + // + <- C + List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D), edge(B, L)), + List.of(edge(C, D), edge(B, A), edge(D, B), edge(D, A), edge(L, D), edge(B, L)) + ); + } + + @ParameterizedTest + @MethodSource + public void testGetNoIncomingEdges(List> edges, List expectedNodes) { + final var actualNodes = create(edges).getNoIncomingEdges(); + assertEquals(expectedNodes, actualNodes); + } + + private static Stream testGetNoIncomingEdges() { + return Stream.of( + new Object[] { List.of(edge(A, B)), List.of(A) }, + new Object[] { List.of(edge(A, B), edge(A, B)), List.of(A) }, + new Object[] { List.of(edge(A, B), edge(D, B)), List.of(A, D) }, + new Object[] { List.of(edge(D, B), edge(A, B)), List.of(D, A) }, + + new Object[] { List.of(edge(A, B), edge(C, D)), List.of(A, C) }, + + // A <- B + // ^ ^ + // | | + // + -- D <- L + // | + // + <- C + new Object[] { List.of(edge(B, A), edge(D, B), edge(D, A), edge(C, D), edge(L, D)), List.of(C, L) }, + new Object[] { List.of(edge(B, A), edge(L, D), edge(D, B), edge(D, A), edge(C, D)), List.of(L, C) } + ); + } + + @ParameterizedTest + @MethodSource + public void testGetNoOutgoingEdges(List> edges, List expectedNodes) { + final var actualNodes = create(edges).getNoOutgoingEdges(); + assertEquals(expectedNodes, actualNodes); + } + + private static Stream testGetNoOutgoingEdges() { + return Stream.of( + new Object[] { List.of(edge(A, B)), List.of(B) }, + new Object[] { List.of(edge(A, B), edge(C, D)), List.of(B, D) } + ); + } + + @ParameterizedTest + @MethodSource + public void testGetTailsOf(String node, List> edges, List expectedNodes) { + final var actualNodes = create(edges).getTailsOf(node); + assertEquals(actualNodes, expectedNodes); + + } + + private static Stream testGetTailsOf() { + return Stream.of( + new Object[] { A, List.of(edge(A, B)), List.of() }, + new Object[] { B, List.of(edge(A, B)), List.of(A) }, + new Object[] { B, List.of(edge(A, B), edge(A, B)), List.of(A) }, + new Object[] { B, List.of(edge(A, B), edge(B, C)), List.of(A) }, + new Object[] { B, List.of(edge(A, B), edge(B, C), edge(C, D)), List.of(A) }, + new Object[] { B, List.of(edge(A, B), edge(A, C), edge(D, B)), List.of(A, D) }, + new Object[] { B, List.of(edge(D, B), edge(A, B), edge(A, C)), List.of(D, A) } + ); + } + + @ParameterizedTest + @MethodSource + public void testGetHeadsOf(String node, List> edges, List expectedNodes) { + final var actualNodes = create(edges).getHeadsOf(node); + assertEquals(actualNodes, expectedNodes); + } + + private static Stream testGetHeadsOf() { + return Stream.of( + new Object[] { A, List.of(edge(A, B)), List.of(B) }, + new Object[] { B, List.of(edge(A, B)), List.of() }, + new Object[] { A, List.of(edge(A, B), edge(A, B)), List.of(B) }, + new Object[] { B, List.of(edge(A, B), edge(B, C)), List.of(C) }, + new Object[] { B, List.of(edge(A, B), edge(B, C), edge(C, D)), List.of(C) }, + new Object[] { D, List.of(edge(D, B), edge(D, A), edge(C, D)), List.of(B, A) }, + new Object[] { D, List.of(edge(D, A), edge(D, B), edge(C, D)), List.of(A, B) } + ); + } + + @Test + public void testSome() { + // A <- B <--- D + // ^ ^ | + // | | | + // +--- C -> L | + // | ^ | + // | | | + // +----+------+ + + final var graphBuilder = FixedDAG.build(); + + graphBuilder.addEdge(edge(C, L)); + graphBuilder.addEdge(edge(D, B)); + graphBuilder.addEdge(edge(B, A)); + graphBuilder.addEdge(edge(D, A)); + graphBuilder.addEdge(edge(C, A)); + graphBuilder.addEdge(edge(D, C)); + graphBuilder.addEdge(edge(C, B)); + + final var graph = graphBuilder.create(); + + assertEquals(graph.getNoIncomingEdges(), List.of(D)); + assertEquals(graph.getNoOutgoingEdges(), List.of(L, A)); + + assertEquals(graph.getHeadsOf(A), List.of()); + assertEquals(graph.getTailsOf(A), List.of(C, D, B)); + + assertEquals(graph.getHeadsOf(B), List.of(A)); + assertEquals(graph.getTailsOf(B), List.of(C, D)); + + assertEquals(graph.getHeadsOf(C), List.of(L, B, A)); + assertEquals(graph.getTailsOf(C), List.of(D)); + + assertEquals(graph.getHeadsOf(D), List.of(C, B, A)); + assertEquals(graph.getTailsOf(D), List.of()); + + assertEquals(graph.getHeadsOf(L), List.of()); + assertEquals(graph.getTailsOf(L), List.of(C)); + } + + @Test + public void testSome2() { + // B -> A <- C + // ^ ^ + // | | + // +--- D ---+ + // ^ + // | + // K -> N <- M <- P + // ^ ^ + // | O | + // | ^ | + // | | | + // +--- L ---+ + // + + final var graphBuilder = FixedDAG.build(); + + graphBuilder.addEdge(edge(B, A)); + graphBuilder.addEdge(edge(C, A)); + graphBuilder.addEdge(edge(D, B)); + graphBuilder.addEdge(edge(D, C)); + graphBuilder.addEdge(edge(N, D)); + graphBuilder.addEdge(edge(M, N)); + graphBuilder.addEdge(edge(K, N)); + graphBuilder.addEdge(edge(L, K)); + graphBuilder.addEdge(edge(L, M)); + graphBuilder.addEdge(edge(P, M)); + graphBuilder.addEdge(edge(L, O)); + + final var graph = graphBuilder.create(); + + assertEquals(graph.getNoIncomingEdges(), List.of(L, P)); + assertEquals(graph.getNoOutgoingEdges(), List.of(A, O)); + + assertEquals(graph.getHeadsOf(A), List.of()); + assertEquals(graph.getTailsOf(A), List.of(B, C)); + assertEquals(graph.getAllHeadsOf(A), List.of()); + assertEquals(graph.getAllTailsOf(A), List.of(B, C, D, N, M, K, L, P)); + + assertEquals(graph.getHeadsOf(B), List.of(A)); + assertEquals(graph.getTailsOf(B), List.of(D)); + assertEquals(graph.getAllHeadsOf(B), List.of(A)); + assertEquals(graph.getAllTailsOf(B), List.of(D, N, M, K, L, P)); + + assertEquals(graph.getHeadsOf(C), List.of(A)); + assertEquals(graph.getTailsOf(C), List.of(D)); + assertEquals(graph.getAllHeadsOf(C), List.of(A)); + assertEquals(graph.getAllTailsOf(C), List.of(D, N, M, K, L, P)); + + assertEquals(graph.getHeadsOf(D), List.of(B, C)); + assertEquals(graph.getTailsOf(D), List.of(N)); + assertEquals(graph.getAllHeadsOf(D), List.of(B, A, C)); + assertEquals(graph.getAllTailsOf(D), List.of(N, M, K, L, P)); + + assertEquals(graph.getHeadsOf(K), List.of(N)); + assertEquals(graph.getTailsOf(K), List.of(L)); + assertEquals(graph.getAllHeadsOf(K), List.of(B, A, C, D, N)); + assertEquals(graph.getAllTailsOf(K), List.of(L)); + + assertEquals(graph.getHeadsOf(L), List.of(M, K, O)); + assertEquals(graph.getTailsOf(L), List.of()); + assertEquals(graph.getAllHeadsOf(L), List.of(B, A, C, D, N, M, K, O)); + assertEquals(graph.getAllTailsOf(L), List.of()); + + assertEquals(graph.getHeadsOf(M), List.of(N)); + assertEquals(graph.getTailsOf(M), List.of(L, P)); + assertEquals(graph.getAllHeadsOf(M), List.of(B, A, C, D, N)); + assertEquals(graph.getAllTailsOf(M), List.of(L, P)); + + assertEquals(graph.getHeadsOf(N), List.of(D)); + assertEquals(graph.getTailsOf(N), List.of(M, K)); + assertEquals(graph.getAllHeadsOf(N), List.of(B, A, C, D)); + assertEquals(graph.getAllTailsOf(N), List.of(M, K, L, P)); + + assertEquals(graph.getHeadsOf(O), List.of()); + assertEquals(graph.getTailsOf(O), List.of(L)); + assertEquals(graph.getAllHeadsOf(O), List.of()); + assertEquals(graph.getAllTailsOf(O), List.of(L)); + + assertEquals(graph.getHeadsOf(P), List.of(M)); + assertEquals(graph.getTailsOf(P), List.of()); + assertEquals(graph.getAllHeadsOf(P), List.of(B, A, C, D, N, M)); + assertEquals(graph.getAllTailsOf(P), List.of()); + } + + @ParameterizedTest + @MethodSource + public void testTopologicalSort(List> edges, int[] expectedNodes) { + + final var nodes = edges.stream().map(edge -> { + return Stream.of(edge.tail(), edge.head()); + }).flatMap(x -> x).sorted().distinct().toList(); + + assertArrayEquals(expectedNodes, FixedDAG.create(edges, nodes).topologicalSort().stream().mapToInt(x -> x).toArray()); + } + + private static List testTopologicalSort() { + return List.of( + new Object[] { List.of( + edge(11, 15), + edge(12, 16), + edge(13, 17), + edge(14, 15), + edge(14, 16), + edge(14, 17), + edge(14, 18)), IntStream.rangeClosed(11, 18).toArray() + }, + + new Object[] { List.of( + edge(5, 2), + edge(5, 0), + edge(4, 0), + edge(2, 3), + edge(3, 1)), new int[] {4, 5, 0, 2, 3, 1} + }, + + new Object[] { List.of( + edge(0, 1), + edge(0, 4), + edge(0, 7), + edge(0, 14), + edge(1, 5), + edge(2, 3), + edge(2, 5), + edge(2, 6), + edge(3, 10), + edge(4, 5), + edge(4, 8), + edge(5, 9), + edge(6, 10), + edge(7, 8), + edge(7, 11), + edge(10, 13), + edge(11, 12), + edge(13, 16), + edge(14, 15)), IntStream.rangeClosed(0, 16).toArray() + }, + + new Object[] { List.of( + edge(0, 2), + edge(0, 4), + edge(1, 4), + edge(1, 5), + edge(2, 5), + edge(3, 2)), new int[] {0, 1, 3, 2, 4, 5} + }, + + new Object[] { List.of( + edge(0, 1), + edge(0, 2), + edge(1, 3), + edge(2, 3), + edge(3, 4)), IntStream.rangeClosed(0, 4).toArray() + }, + + new Object[] { List.of( + edge(1, 2), + edge(1, 3), + edge(2, 4), + edge(3, 4), + edge(4, 5)), IntStream.rangeClosed(1, 5).toArray() + } + ); + } + + @Test + public void testEmptyBuilder() { + assertThrows(IllegalArgumentException.class, FixedDAG.build()::create); + } + + @Test + public void testSingleNodeBuilder() { + final var graphBuilder = FixedDAG.build(); + graphBuilder.addNode(A); + assertNodesEquals(graphBuilder.create().nodes(), A); + } + + @Test + public void testIsolatedNodesBuilder() { + final var graphBuilder = FixedDAG.build(); + graphBuilder.addNode(A); + graphBuilder.addNode(B); + assertNodesEquals(graphBuilder.create().nodes(), A, B); + assertEquals(graphBuilder.create().getNoOutgoingEdges(), List.of(A, B)); + assertEquals(graphBuilder.create().getNoIncomingEdges(), List.of(A, B)); + + graphBuilder.addEdge(edge(A, C)); + assertNodesEquals(graphBuilder.create().nodes(), A, B, C); + assertEquals(graphBuilder.create().getNoOutgoingEdges(), List.of(B, C)); + assertEquals(graphBuilder.create().getNoIncomingEdges(), List.of(A, B)); + } + + private static void assertNodesEquals(FixedDAG.Nodes actual, String... expected) { + assertEquals(List.of(expected), StreamSupport.stream(actual.spliterator(), false).toList()); + } + + private static FixedDAG create(Collection> edges) { + final var graphBuilder = FixedDAG.build(); + edges.forEach(graphBuilder::addEdge); + return graphBuilder.create(); + } + + private static DirectedEdge edge(T tail, T head) { + return DirectedEdge.create(tail, head); + } + + private static final String A = "A"; + private static final String B = "B"; + private static final String C = "C"; + private static final String D = "D"; + private static final String K = "K"; + private static final String L = "L"; + private static final String M = "M"; + private static final String N = "N"; + private static final String O = "O"; + private static final String P = "P"; +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java new file mode 100644 index 00000000000..8d34c1be155 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/pipeline/TaskPipelineBuilderTest.java @@ -0,0 +1,496 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jpackage.internal.pipeline; + +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toMap; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.locks.LockSupport; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +final class TaskPipelineBuilderTest { + + private static final class TestException extends Exception { + + TestException(TestTask sender) { + super(makeMessage(sender)); + } + + static String makeMessage(TestTask sender) { + return "Thrown by " + sender.name(); + } + + private static final long serialVersionUID = 1L; + } + + private enum TestTask implements Consumer { + A, + B, + C, + D, + K, + L, + M, + N, + THROW_1(true); + + TestTask(boolean fail) { + this.fail = fail; + } + + TestTask() { + fail = false; + } + + @Override + public void accept(StringBuffer sb) { + LockSupport.parkNanos(Duration.ofMillis(1).toNanos()); + System.out.println(String.format("[%s] result before append: [%s]; append %s", Thread.currentThread(), sb, name())); + sb.append(name()); + } + + Callable toCallable(StringBuffer sb) { + return new Callable<> () { + + @Override + public Void call() throws Exception { + if (isThrowing()) { + throw new TestException(TestTask.this); + } + accept(sb); + return null; + } + + @Override + public String toString() { + return TestTask.this.toString(); + } + + }; + } + + private boolean isThrowing() { + return fail; + } + + static Stream nonThrowingTasks() { + return Stream.of(values()).filter(Predicate.not(TestTask::isThrowing)); + } + + private final boolean fail; + } + + private record TaskSpec(TestTask task, List dependencies, TestTask dependent) { + + TaskSpec { + Objects.requireNonNull(task); + Objects.requireNonNull(dependencies); + } + + static final class Builder { + + Builder(TestTask task) { + this.task = Objects.requireNonNull(task); + } + + Builder to(TestTask task) { + dependent = task; + return this; + } + + Builder from(TestTask ... tasks) { + dependencies.addAll(List.of(tasks)); + return this; + } + + TaskSpec create() { + return new TaskSpec(task, dependencies, dependent); + } + + private final TestTask task; + private final List dependencies = new ArrayList<>(); + private TestTask dependent; + } + } + + @ParameterizedTest + @MethodSource("testIt") + public void testIt(TestSpec testSpec) throws Exception { + testSpec.test(); + } + + public record TestSpec(List taskSpecs, Object expectedString, Set expectedAnyFailures, Executor executor) { + + public TestSpec { + Objects.requireNonNull(taskSpecs); + Objects.requireNonNull(expectedString); + Objects.requireNonNull(expectedAnyFailures); + } + + static final class Builder { + + Builder taskSpecs(TaskSpec ...specs) { + taskSpecs.addAll(List.of(specs)); + return this; + } + + Builder expected(Pattern v) { + expectedRegexp = v; + return this; + } + + Builder expected(Predicate v) { + expectedPredicate = v; + return this; + } + + Builder expected(String v) { + expectedString = v; + return this; + } + + Builder expectedAnyFailure(TestTask... v) { + expectedAnyFailures.addAll(List.of(v)); + return this; + } + + Builder executor(Executor v) { + executor = v; + return this; + } + + TestSpec create() { + final Object expectedObject; + if (!isParallel()) { + expectedObject = expectedString; + } else if (expectedRegexp != null) { + expectedObject = expectedRegexp; + } else if (expectedPredicate != null) { + expectedObject = expectedPredicate; + } else { + expectedObject = expectedString; + } + + if (expectedPredicate != null && expectedRegexp != null) { + throw new IllegalStateException(); + } + + return new TestSpec(taskSpecs, expectedObject, expectedAnyFailures, executor); + } + + private boolean isParallel() { + return executor != null; + } + + private final List taskSpecs = new ArrayList<>(); + private String expectedString; + private Pattern expectedRegexp; + private Predicate expectedPredicate; + private Set expectedAnyFailures = new HashSet<>(); + private Executor executor; + } + + @SuppressWarnings("unchecked") + void test() { + final var builder = new TaskPipelineBuilder(); + builder.executor(executor); + + final var sb = new StringBuffer(); + + final var taskMap = Stream.of(TestTask.values()).collect(toMap(x -> x, x -> { + return x.toCallable(sb); + })); + + taskSpecs.forEach(taskSpec -> { + final var taskBuilder = builder.task(taskMap.get(taskSpec.task)) + .addDependencies(taskSpec.dependencies.stream().map(taskMap::get).toList()); + if (taskSpec.dependent != null) { + taskBuilder.addDependent(taskMap.get(taskSpec.dependent)); + } + taskBuilder.add(); + }); + + if (expectedAnyFailures.isEmpty()) { + System.out.println(String.format("start for %s", expectedString)); + assertDoesNotThrow(builder.create()::call); + } else { + System.out.println(String.format("start for %s throws %s", expectedString, expectedAnyFailures)); + final var ex = assertThrows(TestException.class, builder.create()::call); + assertTrue(expectedAnyFailures.stream().map(TestException::makeMessage).anyMatch(Predicate.isEqual(ex.getMessage())), () -> { + return String.format("Exception message '%s' doesn't match any of failed tasks %s", ex.getMessage(), expectedAnyFailures); + }); + } + System.out.println("end"); + + final var actualString = sb.toString(); + + assertEquals(actualString.length(), actualString.chars().distinct().count()); + + if (expectedString instanceof Pattern expectedRegexp) { + assertTrue(expectedRegexp.matcher(actualString).matches(), () -> { + return String.format("Regexp %s doesn't match string %s", expectedRegexp, actualString); + }); + } else if (expectedString instanceof Predicate expectedPredicate) { + assertTrue(((Predicate)expectedPredicate).test(actualString), () -> { + return String.format("Predicate %s failed for string %s", expectedString, actualString); + }); + } else { + assertEquals(expectedString.toString(), actualString); + } + } + } + + private static List testIt() { + final List data = new ArrayList<>(); + + data.add(test().taskSpecs(task(A).create()).expected("A").create()); + + data.add(test().taskSpecs(task(B).from(A).create()).expected("AB").create()); + + // D <- C <- B + // ^ ^ + // | | + // +--- A ---+ + data.add(test().taskSpecs( + task(D).create(), + task(C).from(B).to(D).create(), + task(A).to(B).create(), + task(A).to(D).create() + ).expected("ABCD").create()); + + // A <- THROW_1 <- B + data.add(test().taskSpecs( + task(A).create(), + task(THROW_1).from(B).to(A).create() + ).expected("B").expectedAnyFailure(THROW_1).create()); + + data.addAll(testData(ForkJoinPool.commonPool())); + data.addAll(testData(Executors.newSingleThreadExecutor())); + data.addAll(testData(Executors.newFixedThreadPool(5))); + + data.addAll(testData(null)); + + return data; + } + + private static List testData(Executor executor) { + final List data = new ArrayList<>(); + + final var allValuesRegexp = Pattern.compile(String.format("[%s]{%d}", + TestTask.nonThrowingTasks().map(Enum::name).collect(joining()), TestTask.nonThrowingTasks().count())); + + data.add(test().executor(executor).taskSpecs( + task(D).create(), + task(C).from(B).to(D).create(), + task(A).to(B).create(), + task(A).to(D).create() + ).expected("ABCD").create()); + + data.add(test().executor(executor).taskSpecs(TestTask.nonThrowingTasks() + .map(TaskPipelineBuilderTest::task) + .map(TaskSpec.Builder::create) + .toArray(TaskSpec[]::new) + ).expected(allValuesRegexp).expected(TestTask.nonThrowingTasks().map(Enum::name).collect(joining())).create()); + + data.add(test().executor(executor).taskSpecs(TestTask.nonThrowingTasks() + .sorted(Comparator.reverseOrder()) + .map(TaskPipelineBuilderTest::task) + .map(TaskSpec.Builder::create) + .toArray(TaskSpec[]::new) + ).expected(allValuesRegexp).expected(TestTask.nonThrowingTasks().sorted(Comparator.reverseOrder()).map(Enum::name).collect(joining())).create()); + + // B -> A <- C + // ^ ^ + // | | + // +--- D ---+ + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(C).from(D).to(A).create(), + task(B).from(D).to(A).create() + ).expected(Pattern.compile("D(BC|CB)A")).expected("DCBA").create()); + + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(B).from(D).to(A).create(), + task(C).from(D).to(A).create() + ).expected(Pattern.compile("D(BC|CB)A")).expected("DBCA").create()); + + // B -> A <- C + // ^ ^ + // | | + // +--- D ---+ + // ^ + // | + // N + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(C).from(D).to(A).create(), + task(N).to(D).create(), + task(B).from(D).to(A).create() + ).expected(Pattern.compile("ND(BC|CB)A")).expected("NDCBA").create()); + + // B -> A <- C + // ^ ^ + // | | + // +--- D ---+ + // ^ + // | + // K -> N <- M + // ^ ^ + // | | + // +--- L ---+ + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(C).from(D).to(A).create(), + task(N).to(D).create(), + task(B).from(D).to(A).create(), + task(K).from(L).to(N).create(), + task(M).from(L).to(N).create() + ).expected(Pattern.compile("L(KM|MK)ND(BC|CB)A")).expected("LKMNDCBA").create()); + + // +-> A <-+ + // | | + // B THROW_1 <- D + // ^ ^ + // | | + // K C + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(B).from(K).to(A).create(), + task(THROW_1).from(D).to(A).create(), + task(C).to(THROW_1).create() + ).expected(c('K').before('B').and(onlyChars("KBDC"))).expected("KBDC").expectedAnyFailure(THROW_1).create()); + + // +--> A <--+ + // | ^ | + // | | | + // B C THROW_1 + data.add(test().executor(executor).taskSpecs( + task(A).create(), + task(B).to(A).create(), + task(C).to(A).create(), + task(THROW_1).to(A).create() + ).expected(onlyChars("BC")).expected("BC").expectedAnyFailure(THROW_1).create()); + + return data; + } + + private static TaskSpec.Builder task(TestTask task) { + return new TaskSpec.Builder(task); + } + + private static TestSpec.Builder test() { + return new TestSpec.Builder(); + } + + private record PredicateWithDescritpion(Predicate predicate, String description) implements Predicate { + + PredicateWithDescritpion { + Objects.requireNonNull(predicate); + Objects.requireNonNull(description); + } + + @Override + public String toString() { + return String.format("(%s)", description); + } + + @Override + public Predicate and(Predicate other) { + return new PredicateWithDescritpion<>(predicate.and(other), String.format("%s and %s", toString(), other)); + } + + @Override + public Predicate or(Predicate other) { + return new PredicateWithDescritpion<>(predicate.or(other), String.format("%s or %s", toString(), other)); + } + + @Override + public Predicate negate() { + return new PredicateWithDescritpion<>(predicate, String.format("!%s", toString())); + } + + @Override + public boolean test(T t) { + return predicate.test(t); + } + } + + private record StringPredicateBuilder(char ch) { + Predicate before(char other) { + return new PredicateWithDescritpion<>(str -> { + return str.indexOf(ch) < str.indexOf(other); + }, String.format("%s before %s", ch, other)); + } + + Predicate after(char other) { + return new StringPredicateBuilder(other).before(ch); + } + } + + private static StringPredicateBuilder c(char ch) { + return new StringPredicateBuilder(ch); + } + + private static Predicate onlyChars(String chars) { + return onlyChars(chars.chars().mapToObj(v -> (char)v).toArray(Character[]::new)); + } + + private static Predicate onlyChars(Character... chars) { + return new PredicateWithDescritpion<>(str -> { + final Set set = Set.of(chars); + return str.chars().mapToObj(v -> (char)v).allMatch(set::contains); + }, String.format("only %s", List.of(chars))); + } + + private static final TestTask A = TestTask.A; + private static final TestTask B = TestTask.B; + private static final TestTask C = TestTask.C; + private static final TestTask D = TestTask.D; + private static final TestTask K = TestTask.K; + private static final TestTask L = TestTask.L; + private static final TestTask M = TestTask.M; + private static final TestTask N = TestTask.N; + private static final TestTask THROW_1 = TestTask.THROW_1; +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java new file mode 100644 index 00000000000..1ece83be0a6 --- /dev/null +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/CompositeProxyTest.java @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jpackage.internal.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + + +public class CompositeProxyTest { + + static interface Smalltalk { + + default String sayHello() { + return "Hello"; + } + + default String sayBye() { + return "Bye"; + } + } + + static interface ConvoMixin { + + String sayThings(); + + record Stub(String sayThings) implements ConvoMixin { + } + } + + static interface Convo extends Smalltalk, ConvoMixin { + } + + static interface ConvoMixinWithOverrideSayBye { + + String sayThings(); + + String sayBye(); + + record Stub(String sayThings, String sayBye) implements ConvoMixinWithOverrideSayBye { + } + } + + static interface ConvoWithOverrideSayBye extends Smalltalk, ConvoMixinWithOverrideSayBye { + @Override + String sayBye(); + } + + static interface ConvoWithDefaultSayHelloWithOverrideSayBye extends Smalltalk, ConvoMixinWithOverrideSayBye { + @Override + String sayBye(); + + @Override + default String sayHello() { + return "Ciao"; + } + + static String saySomething() { + return "blah"; + } + } + + @Test + public void testSmalltalk() { + var convo = CompositeProxy.create(Smalltalk.class); + assertEquals("Hello", convo.sayHello()); + assertEquals("Bye", convo.sayBye()); + } + + @Test + public void testConvo() { + final var otherThings = "How is your day?"; + var convo = CompositeProxy.create(Convo.class, + new Smalltalk() {}, new ConvoMixin.Stub(otherThings)); + assertEquals("Hello", convo.sayHello()); + assertEquals("Bye", convo.sayBye()); + assertEquals(otherThings, convo.sayThings()); + } + + @Test + public void testConvoWithDuke() { + final var otherThings = "How is your day?"; + var convo = CompositeProxy.create(Convo.class, new Smalltalk() { + @Override + public String sayHello() { + return "Hello, Duke"; + } + }, new ConvoMixin.Stub(otherThings)); + assertEquals("Hello, Duke", convo.sayHello()); + assertEquals("Bye", convo.sayBye()); + assertEquals(otherThings, convo.sayThings()); + } + + @Test + public void testConvoWithCustomSayBye() { + var mixin = new ConvoMixinWithOverrideSayBye.Stub("How is your day?", "See you"); + + var convo = CompositeProxy.create(ConvoWithOverrideSayBye.class, new Smalltalk() {}, mixin); + + var expectedConvo = new ConvoWithOverrideSayBye() { + @Override + public String sayBye() { + return mixin.sayBye; + } + + @Override + public String sayThings() { + return mixin.sayThings; + } + }; + + assertEquals(expectedConvo.sayHello(), convo.sayHello()); + assertEquals(expectedConvo.sayBye(), convo.sayBye()); + assertEquals(expectedConvo.sayThings(), convo.sayThings()); + } + + @Test + public void testConvoWithCustomSayHelloAndSayBye() { + var mixin = new ConvoMixinWithOverrideSayBye.Stub("How is your day?", "See you"); + + var convo = CompositeProxy.create(ConvoWithDefaultSayHelloWithOverrideSayBye.class, new Smalltalk() {}, mixin); + + var expectedConvo = new ConvoWithDefaultSayHelloWithOverrideSayBye() { + @Override + public String sayBye() { + return mixin.sayBye; + } + + @Override + public String sayThings() { + return mixin.sayThings; + } + }; + + assertEquals("Ciao", expectedConvo.sayHello()); + assertEquals(expectedConvo.sayHello(), convo.sayHello()); + assertEquals(expectedConvo.sayBye(), convo.sayBye()); + assertEquals(expectedConvo.sayThings(), convo.sayThings()); + } + + @Test + public void testInherited() { + interface Base { + String doSome(); + } + + interface Next extends Base { + String doNext(); + } + + interface Last extends Next { + } + + var last = CompositeProxy.create(Last.class, new Next() { + @Override + public String doNext() { + return "next"; + } + + @Override + public String doSome() { + return "some"; + } + }); + + assertEquals("next", last.doNext()); + assertEquals("some", last.doSome()); + } + + @Test + public void testNestedProxy() { + interface AddM { + String m(); + } + + interface AddN { + String n(); + } + + interface A extends AddM { + } + + interface B extends AddN { + } + + interface C extends A, B { + } + + var proxyA = CompositeProxy.create(A.class, new AddM() { + @Override + public String m() { + return "hello"; + } + }); + var proxyB = CompositeProxy.create(B.class, new AddN() { + @Override + public String n() { + return "bye"; + } + + }); + var proxyC = CompositeProxy.create(C.class, proxyA, proxyB); + + assertEquals("hello", proxyC.m()); + assertEquals("bye", proxyC.n()); + } + + @Test + public void testComposite() { + interface A { + String sayHello(); + String sayBye(); + default String talk() { + return String.join(",", sayHello(), sayBye()); + } + } + + interface B extends A { + @Override + default String sayHello() { + return "ciao"; + } + } + + var proxy = CompositeProxy.create(B.class, new A() { + @Override + public String sayHello() { + return "hello"; + } + + @Override + public String sayBye() { + return "bye"; + } + }); + + assertEquals("ciao,bye", proxy.talk()); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + public void testBasicObjectMethods(boolean withOverrides) { + interface A { + default void foo() {} + } + + interface B { + default void bar() {} + } + + interface C extends A, B { + } + + final A aImpl; + final B bImpl; + + if (withOverrides) { + aImpl = new A() { + @Override + public String toString() { + return "theA"; + } + + @Override + public boolean equals(Object other) { + return true; + } + + @Override + public int hashCode() { + return 7; + } + }; + + bImpl = new B() { + @Override + public String toString() { + return "theB"; + } + }; + } else { + aImpl = new A() {}; + bImpl = new B() {}; + } + + var proxy = CompositeProxy.create(C.class, aImpl, bImpl); + var proxy2 = CompositeProxy.create(C.class, aImpl, bImpl); + + assertNotEquals(proxy.toString(), proxy2.toString()); + assertNotEquals(proxy.hashCode(), proxy2.hashCode()); + assertFalse(proxy.equals(proxy2)); + assertFalse(proxy2.equals(proxy)); + assertTrue(proxy.equals(proxy)); + assertTrue(proxy2.equals(proxy2)); + } + + @Test + public void testJavadocExample() { + interface Sailboat { + default void trimSails() {} + } + + interface WithMain { + void trimMain(); + } + + interface WithJib { + void trimJib(); + } + + interface Sloop extends Sailboat, WithMain, WithJib { + @Override + public default void trimSails() { + System.out.println("On the sloop:"); + trimMain(); + trimJib(); + } + } + + interface Catboat extends Sailboat, WithMain { + @Override + public default void trimSails() { + System.out.println("On the catboat:"); + trimMain(); + } + } + + final var withMain = new WithMain() { + @Override + public void trimMain() { + System.out.println(" trim the main"); + } + }; + + final var withJib = new WithJib() { + @Override + public void trimJib() { + System.out.println(" trim the jib"); + } + }; + + Sloop sloop = CompositeProxy.create(Sloop.class, new Sailboat() {}, withMain, withJib); + + Catboat catboat = CompositeProxy.create(Catboat.class, new Sailboat() {}, withMain); + + sloop.trimSails(); + catboat.trimSails(); + } +} diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java index bae4921fda3..d766505cf14 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PListReaderTest.java @@ -51,7 +51,7 @@ public class PListReaderTest { enum QueryType { STRING(PListReader::queryValue), BOOLEAN(PListReader::queryBoolValue), - STRING_ARRY(PListReader::queryArrayValue); + STRING_ARRAY(PListReader::queryArrayValue); QueryType(BiFunction queryMethod) { this.queryMethod = Objects.requireNonNull(queryMethod); @@ -98,7 +98,7 @@ Builder expectedValue(Object v) { } else if (v instanceof Boolean) { queryType(QueryType.BOOLEAN); } else if (v instanceof List) { - queryType(QueryType.STRING_ARRY); + queryType(QueryType.STRING_ARRAY); } return this; } @@ -196,7 +196,7 @@ public void testWrongValueType(QueryType queryType) { testSpecs.add(builder.keyName("string-key").create()); testSpecs.add(builder.keyName("array-key").create()); } - case STRING_ARRY -> { + case STRING_ARRAY -> { testSpecs.add(builder.keyName("string-key").create()); testSpecs.add(builder.keyName("boolean-true-key").create()); testSpecs.add(builder.keyName("boolean-false-key").create()); @@ -230,7 +230,7 @@ private static List testQueryValue() { testSpec(QueryType.BOOLEAN).xml("foo").create(), testSpec().expectedValue(List.of("foo", "bar")).xml("foofoobar").create(), testSpec().expectedValue(List.of()).xml("foo").create(), - testSpec(QueryType.STRING_ARRY).xml("foo").create(), + testSpec(QueryType.STRING_ARRAY).xml("foo").create(), testSpec().expectedValue("A").xml("fooAB").create(), testSpec().expectedValue("A").xml("fooAfooB").create() ); diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java index 42578227cf5..579cf5f083c 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/PathGroupTest.java @@ -23,23 +23,35 @@ package jdk.jpackage.internal.util; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; +import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.UnaryOperator; +import java.util.stream.IntStream; import java.util.stream.Stream; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrowsExactly; -import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.params.ParameterizedTest; @@ -48,6 +60,7 @@ public class PathGroupTest { + @Test public void testNullId() { assertThrowsExactly(NullPointerException.class, () -> new PathGroup(Map.of()).getPath(null)); } @@ -113,6 +126,69 @@ public void testRoots() { assertEquals(Path.of("foo"), roots.get(0)); } + public record TestRootsSpec(Collection paths, Set expectedRoots) { + public TestRootsSpec { + paths.forEach(Objects::requireNonNull); + expectedRoots.forEach(Objects::requireNonNull); + } + + void test() { + final var pg = new PathGroup(paths.stream().collect(toMap(x -> new Object(), x -> x))); + final var actualRoots = pg.roots().stream().collect(toSet()); + assertEquals(expectedRoots, actualRoots); + } + + static TestRootsSpec create(Collection paths, Set expectedRoots) { + return new TestRootsSpec(paths.stream().map(Path::of).toList(), expectedRoots.stream().map(Path::of).collect(toSet())); + } + } + + @ParameterizedTest + @MethodSource("testRootsValues") + public void testRoots(TestRootsSpec testSpec) { + testSpec.test(); + } + + private static Collection testRootsValues() { + return List.of( + TestRootsSpec.create(List.of(""), Set.of("")), + TestRootsSpec.create(List.of("/", "a/b/c", "a/b", "a/b", "a/b/"), Set.of("a/b", "/")) + ); + } + + @ParameterizedTest + @MethodSource + public void testSizeInBytes(List paths, @TempDir Path tempDir) throws IOException { + final var files = Set.of("AA.txt", "a/b/c/BB.txt", "a/b/c/DD.txt", "d/foo.txt").stream().map(Path::of).toList(); + + int counter = 0; + for (var file : files) { + file = tempDir.resolve(file); + Files.createDirectories(file.getParent()); + Files.writeString(file, "x".repeat(++counter * 100)); + } + + final var expectedSize = Stream.of(walkFiles(tempDir)) + .map(tempDir::resolve) + .filter(Files::isRegularFile) + .map(toFunction(Files::size)) + .mapToLong(Long::longValue).sum(); + + final var pg = new PathGroup(paths.stream().collect(toMap(x -> new Object(), x -> x))).resolveAt(tempDir); + + assertEquals(expectedSize, pg.sizeInBytes()); + } + + private static Collection> testSizeInBytes() { + return Stream.of( + List.of(""), + List.of("AA.txt", "a/b", "d", "non-existant", "non-existant/foo/bar"), + List.of("AA.txt", "a/b", "d", "a/b/c/BB.txt", "a/b/c/BB.txt") + ).map(v -> { + return v.stream().map(Path::of).toList(); + }).toList(); + } + @Test public void testResolveAt() { final PathGroup pg = new PathGroup(Map.of( @@ -140,7 +216,7 @@ public void testResolveAt() { assertEquals(aPath, pg2.roots().get(0)); } - enum TransformType { COPY, MOVE, HANDLER }; + enum TransformType { COPY, MOVE, HANDLER } private static Stream testTransform() { return Stream.of(TransformType.values()).flatMap(transform -> { @@ -265,6 +341,253 @@ public void createDirectory(Path dir) throws IOException { } } + private enum PathRole { + DESKTOP, + LINUX_APPLAUNCHER_LIB, + } + + private static PathGroup linuxAppImage() { + return new PathGroup(Map.of( + PathRole.DESKTOP, Path.of("lib"), + PathRole.LINUX_APPLAUNCHER_LIB, Path.of("lib/libapplauncher.so") + )); + } + + private static PathGroup linuxUsrTreePackageImage(Path prefix, String packageName) { + final Path lib = prefix.resolve(Path.of("lib", packageName)); + return new PathGroup(Map.of( + PathRole.DESKTOP, lib, + PathRole.LINUX_APPLAUNCHER_LIB, lib.resolve("lib/libapplauncher.so") + )); + } + + @Test + public void testLinuxLibapplauncher(@TempDir Path tempDir) throws IOException { + final Path srcDir = tempDir.resolve("src"); + final Path dstDir = tempDir.resolve("dst"); + + final Map> files = Map.of( + PathRole.LINUX_APPLAUNCHER_LIB, List.of(Path.of("")), + PathRole.DESKTOP, List.of(Path.of("UsrUsrTreeTest.png")) + ); + + final var srcAppLayout = linuxAppImage().resolveAt(srcDir); + final var dstAppLayout = linuxUsrTreePackageImage(dstDir.resolve("usr"), "foo"); + + for (final var e : files.entrySet()) { + final var pathRole = e.getKey(); + final var basedir = srcAppLayout.getPath(pathRole); + for (var file : e.getValue().stream().map(basedir::resolve).toList()) { + Files.createDirectories(file.getParent()); + Files.writeString(file, "foo"); + } + } + + srcAppLayout.copy(dstAppLayout); + + Stream.of(walkFiles(dstDir)).filter(p -> { + return p.getFileName().equals(dstAppLayout.getPath(PathRole.LINUX_APPLAUNCHER_LIB).getFileName()); + }).reduce((x, y) -> { + throw new AssertionError(String.format("Multiple libapplauncher: [%s], [%s]", x, y)); + }); + } + + + public enum TestFileContent { + A, + B, + C; + + void assertFileContent(Path path) { + try { + final var expected = name(); + final var actual = Files.readString(path); + assertEquals(expected, actual); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + void createFile(Path path) { + try { + Files.createDirectories(path.getParent()); + Files.writeString(path, name()); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + } + + public record PathGroupCopy(Path from, Path to) { + public PathGroupCopy { + Objects.requireNonNull(from); + } + + public PathGroupCopy(Path from) { + this(from, null); + } + } + + public record TestFile(Path path, TestFileContent content) { + public TestFile { + Objects.requireNonNull(content); + if (path.isAbsolute()) { + throw new IllegalArgumentException(); + } + } + + void assertFileContent(Path basedir) { + content.assertFileContent(basedir.resolve(path)); + } + + void create(Path basedir) { + content.createFile(basedir.resolve(path)); + } + } + + public record TestCopySpec(List pathGroupSpecs, Collection src, Collection dst) { + public TestCopySpec { + pathGroupSpecs.forEach(Objects::requireNonNull); + src.forEach(Objects::requireNonNull); + dst.forEach(Objects::requireNonNull); + } + + PathGroup from() { + return createPathGroup(PathGroupCopy::from); + } + + PathGroup to() { + return createPathGroup(PathGroupCopy::to); + } + + void test(Path tempDir) throws IOException { + final Path srcDir = tempDir.resolve("src"); + final Path dstDir = tempDir.resolve("dst"); + + src.stream().forEach(testFile -> { + testFile.create(srcDir); + }); + + from().resolveAt(srcDir).copy(to().resolveAt(dstDir)); + + dst.stream().forEach(testFile -> { + testFile.assertFileContent(dstDir); + }); + + Files.createDirectories(dstDir); + final var actualFiles = Stream.of(walkFiles(dstDir)).filter(path -> { + return Files.isRegularFile(dstDir.resolve(path)); + }).collect(toSet()); + final var expectedFiles = dst.stream().map(TestFile::path).collect(toSet()); + + assertEquals(expectedFiles, actualFiles); + } + + static Builder build() { + return new Builder(); + } + + static class Builder { + Builder addPath(String from, String to) { + pathGroupSpecs.add(new PathGroupCopy(Path.of(from), Optional.ofNullable(to).map(Path::of).orElse(null))); + return this; + } + + Builder file(TestFileContent content, String srcPath, String ...dstPaths) { + srcFiles.putAll(Map.of(Path.of(srcPath), content)); + dstFiles.putAll(Stream.of(dstPaths).collect(toMap(Path::of, x -> content))); + return this; + } + + TestCopySpec create() { + return new TestCopySpec(pathGroupSpecs, convert(srcFiles), convert(dstFiles)); + } + + private static Collection convert(Map map) { + return map.entrySet().stream().map(e -> { + return new TestFile(e.getKey(), e.getValue()); + }).toList(); + } + + private final List pathGroupSpecs = new ArrayList<>(); + private final Map srcFiles = new HashMap<>(); + private final Map dstFiles = new HashMap<>(); + } + + private PathGroup createPathGroup(Function keyFunc) { + return new PathGroup(IntStream.range(0, pathGroupSpecs.size()).mapToObj(Integer::valueOf).map(i -> { + return Optional.ofNullable(keyFunc.apply(pathGroupSpecs.get(i))).map(path -> { + return Map.entry(i, path); + }); + }).filter(Optional::isPresent).map(Optional::orElseThrow).collect(toMap(Map.Entry::getKey, Map.Entry::getValue))); + } + } + + @ParameterizedTest + @MethodSource + public void testCopy(TestCopySpec testSpec, @TempDir Path tempDir) throws IOException { + testSpec.test(tempDir); + } + + private static Collection testCopy() { + return List.of( + TestCopySpec.build().create(), + TestCopySpec.build() + .addPath("a/b/c", "a") + .file(TestFileContent.A, "a/b/c/j/k/foo", "a/j/k/foo") + .create(), + TestCopySpec.build() + .addPath("a/b/c", "a") + .addPath("a/b/c", "d") + .file(TestFileContent.A, "a/b/c/j/k/foo", "a/j/k/foo", "d/j/k/foo") + .create(), + TestCopySpec.build() + .addPath("a/b/c", "") + .addPath("a/b/c", "d") + .file(TestFileContent.A, "a/b/c/j/k/foo", "j/k/foo", "d/j/k/foo") + .create(), + TestCopySpec.build() + .addPath("a/b/c", "cc") + .addPath("a/b/c", "dd") + .addPath("a/b/c/foo", null) + .file(TestFileContent.A, "a/b/c/foo") + .create(), + TestCopySpec.build() + .addPath("a/b/c", "cc") + .addPath("a/b/c", "dd") + .addPath("a/b/c/foo", null) + .file(TestFileContent.A, "a/b/c/foo") + .file(TestFileContent.B, "a/b/c/bar", "cc/bar", "dd/bar") + .create(), + TestCopySpec.build() + .addPath("a/b/c", "cc") + .addPath("a/b/c", "dd") + .addPath("a/b/c/bar", "dd/buz") + .addPath("a/b/c/foo", null) + .file(TestFileContent.A, "a/b/c/foo") + .file(TestFileContent.B, "a/b/c/bar", "dd/buz") + .create(), + TestCopySpec.build() + .addPath("a/b/c", "cc") + .addPath("a/b/c", "dd") + .addPath("a/b/c/bar", "dd/buz") + .addPath("a/b/c/bar", "cc/rab") + .addPath("a/b/c/foo", null) + .file(TestFileContent.A, "a/b/c/foo") + .file(TestFileContent.B, "a/b/c/bar", "cc/rab", "dd/buz") + .create(), + TestCopySpec.build() + .addPath("a/b", null) + .addPath("a/b/c", "cc") + .addPath("a/b/c", "dd") + .addPath("a/b/c/bar", "dd/buz") + .addPath("a/b/c/bar", "cc/rab") + .file(TestFileContent.A, "a/b/c/foo") + .file(TestFileContent.B, "a/b/c/bar") + .create() + ); + } + private static Path[] walkFiles(Path root) throws IOException { try (var files = Files.walk(root)) { return files.map(root::relativize).sorted().toArray(Path[]::new); diff --git a/test/jdk/tools/jpackage/linux/ShortcutHintTest.java b/test/jdk/tools/jpackage/linux/ShortcutHintTest.java index fc34d024a98..4d3b33bcd6b 100644 --- a/test/jdk/tools/jpackage/linux/ShortcutHintTest.java +++ b/test/jdk/tools/jpackage/linux/ShortcutHintTest.java @@ -176,7 +176,7 @@ public static void testDesktopFileFromResourceDir() throws IOException { TKit.assertTextStream(expectedVersionString) .label(String.format("[%s] file", desktopFile)) .predicate(String::equals) - .apply(Files.readAllLines(desktopFile).stream()); + .apply(Files.readAllLines(desktopFile)); }).run(); } } diff --git a/test/jdk/tools/jpackage/linux/UsrTreeTest.java b/test/jdk/tools/jpackage/linux/UsrTreeTest.java index e33364c605d..1950aab39a3 100644 --- a/test/jdk/tools/jpackage/linux/UsrTreeTest.java +++ b/test/jdk/tools/jpackage/linux/UsrTreeTest.java @@ -21,15 +21,18 @@ * questions. */ +import static java.util.stream.Collectors.toMap; +import static jdk.jpackage.test.ApplicationLayout.linuxAppImage; + import java.nio.file.Path; import java.util.List; import java.util.function.Consumer; -import java.util.stream.Collectors; -import jdk.jpackage.test.TKit; +import java.util.stream.Stream; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.LinuxHelper; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.LinuxHelper; -import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.TKit; /** @@ -90,20 +93,13 @@ private static void test(String installDir, boolean expectedImageSplit) { "Check there is%spackage name [%s] in common path [%s] between [%s] and [%s]", expectedImageSplit ? " no " : " ", packageName, commonPath, launcherPath, launcherCfgPath)); - - List packageFiles = LinuxHelper.getPackageFiles(cmd).collect( - Collectors.toList()); - - Consumer packageFileVerifier = file -> { - TKit.assertTrue(packageFiles.stream().filter( - path -> path.equals(file)).findFirst().orElse( - null) != null, String.format( - "Check file [%s] is in [%s] package", file, - packageName)); - }; - - packageFileVerifier.accept(launcherPath); - packageFileVerifier.accept(launcherCfgPath); + }) + .addInstallVerifier(cmd -> { + Stream.of( + cmd.appLauncherPath(), + cmd.appLauncherCfgPath(null), + cmd.appLayout().libapplauncher() + ).map(cmd::pathToPackageFile).map(cmd.appInstallationDirectory()::relativize).forEachOrdered(cmd::assertFileInAppImage); }) .run(); } diff --git a/test/jdk/tools/jpackage/macosx/MacSignTest.java b/test/jdk/tools/jpackage/macosx/MacSignTest.java index 4313f1900e2..7b2e06dc7ca 100644 --- a/test/jdk/tools/jpackage/macosx/MacSignTest.java +++ b/test/jdk/tools/jpackage/macosx/MacSignTest.java @@ -24,12 +24,23 @@ import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Objects; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.CannedFormattedString; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JPackageStringBundle; import jdk.jpackage.test.MacHelper; +import jdk.jpackage.test.MacSign; +import jdk.jpackage.test.MacSign.CertificateRequest; +import jdk.jpackage.test.MacSignVerify; +import jdk.jpackage.test.PackageType; import jdk.jpackage.test.TKit; /* @@ -64,23 +75,173 @@ public static void testAppContentWarning() throws IOException { expectedStrings.add(xcodeWarning); } - // --app-content and --type app-image - // Expect `message.codesign.failed.reason.app.content` message in the log. - // This is not a fatal error, just a warning. - // To make jpackage fail, specify bad additional content. - final var cmd = JPackageCommand.helloAppImage() - .ignoreDefaultVerbose(true) - .validateOutput(expectedStrings.toArray(CannedFormattedString[]::new)) - .addArguments("--app-content", appContent) - .addArguments("--mac-sign") - .addArguments("--mac-signing-keychain", SigningBase.StandardKeychain.MAIN.spec().keychain().name()) - .addArguments("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.APP_IMAGE.spec().name()); - - if (MacHelper.isXcodeDevToolsInstalled()) { - // Check there is no warning about missing xcode command line developer tools. - cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); + final var keychain = SigningBase.StandardKeychain.EXPIRED.spec().keychain(); + + MacSign.Keychain.withAddedKeychains(List.of(keychain), () -> { + // --app-content and --type app-image + // Expect `message.codesign.failed.reason.app.content` message in the log. + // This is not a fatal error, just a warning. + // To make jpackage fail, specify bad additional content. + final var cmd = JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .validateOutput(expectedStrings.toArray(CannedFormattedString[]::new)) + .addArguments("--app-content", appContent) + .addArguments("--mac-sign") + .addArguments("--mac-signing-keychain", keychain.name()) + .addArguments("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec().name()); + + if (MacHelper.isXcodeDevToolsInstalled()) { + // Check there is no warning about missing xcode command line developer tools. + cmd.validateOutput(TKit.assertTextStream(xcodeWarning.getValue()).negate()); + } + + cmd.execute(1); + }); + } + + @Test + @Parameter({"IMAGE", "EXPIRED_SIGNING_KEY_USER_NAME"}) + @Parameter({"MAC_DMG", "EXPIRED_SIGNING_KEY_USER_NAME"}) + @Parameter({"MAC_PKG", "EXPIRED_SIGNING_KEY_USER_NAME", "EXPIRED_SIGNING_KEY_USER_NAME_PKG"}) + + @Parameter({"IMAGE", "EXPIRED_SIGN_IDENTITY"}) + @Parameter({"MAC_DMG", "EXPIRED_SIGN_IDENTITY"}) + @Parameter({"MAC_PKG", "EXPIRED_SIGN_IDENTITY"}) + + @Parameter({"IMAGE", "EXPIRED_CODESIGN_SIGN_IDENTITY"}) + @Parameter({"MAC_DMG", "EXPIRED_CODESIGN_SIGN_IDENTITY"}) + @Parameter({"MAC_PKG", "EXPIRED_CODESIGN_SIGN_IDENTITY"}) + + @Parameter({"MAC_PKG", "GOOD_CODESIGN_SIGN_IDENTITY", "EXPIRED_PKG_SIGN_IDENTITY"}) + @Parameter({"MAC_PKG", "EXPIRED_CODESIGN_SIGN_IDENTITY", "GOOD_PKG_SIGN_IDENTITY"}) + public static void testExpiredCertificate(PackageType type, SignOption... options) { + + final var keychain = SigningBase.StandardKeychain.EXPIRED.spec().keychain(); + + MacSign.Keychain.withAddedKeychains(List.of(keychain), () -> { + final var cmd = JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .addArguments("--mac-sign") + .addArguments("--mac-signing-keychain", keychain.name()) + .addArguments(Stream.of(options).map(SignOption::args).flatMap(List::stream).toList()) + .setPackageType(type); + + SignOption.configureOutputValidation(cmd, Stream.of(options).filter(SignOption::expired).toList(), opt -> { + return JPackageStringBundle.MAIN.cannedFormattedString("error.certificate.expired", opt.identityName()); + }).execute(1); + }); + } + + @Test + @Parameter({"IMAGE", "GOOD_SIGNING_KEY_USER_NAME"}) + @Parameter({"MAC_DMG", "GOOD_SIGNING_KEY_USER_NAME"}) + @Parameter({"MAC_PKG", "GOOD_SIGNING_KEY_USER_NAME_PKG", "GOOD_SIGNING_KEY_USER_NAME"}) + + @Parameter({"IMAGE", "GOOD_CODESIGN_SIGN_IDENTITY"}) + @Parameter({"MAC_PKG", "GOOD_CODESIGN_SIGN_IDENTITY", "GOOD_PKG_SIGN_IDENTITY"}) + @Parameter({"MAC_PKG", "GOOD_PKG_SIGN_IDENTITY"}) + public static void testMultipleCertificates(PackageType type, SignOption... options) { + + final var keychain = SigningBase.StandardKeychain.DUPLICATE.spec().keychain(); + + MacSign.Keychain.withAddedKeychains(List.of(keychain), () -> { + final var cmd = JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .addArguments("--mac-sign") + .addArguments("--mac-signing-keychain", keychain.name()) + .addArguments(Stream.of(options).map(SignOption::args).flatMap(List::stream).toList()) + .setPackageType(type); + + SignOption.configureOutputValidation(cmd, List.of(options), opt -> { + return JPackageStringBundle.MAIN.cannedFormattedString("error.multiple.certs.found", opt.identityName(), keychain.name()); + }).execute(1); + }); + } + + @Test + @ParameterSupplier + public static void testSelectSigningIdentity(String signingKeyUserName, CertificateRequest certRequest) { + + final var keychain = SigningBase.StandardKeychain.MAIN.spec().keychain(); + + MacSign.Keychain.withAddedKeychains(List.of(keychain), () -> { + final var cmd = JPackageCommand.helloAppImage() + .setFakeRuntime() + .addArguments("--mac-sign") + .addArguments("--mac-signing-keychain", keychain.name()) + .addArguments("--mac-signing-key-user-name", signingKeyUserName); + + cmd.executeAndAssertHelloAppImageCreated(); + + MacSignVerify.assertSigned(cmd.outputBundle(), certRequest); + }); + } + + public static Collection testSelectSigningIdentity() { + return Stream.of( + SigningBase.StandardCertificateRequest.CODESIGN, + SigningBase.StandardCertificateRequest.CODESIGN_UNICODE + ).map(SigningBase.StandardCertificateRequest::spec).mapMulti((certRequest, acc) -> { + acc.accept(new Object[] {certRequest.shortName(), certRequest}); + acc.accept(new Object[] {certRequest.name(), certRequest}); + }).toList(); + } + + enum SignOption { + EXPIRED_SIGNING_KEY_USER_NAME("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), true, false), + EXPIRED_SIGNING_KEY_USER_NAME_PKG("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.PKG_EXPIRED.spec(), true, false), + EXPIRED_SIGN_IDENTITY("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), false, false), + EXPIRED_CODESIGN_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN_EXPIRED.spec(), false, true), + EXPIRED_PKG_SIGN_IDENTITY("--mac-installer-sign-identity", SigningBase.StandardCertificateRequest.PKG_EXPIRED.spec(), false, true), + GOOD_SIGNING_KEY_USER_NAME("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.CODESIGN.spec(), true, false), + GOOD_SIGNING_KEY_USER_NAME_PKG("--mac-signing-key-user-name", SigningBase.StandardCertificateRequest.PKG.spec(), true, false), + GOOD_CODESIGN_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.CODESIGN.spec(), false, true), + GOOD_PKG_SIGN_IDENTITY("--mac-app-image-sign-identity", SigningBase.StandardCertificateRequest.PKG.spec(), false, true); + + SignOption(String option, MacSign.CertificateRequest cert, boolean shortName, boolean passThrough) { + this.option = Objects.requireNonNull(option); + this.cert = Objects.requireNonNull(cert); + this.shortName = shortName; + this.passThrough = passThrough; + } + + boolean passThrough() { + return passThrough; + } + + boolean expired() { + return cert.expired(); + } + + String identityName() { + return cert.name(); + } + + List args() { + return List.of(option, shortName ? cert.shortName() : cert.name()); + } + + static JPackageCommand configureOutputValidation(JPackageCommand cmd, List options, + Function conv) { + options.stream().filter(SignOption::passThrough) + .map(conv) + .map(CannedFormattedString::getValue) + .map(TKit::assertTextStream) + .map(TKit.TextStreamVerifier::negate) + .forEach(cmd::validateOutput); + + options.stream().filter(Predicate.not(SignOption::passThrough)) + .map(conv) + .map(CannedFormattedString::getValue) + .map(TKit::assertTextStream) + .forEach(cmd::validateOutput); + + return cmd; } - cmd.execute(1); + private final String option; + private final MacSign.CertificateRequest cert; + private final boolean shortName; + private final boolean passThrough; } } diff --git a/test/jdk/tools/jpackage/macosx/base/SigningBase.java b/test/jdk/tools/jpackage/macosx/base/SigningBase.java index e3237197c74..5484245f111 100644 --- a/test/jdk/tools/jpackage/macosx/base/SigningBase.java +++ b/test/jdk/tools/jpackage/macosx/base/SigningBase.java @@ -22,16 +22,18 @@ */ import java.nio.file.Path; +import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.stream.Stream; -import jdk.jpackage.test.Executor; -import jdk.jpackage.test.Executor.Result; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.MacSign; -import jdk.jpackage.test.MacSign.CertificateType; import jdk.jpackage.test.MacSign.CertificateRequest; +import jdk.jpackage.test.MacSign.CertificateType; import jdk.jpackage.test.MacSign.KeychainWithCertsSpec; +import jdk.jpackage.test.MacSign.ResolvedKeychain; +import jdk.jpackage.test.MacSignVerify; import jdk.jpackage.test.TKit; @@ -64,10 +66,14 @@ public class SigningBase { public enum StandardCertificateRequest { - APP_IMAGE(cert().userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - INSTALLER(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), - APP_IMAGE_UNICODE(cert().userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), - INSTALLER_UNICODE(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])); + CODESIGN(cert().userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + CODESIGN_COPY(cert().days(100).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + PKG(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + PKG_COPY(cert().type(CertificateType.INSTALLER).days(100).userName(DEV_NAMES[CertIndex.ASCII_INDEX.value()])), + CODESIGN_UNICODE(cert().userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), + PKG_UNICODE(cert().type(CertificateType.INSTALLER).userName(DEV_NAMES[CertIndex.UNICODE_INDEX.value()])), + CODESIGN_EXPIRED(cert().expired().userName("expired jpackage test")), + PKG_EXPIRED(cert().expired().type(CertificateType.INSTALLER).userName("expired jpackage test")); StandardCertificateRequest(CertificateRequest.Builder specBuilder) { this.spec = specBuilder.create(); @@ -85,7 +91,21 @@ private static CertificateRequest.Builder cert() { } public enum StandardKeychain { - MAIN(DEFAULT_KEYCHAIN, StandardCertificateRequest.values()); + MAIN(DEFAULT_KEYCHAIN, + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_UNICODE, + StandardCertificateRequest.PKG_UNICODE), + EXPIRED("jpackagerTest-expired.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_EXPIRED, + StandardCertificateRequest.PKG_EXPIRED), + DUPLICATE("jpackagerTest-duplicate.keychain", + StandardCertificateRequest.CODESIGN, + StandardCertificateRequest.PKG, + StandardCertificateRequest.CODESIGN_COPY, + StandardCertificateRequest.PKG_COPY); StandardKeychain(String keychainName, StandardCertificateRequest... certs) { this(keychainName, certs[0].spec(), Stream.of(certs).skip(1).map(StandardCertificateRequest::spec).toArray(CertificateRequest[]::new)); @@ -94,11 +114,15 @@ public enum StandardKeychain { StandardKeychain(String keychainName, CertificateRequest cert, CertificateRequest... otherCerts) { final var builder = keychain(keychainName).addCert(cert); List.of(otherCerts).forEach(builder::addCert); - this.spec = builder.create(); + this.spec = new ResolvedKeychain(builder.create()); } public KeychainWithCertsSpec spec() { - return spec; + return spec.spec(); + } + + public X509Certificate mapCertificateRequest(CertificateRequest certRequest) { + return Objects.requireNonNull(spec.mapCertificateRequests().get(certRequest)); } private static KeychainWithCertsSpec.Builder keychain(String name) { @@ -113,7 +137,7 @@ private static List signingEnv() { return Stream.of(values()).map(StandardKeychain::spec).toList(); } - private final KeychainWithCertsSpec spec; + private final ResolvedKeychain spec; } public static void setUp() { @@ -131,7 +155,7 @@ public static void verifySignTestEnvReady() { } private final class Inner { - private final static boolean SIGN_ENV_READY = MacSign.isDeployed(StandardKeychain.signingEnv()); + private static final boolean SIGN_ENV_READY = MacSign.isDeployed(StandardKeychain.signingEnv()); } enum CertIndex { @@ -199,165 +223,60 @@ public static String getKeyChain() { return DEFAULT_KEYCHAIN; } - // Note: It is not clear if we can combine "--verify" and "--display", so - // we testing them separately. Since JDK-8298488 unsigned app images are - // actually signed with adhoc signature and it will pass "--verify", so in - // addition we will check certificate name which was used to sign. - private static enum CodesignCheckType { - VERIFY, // Runs codesign with "--verify" to check signature and 0 exit code - VERIFY_UNSIGNED, // Runs codesign with "--verify" to check signature and 1 exit code - DISPLAY // Runs codesign with "--display --verbose=4" to get info about signature - }; - - private static void checkString(List result, String lookupString) { - TKit.assertTextStream(lookupString).predicate( - (line, what) -> line.trim().contains(what)).apply(result.stream()); - } - - @SuppressWarnings("fallthrough") - private static List codesignResult(Path target, CodesignCheckType type) { - int exitCode = 0; - Executor executor = new Executor().setExecutable("/usr/bin/codesign"); - switch (type) { - case VERIFY_UNSIGNED: - exitCode = 1; - case VERIFY: - executor.addArguments("--verify", "--deep", "--strict", - "--verbose=2", target.toString()); - break; - case DISPLAY: - executor.addArguments("--display", "--verbose=4", target.toString()); - break; - default: - TKit.error("Unknown CodesignCheckType: " + type); - break; - } - return executor.saveOutput().execute(exitCode).getOutput(); - } - - private static void verifyCodesignResult(List result, Path target, - boolean signed, CodesignCheckType type, int certIndex) { - result.stream().forEachOrdered(TKit::trace); - String lookupString; - switch (type) { - case VERIFY: - lookupString = target.toString() + ": valid on disk"; - checkString(result, lookupString); - lookupString = target.toString() + ": satisfies its Designated Requirement"; - checkString(result, lookupString); - break; - case VERIFY_UNSIGNED: - lookupString = target.toString() + ": code object is not signed at all"; - checkString(result, lookupString); - break; - case DISPLAY: - if (signed) { - lookupString = "Authority=" + getAppCert(certIndex); - } else { - lookupString = "Signature=adhoc"; - } - checkString(result, lookupString); - break; - default: - TKit.error("Unknown CodesignCheckType: " + type); - break; - } - } - - private static Result spctlResult(Path target, String type) { - Result result = new Executor() - .setExecutable("/usr/sbin/spctl") - .addArguments("-vvv", "--assess", "--type", type, - target.toString()) - .saveOutput() - .executeWithoutExitCodeCheck(); - - // allow exit code 3 for not being notarized - if (result.getExitCode() != 3) { - result.assertExitCodeIsZero(); - } - return result; - } - - private static void verifySpctlResult(List output, Path target, - String type, int exitCode, int certIndex) { - output.stream().forEachOrdered(TKit::trace); - String lookupString; - - if (exitCode == 0) { - lookupString = target.toString() + ": accepted"; - checkString(output, lookupString); - } else if (exitCode == 3) { - // allow failure purely for not being notarized - lookupString = target.toString() + ": rejected"; - checkString(output, lookupString); - } - - if (type.equals("install")) { - lookupString = "origin=" + getInstallerCert(certIndex); - } else { - lookupString = "origin=" + getAppCert(certIndex); - } - checkString(output, lookupString); - } - - private static List pkgutilResult(Path target, boolean signed) { - List result = new Executor() - .setExecutable("/usr/sbin/pkgutil") - .addArguments("--check-signature", - target.toString()) - .saveOutput() - .execute(signed ? 0 : 1) - .getOutput(); - - return result; - } - - private static void verifyPkgutilResult(List result, boolean signed, - int certIndex) { - result.stream().forEachOrdered(TKit::trace); + public static void verifyCodesign(Path target, boolean signed, int certIndex) { if (signed) { - String lookupString = "Status: signed by"; - checkString(result, lookupString); - lookupString = "1. " + getInstallerCert(certIndex); - checkString(result, lookupString); + final var certRequest = getCertRequest(certIndex); + MacSignVerify.assertSigned(target, certRequest); } else { - String lookupString = "Status: no signature"; - checkString(result, lookupString); + MacSignVerify.assertAdhocSigned(target); } } - public static void verifyCodesign(Path target, boolean signed, int certIndex) { - List result = codesignResult(target, CodesignCheckType.VERIFY); - verifyCodesignResult(result, target, signed, CodesignCheckType.VERIFY, certIndex); - - result = codesignResult(target, CodesignCheckType.DISPLAY); - verifyCodesignResult(result, target, signed, CodesignCheckType.DISPLAY, certIndex); - } - // Since we no longer have unsigned app image, but we need to check // DMG which is not adhoc or certificate signed and we cannot use verifyCodesign // for this. verifyDMG() is introduced to check that DMG is unsigned. // Should not be used to validated anything else. public static void verifyDMG(Path target) { if (!target.toString().toLowerCase().endsWith(".dmg")) { - TKit.error("Unexpected target: " + target); + throw new IllegalArgumentException("Unexpected target: " + target); } - List result = codesignResult(target, CodesignCheckType.VERIFY_UNSIGNED); - verifyCodesignResult(result, target, false, CodesignCheckType.VERIFY_UNSIGNED, -1); + MacSignVerify.assertUnsigned(target); } public static void verifySpctl(Path target, String type, int certIndex) { - Result result = spctlResult(target, type); - List output = result.getOutput(); + final var standardCertIndex = Stream.of(CertIndex.values()).filter(v -> { + return v.value() == certIndex; + }).findFirst().orElseThrow(); + + final var standardType = Stream.of(MacSignVerify.SpctlType.values()).filter(v -> { + return v.value().equals(type); + }).findFirst().orElseThrow(); + + final String expectedSignOrigin; + if (standardCertIndex == CertIndex.INVALID_INDEX) { + expectedSignOrigin = null; + } else if (standardType == MacSignVerify.SpctlType.EXEC) { + expectedSignOrigin = getCertRequest(certIndex).name(); + } else if (standardType == MacSignVerify.SpctlType.INSTALL) { + expectedSignOrigin = getPkgCertRequest(certIndex).name(); + } else { + throw new IllegalArgumentException(); + } + + final var signOrigin = MacSignVerify.findSpctlSignOrigin(standardType, target).orElse(null); - verifySpctlResult(output, target, type, result.getExitCode(), certIndex); + TKit.assertEquals(signOrigin, expectedSignOrigin, + String.format("Check [%s] has sign origin as expected", target)); } public static void verifyPkgutil(Path target, boolean signed, int certIndex) { - List result = pkgutilResult(target, signed); - verifyPkgutilResult(result, signed, certIndex); + if (signed) { + final var certRequest = getPkgCertRequest(certIndex); + MacSignVerify.assertPkgSigned(target, certRequest, StandardKeychain.MAIN.mapCertificateRequest(certRequest)); + } else { + MacSignVerify.assertUnsigned(target); + } } public static void verifyAppImageSignature(JPackageCommand appImageCmd, @@ -378,4 +297,31 @@ public static void verifyAppImageSignature(JPackageCommand appImageCmd, } } + private static CertificateRequest getCertRequest(int certIndex) { + switch (CertIndex.values()[certIndex]) { + case ASCII_INDEX -> { + return StandardCertificateRequest.CODESIGN.spec(); + } + case UNICODE_INDEX -> { + return StandardCertificateRequest.CODESIGN_UNICODE.spec(); + } + default -> { + throw new IllegalArgumentException(); + } + } + } + + private static CertificateRequest getPkgCertRequest(int certIndex) { + switch (CertIndex.values()[certIndex]) { + case ASCII_INDEX -> { + return StandardCertificateRequest.PKG.spec(); + } + case UNICODE_INDEX -> { + return StandardCertificateRequest.PKG_UNICODE.spec(); + } + default -> { + throw new IllegalArgumentException(); + } + } + } } diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index c14cd50cc11..15b61763562 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -21,17 +21,20 @@ * questions. */ +import static jdk.internal.util.OperatingSystem.LINUX; +import static jdk.internal.util.OperatingSystem.MACOS; +import static java.util.stream.Collectors.joining; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import jdk.jpackage.test.PackageTest; import jdk.jpackage.test.TKit; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Parameter; import java.util.Arrays; import java.util.Collection; import java.util.List; -import static java.util.stream.Collectors.joining; import java.util.stream.Stream; import jdk.jpackage.internal.util.FileUtils; import jdk.jpackage.internal.util.function.ThrowingFunction; @@ -56,6 +59,7 @@ public class AppContentTest { private static final String TEST_JAVA = "apps/PrintEnv.java"; private static final String TEST_DUKE = "apps/dukeplug.png"; + private static final String TEST_DUKE_LINK = "dukeplugLink.txt"; private static final String TEST_DIR = "apps"; private static final String TEST_BAD = "non-existant"; @@ -67,24 +71,20 @@ public class AppContentTest { // Need to prepare arguments for `--app-content` accordingly. private static final boolean copyInResources = TKit.isOSX(); - private final List testPathArgs; - - @Parameters - public static Collection data() { - return List.of(new String[][]{ - {TEST_JAVA, TEST_DUKE}, // include two files in two options - {TEST_JAVA, TEST_BAD}, // try to include non-existant content - {TEST_JAVA + "," + TEST_DUKE, TEST_DIR}, // two files in one option, - // and a dir tree in another option. - }); - } - - public AppContentTest(String... testPathArgs) { - this.testPathArgs = List.of(testPathArgs); - } + private static final String RESOURCES_DIR = "Resources"; + private static final String LINKS_DIR = "Links"; @Test - public void test() throws Exception { + // include two files in two options + @Parameter({TEST_JAVA, TEST_DUKE}) + // try to include non-existant content + @Parameter({TEST_JAVA, TEST_BAD}) + // two files in one option and a dir tree in another option. + @Parameter({TEST_JAVA + "," + TEST_DUKE, TEST_DIR}) + // include one file and one link to the file + @Parameter(value = {TEST_JAVA, TEST_DUKE_LINK}, ifOS = {MACOS,LINUX}) + public void test(String... args) throws Exception { + final List testPathArgs = List.of(args); final int expectedJPackageExitCode; if (testPathArgs.contains(TEST_BAD)) { expectedJPackageExitCode = 1; @@ -98,15 +98,19 @@ public void test() throws Exception { .addRunOnceInitializer(appContentInitializer::initAppContent) .addInitializer(appContentInitializer::applyTo) .addInstallVerifier(cmd -> { - Path baseDir = getAppContentRoot(cmd); for (String arg : testPathArgs) { List paths = Arrays.asList(arg.split(",")); for (String p : paths) { Path name = Path.of(p).getFileName(); - TKit.assertPathExists(baseDir.resolve(name), true); + if (isSymlinkPath(name)) { + TKit.assertSymbolicLinkExists(getAppContentRoot(cmd) + .resolve(LINKS_DIR).resolve(name)); + } else { + TKit.assertPathExists(getAppContentRoot(cmd) + .resolve(name), true); + } } } - }) .setExpectedExitCode(expectedJPackageExitCode) .run(); @@ -115,12 +119,16 @@ public void test() throws Exception { private static Path getAppContentRoot(JPackageCommand cmd) { Path contentDir = cmd.appLayout().contentDirectory(); if (copyInResources) { - return contentDir.resolve("Resources"); + return contentDir.resolve(RESOURCES_DIR); } else { return contentDir; } } + private static boolean isSymlinkPath(Path v) { + return v.getFileName().toString().contains("Link"); + } + private static final class AppContentInitializer { AppContentInitializer(List appContentArgs) { appContentPathGroups = appContentArgs.stream().map(arg -> { @@ -144,7 +152,7 @@ void applyTo(JPackageCommand cmd) { } private static Path copyAppContentPath(Path appContentPath) throws IOException { - var appContentArg = TKit.createTempDirectory("app-content").resolve("Resources"); + var appContentArg = TKit.createTempDirectory("app-content").resolve(RESOURCES_DIR); var srcPath = TKit.TEST_SRC_ROOT.resolve(appContentPath); var dstPath = appContentArg.resolve(srcPath.getFileName()); Files.createDirectories(dstPath.getParent()); @@ -152,20 +160,46 @@ private static Path copyAppContentPath(Path appContentPath) throws IOException { return appContentArg; } - private static List initAppContentPaths(List appContentPaths) { + private static Path createAppContentLink(Path appContentPath) throws IOException { + var appContentArg = TKit.createTempDirectory("app-content"); + Path dstPath; if (copyInResources) { - return appContentPaths.stream().map(appContentPath -> { - if (appContentPath.endsWith(TEST_BAD)) { - return appContentPath; - } else { - return ThrowingFunction.toFunction( - AppContentInitializer::copyAppContentPath).apply( - appContentPath); - } - }).toList(); + appContentArg = appContentArg.resolve(RESOURCES_DIR); + dstPath = appContentArg.resolve(LINKS_DIR) + .resolve(appContentPath.getFileName()); } else { - return appContentPaths.stream().map(TKit.TEST_SRC_ROOT::resolve).toList(); + appContentArg = appContentArg.resolve(LINKS_DIR); + dstPath = appContentArg.resolve(appContentPath.getFileName()); } + + Files.createDirectories(dstPath.getParent()); + + // Create target file for a link + String tagetName = dstPath.getFileName().toString().replace("Link", ""); + Path targetPath = dstPath.getParent().resolve(tagetName); + Files.write(targetPath, "foo".getBytes()); + // Create link + Files.createSymbolicLink(dstPath, targetPath.getFileName()); + + return appContentArg; + } + + private static List initAppContentPaths(List appContentPaths) { + return appContentPaths.stream().map(appContentPath -> { + if (appContentPath.endsWith(TEST_BAD)) { + return appContentPath; + } else if (isSymlinkPath(appContentPath)) { + return ThrowingFunction.toFunction( + AppContentInitializer::createAppContentLink).apply( + appContentPath); + } else if (copyInResources) { + return ThrowingFunction.toFunction( + AppContentInitializer::copyAppContentPath).apply( + appContentPath); + } else { + return TKit.TEST_SRC_ROOT.resolve(appContentPath); + } + }).toList(); } private List jpackageArgs; diff --git a/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java b/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java index 772370b0f8c..9a6468e0771 100644 --- a/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java +++ b/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java @@ -82,7 +82,7 @@ public static void test() throws Exception { TKit.assertTextStream(expectedEnvVarValue) .predicate(TKit.isLinux() ? String::endsWith : String::equals) .label(String.format("value of %s env variable", envVarName)) - .apply(Stream.of(actualEnvVarValue)); + .apply(List.of(actualEnvVarValue)); final String javaLibraryPath = getValue.apply(2, "java.library.path"); TKit.assertTrue( diff --git a/test/jdk/tools/jpackage/share/BasicTest.java b/test/jdk/tools/jpackage/share/BasicTest.java index 68c1b2c76cb..b55f7bb87ad 100644 --- a/test/jdk/tools/jpackage/share/BasicTest.java +++ b/test/jdk/tools/jpackage/share/BasicTest.java @@ -114,8 +114,8 @@ public void testJpackageProps() { List output = HelloApp.executeLauncher(cmd).getOutput(); - TKit.assertTextStream("jpackage.app-version=" + appVersion).apply(output.stream()); - TKit.assertTextStream("jpackage.app-path=").apply(output.stream()); + TKit.assertTextStream("jpackage.app-version=" + appVersion).apply(output); + TKit.assertTextStream("jpackage.app-path=").apply(output); } @Test @@ -169,9 +169,9 @@ public void testHelp() { }; TKit.trace("Check parameters in help text"); - TKit.assertNotEquals(0, countStrings.apply(List.of(expectedPrefix)), + TKit.assertNotEquals(0, countStrings.apply(List.of(expectedPrefix)).longValue(), "Check help text contains platform specific parameters"); - TKit.assertEquals(0, countStrings.apply(unexpectedPrefixes), + TKit.assertEquals(0, countStrings.apply(unexpectedPrefixes).longValue(), "Check help text doesn't contain unexpected parameters"); } @@ -221,12 +221,12 @@ public void testVerbose() { expectedVerboseOutputStrings.forEach(str -> { TKit.assertTextStream(str).label("regular output") .predicate(String::contains).negate() - .apply(nonVerboseOutput.stream()); + .apply(nonVerboseOutput); }); expectedVerboseOutputStrings.forEach(str -> { TKit.assertTextStream(str).label("verbose output") - .apply(verboseOutput[0].stream()); + .apply(verboseOutput[0]); }); } @@ -237,20 +237,21 @@ public void testErrorsAlwaysPrinted(boolean verbose) { final var cmd = JPackageCommand.helloAppImage() .ignoreDefaultVerbose(true) .useToolProvider(false) + .discardStdout(true) .removeArgumentWithValue("--main-class"); if (verbose) { cmd.addArgument("--verbose"); } - final var textVerifier = Stream.of( + cmd.validateOutput(Stream.of( List.of("error.no-main-class-with-main-jar", "hello.jar"), List.of("error.no-main-class-with-main-jar.advice", "hello.jar") ).map(args -> { return JPackageStringBundle.MAIN.cannedFormattedString(args.getFirst(), args.subList(1, args.size()).toArray()); - }).map(CannedFormattedString::getValue).map(TKit::assertTextStream).reduce(TKit.TextStreamVerifier::andThen).orElseThrow(); + }).toArray(CannedFormattedString[]::new)); - textVerifier.apply(cmd.saveConsoleOutput(true).execute(1).getOutput().stream().filter(Predicate.not(JPackageCommand::withTimestamp))); + cmd.execute(1); } @Test diff --git a/test/jdk/tools/jpackage/share/EmptyFolderTest.java b/test/jdk/tools/jpackage/share/EmptyFolderTest.java index 40a4db03d6f..f2cb72e097d 100644 --- a/test/jdk/tools/jpackage/share/EmptyFolderTest.java +++ b/test/jdk/tools/jpackage/share/EmptyFolderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -97,16 +97,21 @@ private static void createDirTree(JPackageCommand cmd) throws IOException { } private static void validateDirTree(JPackageCommand cmd) { + // When MSI package is unpacked and not installed, empty directories are not created. + final boolean emptyDirSupported = !(PackageType.WINDOWS.contains(cmd.packageType()) && cmd.isPackageUnpacked()); + validateDirTree(cmd, emptyDirSupported); + } + + private static void validateDirTree(JPackageCommand cmd, boolean emptyDirSupported) { var outputBaseDir = cmd.appLayout().appDirectory(); var inputBaseDir = cmd.inputDir(); for (var path : DIR_STRUCT) { Path outputPath = outputBaseDir.resolve(path); if (isFile(outputPath)) { TKit.assertFileExists(outputPath); - } else if (!PackageType.WINDOWS.contains(cmd.packageType())) { + } else if (emptyDirSupported) { TKit.assertDirectoryExists(outputPath); } else if (inputBaseDir.resolve(path).toFile().list().length == 0) { - // MSI packages don't support empty folders TKit.assertPathExists(outputPath, false); } else { TKit.assertDirectoryNotEmpty(outputPath); diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index cb302734a43..c352decc0f3 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -41,6 +41,7 @@ import java.util.regex.Pattern; import java.util.stream.Stream; import jdk.jpackage.internal.util.TokenReplace; +import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.CannedFormattedString; @@ -644,6 +645,44 @@ public static Collection testLinux() { return toTestArgs(testCases.stream()); } + @Test(ifOS = MACOS) + @Parameter({"MAC_PKG", "--mac-signing-key-user-name", "false"}) + @Parameter({"MAC_DMG", "--mac-signing-key-user-name", "false"}) + @Parameter({"IMAGE", "--mac-signing-key-user-name", "false"}) + @Parameter({"MAC_PKG", "--mac-app-image-sign-identity", "true"}) + @Parameter({"MAC_DMG", "--mac-app-image-sign-identity", "true"}) + @Parameter({"IMAGE", "--mac-app-image-sign-identity", "true"}) + @Parameter({"MAC_PKG", "--mac-installer-sign-identity", "true"}) + public static void testMacSigningIdentityValidation(PackageType type, String option, boolean passThroughOption) { + + final var signingId = "foo"; + + final List errorMessages = new ArrayList<>(); + errorMessages.add(JPackageStringBundle.MAIN.cannedFormattedString( + "error.cert.not.found", "Developer ID Application: " + signingId, "")); + errorMessages.addAll(Stream.of( + "error.explicit-sign-no-cert", + "error.explicit-sign-no-cert.advice" + ).map(JPackageStringBundle.MAIN::cannedFormattedString).toList()); + + final var cmd = JPackageCommand.helloAppImage() + .ignoreDefaultVerbose(true) + .addArguments("--mac-sign") + .addArguments(option, signingId) + .setPackageType(type); + + if (passThroughOption) { + errorMessages.stream() + .map(CannedFormattedString::getValue) + .map(TKit::assertTextStream) + .map(TKit.TextStreamVerifier::negate).forEach(cmd::validateOutput); + } else { + cmd.validateOutput(errorMessages.toArray(CannedFormattedString[]::new)); + } + + cmd.execute(1); + } + private static void duplicate(TestSpec.Builder builder, Consumer accumulator, Consumer mutator) { accumulator.accept(builder.create()); mutator.accept(builder); @@ -732,7 +771,7 @@ private static void defaultInit(JPackageCommand cmd, List // It will affect jpackage error messages if the command line is malformed. cmd.ignoreDefaultVerbose(true); - // Ignore external runtime as it will interfer + // Ignore external runtime as it will interfere // with jpackage arguments in this test. cmd.ignoreDefaultRuntime(true); diff --git a/test/jdk/tools/jpackage/share/IconTest.java b/test/jdk/tools/jpackage/share/IconTest.java index 6d84714f28b..df207d1c30a 100644 --- a/test/jdk/tools/jpackage/share/IconTest.java +++ b/test/jdk/tools/jpackage/share/IconTest.java @@ -191,7 +191,7 @@ private ThrowingBiConsumer createBundleVerifie var verifier = createConsoleOutputVerifier(cmd.name(), config.get( Launcher.Main), null); if (verifier != null) { - verifier.apply(result.getOutput().stream()); + verifier.apply(result.getOutput()); } if (config.containsKey(Launcher.Additional)) { @@ -199,7 +199,7 @@ private ThrowingBiConsumer createBundleVerifie Launcher.Additional.launcherName, config.get( Launcher.Additional), config.get(Launcher.Main)); if (verifier != null) { - verifier.apply(result.getOutput().stream()); + verifier.apply(result.getOutput()); } } }; diff --git a/test/jdk/tools/jpackage/share/InstallDirTest.java b/test/jdk/tools/jpackage/share/InstallDirTest.java index 2c14e863910..bbdc118d60b 100644 --- a/test/jdk/tools/jpackage/share/InstallDirTest.java +++ b/test/jdk/tools/jpackage/share/InstallDirTest.java @@ -113,7 +113,7 @@ public static void testLinuxInvalid(String installDir) { .run(); } - record DmgTestSpec(Path installDir, boolean installDirIgnored, boolean runtimeInstaller) { + record DmgTestSpec(Path installDir, boolean runtimeInstaller) { DmgTestSpec { Objects.requireNonNull(installDir); @@ -125,15 +125,8 @@ static Builder build() { static final class Builder { - Builder ignoredInstallDir(String v) { - installDir = Path.of(v); - installDirIgnored = true; - return this; - } - Builder acceptedInstallDir(String v) { installDir = Path.of(v); - installDirIgnored = false; return this; } @@ -143,11 +136,10 @@ Builder runtimeInstaller() { } DmgTestSpec create() { - return new DmgTestSpec(installDir, installDirIgnored, runtimeInstaller); + return new DmgTestSpec(installDir, runtimeInstaller); } private Path installDir; - private boolean installDirIgnored; private boolean runtimeInstaller; } @@ -155,9 +147,6 @@ DmgTestSpec create() { public String toString() { final var sb = new StringBuilder(); sb.append(installDir); - if (installDirIgnored) { - sb.append(", ignore"); - } if (runtimeInstaller) { sb.append(", runtime"); } @@ -176,27 +165,8 @@ void run() { test.addInitializer(JPackageCommand::setFakeRuntime).addInitializer(cmd -> { cmd.addArguments("--install-dir", installDir); - cmd.validateOutput(createInstallDirWarningVerifier()); }).run(Action.CREATE_AND_UNPACK); } - - private TextStreamVerifier createInstallDirWarningVerifier() { - final var verifier = TKit.assertTextStream( - JPackageStringBundle.MAIN.cannedFormattedString("message.install-dir-ignored", defaultDmgInstallDir()).getValue()); - if (installDirIgnored) { - return verifier; - } else { - return verifier.negate(); - } - } - - private String defaultDmgInstallDir() { - if (runtimeInstaller) { - return "/Library/Java/JavaVirtualMachines"; - } else { - return "/Applications"; - } - } } @Test(ifOS = OperatingSystem.MACOS) @@ -207,19 +177,19 @@ public static void testDmg(DmgTestSpec testSpec) { public static List testDmg() { return Stream.of( - DmgTestSpec.build().ignoredInstallDir("/foo"), - DmgTestSpec.build().ignoredInstallDir("/foo/bar"), - DmgTestSpec.build().ignoredInstallDir("/foo").runtimeInstaller(), - DmgTestSpec.build().ignoredInstallDir("/foo/bar").runtimeInstaller(), + DmgTestSpec.build().acceptedInstallDir("/foo"), + DmgTestSpec.build().acceptedInstallDir("/foo/bar"), + DmgTestSpec.build().acceptedInstallDir("/foo").runtimeInstaller(), + DmgTestSpec.build().acceptedInstallDir("/foo/bar").runtimeInstaller(), - DmgTestSpec.build().ignoredInstallDir("/Library/Java/JavaVirtualMachines"), - DmgTestSpec.build().ignoredInstallDir("/Applications").runtimeInstaller(), + DmgTestSpec.build().acceptedInstallDir("/Library/Java/JavaVirtualMachines"), + DmgTestSpec.build().acceptedInstallDir("/Applications").runtimeInstaller(), DmgTestSpec.build().acceptedInstallDir("/Applications"), - DmgTestSpec.build().ignoredInstallDir("/Applications/foo/bar/buz"), + DmgTestSpec.build().acceptedInstallDir("/Applications/foo/bar/buz"), DmgTestSpec.build().runtimeInstaller().acceptedInstallDir("/Library/Java/JavaVirtualMachines"), - DmgTestSpec.build().runtimeInstaller().ignoredInstallDir("/Library/Java/JavaVirtualMachines/foo/bar/buz") + DmgTestSpec.build().runtimeInstaller().acceptedInstallDir("/Library/Java/JavaVirtualMachines/foo/bar/buz") ).map(DmgTestSpec.Builder::create).map(testSpec -> { return new Object[] { testSpec }; }).toList(); diff --git a/test/jdk/tools/jpackage/share/JLinkOptionsTest.java b/test/jdk/tools/jpackage/share/JLinkOptionsTest.java index a882fd15f18..4c4d7d3e5a3 100644 --- a/test/jdk/tools/jpackage/share/JLinkOptionsTest.java +++ b/test/jdk/tools/jpackage/share/JLinkOptionsTest.java @@ -129,12 +129,12 @@ public void test(String javaAppDesc, String[] jpackageArgs, String[] required, S List mods = List.of(release.get(1)); if (required != null) { for (String s : required) { - TKit.assertTextStream(s).label("mods").apply(mods.stream()); + TKit.assertTextStream(s).label("mods").apply(mods); } } if (prohibited != null) { for (String s : prohibited) { - TKit.assertTextStream(s).label("mods").negate().apply(mods.stream()); + TKit.assertTextStream(s).label("mods").negate().apply(mods); } } } diff --git a/test/jdk/tools/jpackage/share/JavaOptionsEqualsTest.java b/test/jdk/tools/jpackage/share/JavaOptionsEqualsTest.java index 220c55b5e50..5a75529cb7b 100644 --- a/test/jdk/tools/jpackage/share/JavaOptionsEqualsTest.java +++ b/test/jdk/tools/jpackage/share/JavaOptionsEqualsTest.java @@ -82,7 +82,7 @@ public JavaOptionsEqualsTest(String javaAppDesc, String[] jpackageArgs) { public void test() { cmd.executeAndAssertHelloAppImageCreated(); List output = HelloApp.executeLauncher(cmd).getOutput(); - TKit.assertTextStream(WARNING1).apply(output.stream()); - TKit.assertTextStream(WARNING2).apply(output.stream()); + TKit.assertTextStream(WARNING1).apply(output); + TKit.assertTextStream(WARNING2).apply(output); } } diff --git a/test/jdk/tools/jpackage/share/JavaOptionsTest.java b/test/jdk/tools/jpackage/share/JavaOptionsTest.java index 014a9434cad..cb720dfb2a3 100644 --- a/test/jdk/tools/jpackage/share/JavaOptionsTest.java +++ b/test/jdk/tools/jpackage/share/JavaOptionsTest.java @@ -91,7 +91,7 @@ public void test() { // 2.) run the launcher it generated List output = HelloApp.executeLauncher(cmd).getOutput(); for (String expect : expected) { - TKit.assertTextStream(expect).apply(output.stream()); + TKit.assertTextStream(expect).apply(output); } } diff --git a/test/jdk/tools/jpackage/share/MainClassTest.java b/test/jdk/tools/jpackage/share/MainClassTest.java index 15d4e0999c5..dd89d84e46d 100644 --- a/test/jdk/tools/jpackage/share/MainClassTest.java +++ b/test/jdk/tools/jpackage/share/MainClassTest.java @@ -248,7 +248,7 @@ public void test() throws IOException { .execute().getOutput(); TKit.assertTextStream(String.format( "Error: Could not find or load main class %s", - nonExistingMainClass)).apply(output.stream()); + nonExistingMainClass)).apply(output); } } diff --git a/test/jdk/tools/jpackage/share/PostImageScriptTest.java b/test/jdk/tools/jpackage/share/PostImageScriptTest.java new file mode 100644 index 00000000000..bbdd0b7c581 --- /dev/null +++ b/test/jdk/tools/jpackage/share/PostImageScriptTest.java @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import static jdk.internal.util.OperatingSystem.LINUX; +import static jdk.internal.util.OperatingSystem.MACOS; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Predicate; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.Annotations.ParameterSupplier; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.ApplicationLayout; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageUserScript; +import jdk.jpackage.test.JPackageUserScript.WinGlobals; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.RunnablePackageTest.Action; +import jdk.jpackage.test.TKit; + +/* + * @test + * @summary jpackage with user-supplied post app image script + * @library /test/jdk/tools/jpackage/helpers + * @build jdk.jpackage.test.* + * @compile -Xlint:all -Werror PostImageScriptTest.java + * @run main/othervm/timeout=720 -Xmx512m + * jdk.jpackage.test.Main + * --jpt-run=PostImageScriptTest + */ + +public class PostImageScriptTest { + + public enum Mode { + APP, + RUNTIME, + EXTERNAL_APP_IMAGE + } + + public record TestSpec(Mode mode, boolean verifyAppImageContents) { + + public TestSpec { + Objects.requireNonNull(mode); + } + + @Override + public String toString() { + final var sb = new StringBuilder(); + sb.append(mode); + if (verifyAppImageContents) { + sb.append("; verifyAppImageContents"); + } + return sb.toString(); + } + + static PackageTest createTest(Mode mode, PackageType... types) { + if (types.length > 0 && Stream.of(types).allMatch(Predicate.not(PackageType::isEnabled))) { + throw TKit.throwSkippedException(String.format("All native packagers from %s list are disabled", List.of(types))); + } + + final var test = new PackageTest().forTypes(types); + + final var appImageCmd = JPackageCommand.helloAppImage() + .setFakeRuntime().setArgumentValue("--dest", TKit.createTempDirectory("appimage")); + + appImageCmd.execute(); + + switch (mode) { + case APP -> { + test.configureHelloApp(); + test.addInitializer(cmd -> { + cmd.addArguments("--runtime-image", appImageCmd.appRuntimeDirectory()); + }); + } + case RUNTIME -> { + test.addInitializer(cmd -> { + cmd.removeArgumentWithValue("--input"); + cmd.addArguments("--runtime-image", appImageCmd.appRuntimeDirectory()); + }); + } + case EXTERNAL_APP_IMAGE -> { + test.addInitializer(cmd -> { + cmd.removeArgumentWithValue("--input"); + cmd.addArguments("--app-image", appImageCmd.outputBundle()); + }); + } + } + + test.addInitializer(cmd -> { + cmd.setArgumentValue("--resource-dir", TKit.createTempDirectory("resources")); + }); + + return test; + } + + PackageTest createTest() { + return createTest(mode); + } + + PackageTest initTest() { + return initTest(createTest()); + } + + PackageTest initTest(PackageTest test) { + if (verifyAppImageContents) { + test.addInitializer(cmd -> { + final Path runtimeDir; + if (TKit.isLinux()) { + runtimeDir = Path.of("/").relativize(cmd.appRuntimeDirectory()); + } else if (!cmd.isRuntime()) { + runtimeDir = ApplicationLayout.platformAppImage().runtimeHomeDirectory(); + } else if (TKit.isOSX()) { + runtimeDir = Path.of("Contents/Home"); + } else { + runtimeDir = Path.of(""); + } + + final Path runtimeBinDir = runtimeDir.resolve("bin"); + + if (TKit.isWindows()) { + final List script = new ArrayList<>(); + script.addAll(WinGlobals.JS_SHELL.expr()); + script.addAll(WinGlobals.JS_FS.expr()); + script.addAll(List.of( + "WScript.Echo('PWD: ' + fs.GetFolder(shell.CurrentDirectory).Path)", + String.format("WScript.Echo('Probe directory: %s')", runtimeBinDir), + String.format("fs.GetFolder('%s')", runtimeBinDir.toString().replace('\\', '/')) + )); + JPackageUserScript.POST_IMAGE.create(cmd, script); + } else { + JPackageUserScript.POST_IMAGE.create(cmd, List.of( + "set -e", + "printf 'PWD: %s\\n' \"$PWD\"", + String.format("printf 'Probe directory: %%s\\n' '%s'", runtimeBinDir), + String.format("[ -d '%s' ]", runtimeBinDir) + )); + } + }); + } else { + JPackageUserScript.verifyPackagingDirectories(test); + } + + return test; + } + } + + @Test + @ParameterSupplier(value="createVerifyAppImageContentsTestSpecs") + @ParameterSupplier(value="createVerifyNoNewFilesInDirectoriesTestSpecs") + public static void test(TestSpec spec) { + spec.initTest().run(Action.CREATE); + } + + public static Collection createVerifyAppImageContentsTestSpecs() { + return createModeTestSpecs(true); + } + + public static Collection createVerifyNoNewFilesInDirectoriesTestSpecs() { + return createModeTestSpecs(false); + } + + @Test(ifOS = LINUX) + @ParameterSupplier(value="createVerifyAppImageContentsTestSpecs") + public static void testWithInstallDir(TestSpec spec) { + spec.initTest(spec.createTest().addInitializer(cmd -> { + cmd.addArguments("--install-dir", "/usr"); + })).run(Action.CREATE); + } + + @Test(ifOS = MACOS) + @Parameter("APP") + public static void testWithServices(Mode mode) { + final var test = TestSpec.createTest(mode, PackageType.MAC_PKG).addInitializer(cmd -> { + cmd.addArgument("--launcher-as-service"); + }); + + JPackageUserScript.verifyPackagingDirectories() + .withUnchangedDirectory("../services") + .withUnchangedDirectory("../support") + .withNonexistantPath("../packages") + .apply(test).run(Action.CREATE); + } + + @Test + public static void testEnvVars() { + final Map verifiers = new HashMap<>(); + + final var imageDirOutputPrefix = "image-dir="; + + TestSpec.createTest(Mode.APP).addInitializer(cmd -> { + final var verifier = JPackageUserScript.verifyEnvVariables().envVar("JpAppImageDir").create(); + verifiers.put(cmd.packageType(), verifier); + + final List script = new ArrayList<>(); + script.addAll(verifier.createScript()); + if (TKit.isWindows()) { + script.add("WScript.Echo('" + imageDirOutputPrefix + "' + fs.GetFolder(shell.CurrentDirectory).Path)"); + } else { + script.add("printf '" + imageDirOutputPrefix + "%s\\n' \"$PWD\""); + } + + JPackageUserScript.POST_IMAGE.create(cmd, script); + + cmd.saveConsoleOutput(true); + + }).addBundleVerifier((cmd, result) -> { + final var imageDir = result.stdout().getOutput().stream().map(String::stripLeading).filter(str -> { + return str.startsWith(imageDirOutputPrefix); + }).map(str -> { + return str.substring(imageDirOutputPrefix.length()); + }).findFirst().orElseThrow(); + final var verifier = verifiers.get(cmd.packageType()); + // On macOS, the path to app image set from jpackage starts with "/var" + // and the value of `PWD` variable in the "post-image" script is a path + // starting with "/private/var", which is a target of "/var" symlink. + // + // Can't use Path.toRealPath() to resolve symlinks because the app image directory is gone. + // + // Instead, the workaround is to strip all leading path components + // before the path component starting with "jdk.jpackage" substring. + verifier.verify(Map.of("JpAppImageDir", JPackageUserScript.ExpectedEnvVarValue.create( + stripLeadingNonJPackagePathComponents(imageDir), + PostImageScriptTest::stripLeadingNonJPackagePathComponents))); + }).run(Action.CREATE); + } + + private static Collection createModeTestSpecs(boolean verifyAppImageContents) { + return Stream.of(Mode.values()).map(mode -> { + return new TestSpec(mode, verifyAppImageContents); + }).map(spec -> { + return new Object[] {spec}; + }).toList(); + } + + private static Path stripLeadingNonJPackagePathComponents(String path) { + if (!Path.of(path).isAbsolute()) { + throw new IllegalArgumentException(); + } + + final var m = JPACKAGE_TEMP_DIR_REGEXP.matcher(path); + if (!m.find()) { + TKit.assertUnexpected(String.format("jpackage temp directory not foind in [%s] path", path)); + } + + return Path.of(m.group()); + } + + private static final Pattern JPACKAGE_TEMP_DIR_REGEXP = Pattern.compile("[\\\\/]jdk\\.jpackage.+$", + TKit.isWindows() ? 0 : Pattern.CASE_INSENSITIVE); +} diff --git a/test/jdk/tools/jpackage/share/RuntimeImageTest.java b/test/jdk/tools/jpackage/share/RuntimeImageTest.java index 0e30d7ee179..1110a813cde 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageTest.java @@ -21,13 +21,14 @@ * questions. */ +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import jdk.jpackage.test.TKit; import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Executor; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.JavaTool; -import jdk.jpackage.test.Executor; +import jdk.jpackage.test.TKit; /* * @test @@ -43,27 +44,58 @@ public class RuntimeImageTest { @Test - public static void test() throws Exception { - final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); - final Path jlinkOutputDir = workDir.resolve("temp.runtime"); - Files.createDirectories(jlinkOutputDir.getParent()); + public static void test() throws IOException { - new Executor() - .setToolProvider(JavaTool.JLINK) - .dumpOutput() - .addArguments( - "--output", jlinkOutputDir.toString(), - "--add-modules", "java.desktop", - "--strip-debug", - "--no-header-files", - "--no-man-pages", - "--strip-native-commands") - .execute(); + JPackageCommand cmd = JPackageCommand.helloAppImage(); - JPackageCommand cmd = JPackageCommand.helloAppImage() - .setArgumentValue("--runtime-image", jlinkOutputDir.toString()); + if (JPackageCommand.DEFAULT_RUNTIME_IMAGE == null) { + final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); + final Path jlinkOutputDir = workDir.resolve("temp.runtime"); + Files.createDirectories(jlinkOutputDir.getParent()); + + new Executor() + .setToolProvider(JavaTool.JLINK) + .dumpOutput() + .addArguments( + "--output", jlinkOutputDir.toString(), + "--add-modules", "java.desktop", + "--strip-debug", + "--no-header-files", + "--no-man-pages", + "--strip-native-commands") + .execute(); + + cmd.setArgumentValue("--runtime-image", jlinkOutputDir.toString()); + } cmd.executeAndAssertHelloAppImageCreated(); } + @Test + public static void testStrippedFiles() throws IOException { + final var cmd = JPackageCommand.helloAppImage().setFakeRuntime(); + + final var runtimePath = Path.of(cmd.executePrerequisiteActions().getArgumentValue("--runtime-image")); + + Files.createDirectories(runtimePath.resolve("jmods")); + Files.createDirectories(runtimePath.resolve("lib")); + Files.createFile(runtimePath.resolve("lib/src.zip")); + Files.createFile(runtimePath.resolve("src.zip")); + + Files.createDirectories(runtimePath.resolve("foo/bar/src.zip")); + Files.createFile(runtimePath.resolve("foo/jmods")); + Files.createFile(runtimePath.resolve("foo/src.zip")); + Files.createDirectories(runtimePath.resolve("custom/jmods")); + + (new JPackageCommand()).addArguments(cmd.getAllArguments()).executeAndAssertHelloAppImageCreated(); + + final var appRuntimeDir = cmd.appLayout().runtimeHomeDirectory(); + TKit.assertPathExists(appRuntimeDir.resolve("jmods"), false); + TKit.assertPathExists(appRuntimeDir.resolve("lib/src.zip"), false); + TKit.assertPathExists(appRuntimeDir.resolve("src.zip"), false); + TKit.assertDirectoryExists(appRuntimeDir.resolve("foo/bar/src.zip")); + TKit.assertDirectoryExists(appRuntimeDir.resolve("custom/jmods")); + TKit.assertFileExists(appRuntimeDir.resolve("foo/jmods")); + TKit.assertFileExists(appRuntimeDir.resolve("foo/src.zip")); + } } diff --git a/test/jdk/tools/jpackage/share/RuntimePackageTest.java b/test/jdk/tools/jpackage/share/RuntimePackageTest.java index 9eb4f8d231e..2af6543c2db 100644 --- a/test/jdk/tools/jpackage/share/RuntimePackageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimePackageTest.java @@ -40,6 +40,7 @@ import jdk.jpackage.test.LinuxHelper; import static jdk.jpackage.test.TKit.assertTrue; import static jdk.jpackage.test.TKit.assertFalse; +import static jdk.internal.util.OperatingSystem.LINUX; /** * Test --runtime-image parameter. @@ -81,22 +82,22 @@ public class RuntimePackageTest { @Test public static void test() { - init(PackageType.NATIVE).run(); + init().run(); } - @Test + @Test(ifOS = LINUX) @Parameter("/usr") @Parameter("/usr/lib/Java") public static void testUsrInstallDir(String installDir) { - init(PackageType.LINUX) - .addInitializer(cmd -> cmd.addArguments("--install-dir", "/usr")) + init() + .addInitializer(cmd -> cmd.addArguments("--install-dir", installDir)) .run(); } @Test public static void testName() { // Test that jpackage can derive package name from the path to runtime image. - init(PackageType.NATIVE) + init() .addInitializer(cmd -> cmd.removeArgumentWithValue("--name")) // Don't attempt to install this package as it may have an odd name derived from // the runtime image path. Say, on Linux for `--runtime-image foo/bar/sed` @@ -105,9 +106,8 @@ public static void testName() { .run(Action.CREATE_AND_UNPACK); } - private static PackageTest init(Set types) { + private static PackageTest init() { return new PackageTest() - .forTypes(types) .addInitializer(cmd -> { final Path runtimeImageDir; @@ -166,8 +166,7 @@ private static PackageTest init(Set types) { "Check the package doesn't deliver [%s] copyright file", copyright)); } - }) - .forTypes(types); + }); } private static Set listFiles(Path root) throws IOException { diff --git a/test/jdk/tools/jpackage/windows/Win8301247Test.java b/test/jdk/tools/jpackage/windows/Win8301247Test.java index b0c11147a17..2f98141dcb4 100644 --- a/test/jdk/tools/jpackage/windows/Win8301247Test.java +++ b/test/jdk/tools/jpackage/windows/Win8301247Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,14 +21,12 @@ * questions. */ -import java.io.IOException; +import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; + import java.time.Duration; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.HelloApp; -import static jdk.jpackage.test.WindowsHelper.killAppLauncherProcess; +import jdk.jpackage.test.JPackageCommand; /** * Test that terminating of the parent app launcher process automatically @@ -48,7 +46,7 @@ public class Win8301247Test { @Test - public void test() throws IOException, InterruptedException { + public void test() throws InterruptedException { var cmd = JPackageCommand.helloAppImage().ignoreFakeRuntime(); // Launch the app in a way it doesn't exit to let us trap app laucnher @@ -56,22 +54,20 @@ public void test() throws IOException, InterruptedException { cmd.addArguments("--java-options", "-Djpackage.test.noexit=true"); cmd.executeAndAssertImageCreated(); - try ( // Launch the app in a separate thread - ExecutorService exec = Executors.newSingleThreadExecutor()) { - exec.execute(() -> { - HelloApp.executeLauncher(cmd); - }); + // Launch the app in a separate thread + new Thread(() -> { + HelloApp.executeLauncher(cmd); + }).start(); - // Wait a bit to let the app start - Thread.sleep(Duration.ofSeconds(10)); + // Wait a bit to let the app start + Thread.sleep(Duration.ofSeconds(10)); - // Find the main app launcher process and kill it - killAppLauncherProcess(cmd, null, 2); + // Find the main app launcher process and kill it + killAppLauncherProcess(cmd, null, 2); - // Wait a bit and check if child app launcher process is still running (it must NOT) - Thread.sleep(Duration.ofSeconds(5)); + // Wait a bit and check if child app launcher process is still running (it must NOT) + Thread.sleep(Duration.ofSeconds(5)); - killAppLauncherProcess(cmd, null, 0); - } + killAppLauncherProcess(cmd, null, 0); } } diff --git a/test/jdk/tools/jpackage/windows/WinL10nTest.java b/test/jdk/tools/jpackage/windows/WinL10nTest.java index 4f5a27f9ff0..14139013318 100644 --- a/test/jdk/tools/jpackage/windows/WinL10nTest.java +++ b/test/jdk/tools/jpackage/windows/WinL10nTest.java @@ -120,7 +120,7 @@ private static boolean isWix3(Executor.Result result) { return getWixTypeFromVerboseJPackageOutput(result) == WIX3; } - private final static Predicate createToolCommandLinePredicate(String wixToolName) { + private static final Predicate createToolCommandLinePredicate(String wixToolName) { var toolFileName = wixToolName + ".exe"; return (s) -> { s = s.trim(); @@ -198,12 +198,12 @@ public void test() throws IOException { return String.join(" ", "-culture", culture); }).collect(Collectors.joining(" ")); } - TKit.assertTextStream(expected).apply(wixCmdline.stream()); + TKit.assertTextStream(expected).apply(wixCmdline); } if (expectedErrorMessage != null) { TKit.assertTextStream(expectedErrorMessage) - .apply(result.getOutput().stream()); + .apply(result.getOutput()); } if (wxlFileInitializers != null) { @@ -213,18 +213,18 @@ public void test() throws IOException { if (allWxlFilesValid) { for (var v : wxlFileInitializers) { if (!v.name.startsWith("MsiInstallerStrings_")) { - v.createCmdOutputVerifier(wixSrcDir).apply(wixCmdline.stream()); + v.createCmdOutputVerifier(wixSrcDir).apply(wixCmdline); } } for (var v : createDefaultL10nFilesLocVerifiers(wixSrcDir)) { - v.apply(wixCmdline.stream()); + v.apply(wixCmdline); } } else { Stream.of(wxlFileInitializers) .filter(Predicate.not(WixFileInitializer::isValid)) .forEach(v -> v.createCmdOutputVerifier( - wixSrcDir).apply(result.getOutput().stream())); + wixSrcDir).apply(result.getOutput())); TKit.assertTrue(wixCmdline.stream().findAny().isEmpty(), String.format("Check %s.exe was not invoked", isWix3 ? "light" : "wix")); @@ -251,12 +251,12 @@ public void test() throws IOException { test.run(); } - final private WixFileInitializer[] wxlFileInitializers; - final private String[] expectedCultures; - final private String expectedErrorMessage; - final private String userLanguage; - final private String userCountry; - final private boolean enableWixUIExtension; + private final WixFileInitializer[] wxlFileInitializers; + private final String[] expectedCultures; + private final String expectedErrorMessage; + private final String userLanguage; + private final String userCountry; + private final boolean enableWixUIExtension; private Path resourceDir; private static class WixFileInitializer { diff --git a/test/jdk/tools/jpackage/windows/WinOSConditionTest.java b/test/jdk/tools/jpackage/windows/WinOSConditionTest.java index 3cf4fdd541c..aea7e9e99b2 100644 --- a/test/jdk/tools/jpackage/windows/WinOSConditionTest.java +++ b/test/jdk/tools/jpackage/windows/WinOSConditionTest.java @@ -62,15 +62,28 @@ public static void test() throws IOException { "--resource-dir", resourceDir.toString()).setFakeRuntime(); }) .addUninstallVerifier(cmd -> { + // Installation could have ended up with 1603 or 1625 error codes. + // MSI error code 1625 indicates the test is being executed in an environment + // that doesn't allow per-user installations. This means the test should be skipped. + try (final var lines = cmd.winMsiLogFileContents().orElseThrow()) { + if (lines.anyMatch(line -> { + return line.endsWith("Installation success or error status: 1625."); + })) { + TKit.throwSkippedException("Installation of per-user packages by the current user is forbidden by system policy"); + } + } + // MSI error code 1603 is generic. // Dig into the last msi log file for log messages specific to failed condition. try (final var lines = cmd.winMsiLogFileContents().orElseThrow()) { - TKit.assertTextStream("Doing action: LaunchConditions").predicate(String::endsWith) - .andThen(TKit.assertTextStream("Not supported on this version of Windows").predicate(String::endsWith)).apply(lines); + TKit.TextStreamVerifier.group() + .add(TKit.assertTextStream("Doing action: LaunchConditions").predicate(String::endsWith)) + .add(TKit.assertTextStream("Not supported on this version of Windows").predicate(String::endsWith)) + .create().accept(lines.iterator()); } }) .createMsiLog(true) - .setExpectedInstallExitCode(1603) + .setExpectedInstallExitCode(1603, 1625) // Create, try install the package (installation should fail) and verify it is not installed. .run(Action.CREATE, Action.INSTALL, Action.VERIFY_UNINSTALL); } diff --git a/test/jdk/tools/jpackage/windows/WinResourceTest.java b/test/jdk/tools/jpackage/windows/WinResourceTest.java index b34521403f3..b22501ac6cc 100644 --- a/test/jdk/tools/jpackage/windows/WinResourceTest.java +++ b/test/jdk/tools/jpackage/windows/WinResourceTest.java @@ -95,9 +95,9 @@ public void test() throws IOException { TKit.assertTextStream(expectedLogMessage) .predicate(String::startsWith) .apply(JPackageCommand.stripTimestamps( - result.getOutput().stream())); + result.getOutput().stream()).iterator()); TKit.assertTextStream(expectedWixErrorMsg) - .apply(result.getOutput().stream()); + .apply(result.getOutput()); }) .setExpectedExitCode(1) .run(); diff --git a/test/jdk/tools/jpackage/windows/WinScriptTest.java b/test/jdk/tools/jpackage/windows/WinScriptTest.java index 45068ffd395..6dcb132cf8a 100644 --- a/test/jdk/tools/jpackage/windows/WinScriptTest.java +++ b/test/jdk/tools/jpackage/windows/WinScriptTest.java @@ -24,14 +24,15 @@ import java.io.IOException; import java.nio.file.Path; import java.util.List; -import jdk.jpackage.internal.util.XmlUtils; -import jdk.jpackage.test.TKit; -import jdk.jpackage.test.PackageTest; -import jdk.jpackage.test.PackageType; -import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JPackageUserScript; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.RunnablePackageTest.Action; +import jdk.jpackage.test.TKit; /* * @test usage of scripts from resource dir @@ -107,7 +108,7 @@ public void test(int wsfExitCode) throws IOException { throw new UnsupportedOperationException(); } - test.run(); + test.run(Action.CREATE); } private static class ScriptData { @@ -115,11 +116,11 @@ private static class ScriptData { if (scriptType == PackageType.WIN_MSI) { echoText = "post app image wsf"; envVarName = "JpAppImageDir"; - scriptSuffixName = "post-image"; + script = JPackageUserScript.POST_IMAGE; } else { echoText = "post msi wsf"; envVarName = "JpMsiFile"; - scriptSuffixName = "post-msi"; + script = JPackageUserScript.POST_MSI; } this.wsfExitCode = wsfExitCode; } @@ -127,19 +128,19 @@ private static class ScriptData { void assertJPackageOutput(List output) { TKit.assertTextStream(String.format(" jp: %s", echoText)) .predicate(String::equals) - .apply(output.stream()); + .apply(output); String cwdPattern = String.format(" jp: CWD(%s)=", envVarName); TKit.assertTextStream(cwdPattern) .predicate(String::startsWith) - .apply(output.stream()); + .apply(output); String cwd = output.stream().filter(line -> line.startsWith( cwdPattern)).findFirst().get().substring(cwdPattern.length()); String envVarPattern = String.format(" jp: %s=", envVarName); TKit.assertTextStream(envVarPattern) .predicate(String::startsWith) - .apply(output.stream()); + .apply(output); String envVar = output.stream().filter(line -> line.startsWith( envVarPattern)).findFirst().get().substring(envVarPattern.length()); @@ -149,26 +150,17 @@ void assertJPackageOutput(List output) { } void createScript(JPackageCommand cmd) throws IOException { - XmlUtils.createXml(Path.of(cmd.getArgumentValue("--resource-dir"), - String.format("%s-%s.wsf", cmd.name(), scriptSuffixName)), xml -> { - xml.writeStartElement("job"); - xml.writeAttribute("id", "main"); - xml.writeStartElement("script"); - xml.writeAttribute("language", "JScript"); - xml.writeCData(String.join("\n", List.of( + script.create(cmd, List.of( "var shell = new ActiveXObject('WScript.Shell')", "WScript.Echo('jp: " + envVarName + "=' + shell.ExpandEnvironmentStrings('%" + envVarName + "%'))", "WScript.Echo('jp: CWD(" + envVarName + ")=' + shell.CurrentDirectory)", String.format("WScript.Echo('jp: %s')", echoText), String.format("WScript.Quit(%d)", wsfExitCode) - ))); - xml.writeEndElement(); - xml.writeEndElement(); - }); + )); } private final int wsfExitCode; - private final String scriptSuffixName; + private final JPackageUserScript script; private final String echoText; private final String envVarName; } diff --git a/test/jdk/tools/launcher/Arrrghs.java b/test/jdk/tools/launcher/Arrrghs.java index efc95052842..fe1539ff5a9 100644 --- a/test/jdk/tools/launcher/Arrrghs.java +++ b/test/jdk/tools/launcher/Arrrghs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -563,16 +563,16 @@ void testMainMethod() throws FileNotFoundException { if (!tr.testStatus) System.out.println(tr); - // incorrect method type - non-static + // non-static method type createJar(new File("some.jar"), new File("Foo"), "public void main(String[] args){}"); tr = doExec(javaCmd, "-jar", "some.jar"); - tr.contains("Error: Main method not found in class Foo"); + tr.checkPositive(); if (!tr.testStatus) System.out.println(tr); // use classpath to check tr = doExec(javaCmd, "-cp", "some.jar", "Foo"); - tr.contains("Error: Main method not found in class Foo"); + tr.checkPositive(); if (!tr.testStatus) System.out.println(tr); @@ -601,6 +601,54 @@ void testMainMethod() throws FileNotFoundException { tr.checkPositive(); if (!tr.testStatus) System.out.println(tr); + + //private method with parameter, usable method without parameter: + createJar(new File("some.jar"), new File("Foo"), + "private static void main(String[] args){}", + "void main() {System.out.println(\"THE_CHOSEN_ONE\");}"); + tr = doExec(javaCmd, "-jar", "some.jar"); + tr.contains("THE_CHOSEN_ONE"); + if (!tr.testStatus) + System.out.println(tr); + + createJar(new File("some.jar"), new File("Foo"), + "private void main(String[] args){}", + "void main() {System.out.println(\"THE_CHOSEN_ONE\");}"); + tr = doExec(javaCmd, "-jar", "some.jar"); + tr.contains("THE_CHOSEN_ONE"); + if (!tr.testStatus) + System.out.println(tr); + + //method with a wrong return type with parameter, usable method without parameter: + createJar(new File("some.jar"), new File("Foo"), + "public static int main(String[] args){ return -1; }", + "void main() {System.out.println(\"THE_CHOSEN_ONE\");}"); + tr = doExec(javaCmd, "-jar", "some.jar"); + tr.contains("THE_CHOSEN_ONE"); + if (!tr.testStatus) + System.out.println(tr); + + createJar(new File("some.jar"), new File("Foo"), + "public int main(String[] args){ return -1; }", + "void main() {System.out.println(\"THE_CHOSEN_ONE\");}"); + tr = doExec(javaCmd, "-jar", "some.jar"); + tr.contains("THE_CHOSEN_ONE"); + if (!tr.testStatus) + System.out.println(tr); + + // instance method abstract class: + createJarForSource(null, new File("some.jar"), new File("Foo"), + """ + public abstract class Foo { + void main() { + System.out.println("Cannot be called."); + } + } + """); + tr = doExec(javaCmd, "-jar", "some.jar"); + tr.contains("Error: abstract class Foo can not be instantiated"); + if (!tr.testStatus) + System.out.println(tr); } /* * tests 6968053, ie. we turn on the -Xdiag (for now) flag and check if diff --git a/test/jdk/tools/launcher/TestHelper.java b/test/jdk/tools/launcher/TestHelper.java index d5e5f47499b..0dcd6de2a5e 100644 --- a/test/jdk/tools/launcher/TestHelper.java +++ b/test/jdk/tools/launcher/TestHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ import java.util.Map; import java.util.Arrays; import java.util.spi.ToolProvider; +import java.util.stream.Collectors; import static java.nio.file.StandardCopyOption.*; import static java.nio.file.StandardOpenOption.*; @@ -64,6 +65,7 @@ public class TestHelper { static final File TEST_CLASSES_DIR; static final File TEST_SOURCES_DIR; + static final String NL = System.getProperty("line.separator"); static final String JAVAHOME = System.getProperty("java.home"); static final String JAVA_BIN; static final String JAVA_LIB; @@ -287,17 +289,21 @@ static void compile(String... compilerArgs) { */ static void createJar(String mEntry, File jarName, File mainClass, String... mainDefs) throws FileNotFoundException { + String source = + Arrays.stream(mainDefs != null ? mainDefs : new String[0]) + .collect(Collectors.joining(NL, + "public class Foo {" + NL, + "}" + NL)); + createJarForSource(mEntry, jarName, mainClass, source); + } + + static void createJarForSource(String mEntry, File jarName, File mainClass, + String source) throws FileNotFoundException { if (jarName.exists()) { jarName.delete(); } try (PrintStream ps = new PrintStream(new FileOutputStream(mainClass + ".java"))) { - ps.println("public class Foo {"); - if (mainDefs != null) { - for (String x : mainDefs) { - ps.println(x); - } - } - ps.println("}"); + ps.println(source); } String compileArgs[] = { diff --git a/test/jdk/tools/launcher/ToolsOpts.java b/test/jdk/tools/launcher/ToolsOpts.java index 858ba89775b..036e0f3643e 100644 --- a/test/jdk/tools/launcher/ToolsOpts.java +++ b/test/jdk/tools/launcher/ToolsOpts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -128,7 +128,8 @@ static void checkJoptionOutput(TestResult tr, String[] opts) throws IOException String jopts = ""; for (String pat : opts) { jopts = jopts.concat(pat + " "); - if (tr.contains("-J")) { + if (tr.contains(" -J-")) { + System.err.println(tr); throw new RuntimeException( "failed: output should not contain option " + pat); } diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 5f74ffa6ea6..360c96c74ef 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -124,6 +124,7 @@ public Map call() { map.put("vm.cds", this::vmCDS); map.put("vm.cds.custom.loaders", this::vmCDSForCustomLoaders); map.put("vm.cds.supports.aot.class.linking", this::vmCDSSupportsAOTClassLinking); + map.put("vm.cds.supports.aot.code.caching", this::vmCDSSupportsAOTCodeCaching); map.put("vm.cds.write.archived.java.heap", this::vmCDSCanWriteArchivedJavaHeap); map.put("vm.continuations", this::vmContinuations); // vm.graal.enabled is true if Graal is used as JIT @@ -472,6 +473,20 @@ protected String vmCDSSupportsAOTClassLinking() { return vmCDSCanWriteArchivedJavaHeap(); } + /** + * @return true if this VM can support the AOT Code Caching + */ + protected String vmCDSSupportsAOTCodeCaching() { + if ("true".equals(vmCDSSupportsAOTClassLinking()) && + !"zero".equals(vmFlavor()) && + "false".equals(vmJvmciEnabled()) && + (Platform.isX64() || Platform.isAArch64())) { + return "true"; + } else { + return "false"; + } + } + /** * @return true if the VM options specified via the "test.cds.runtime.options" * property is compatible with writing Java heap objects into the CDS archive diff --git a/test/langtools/ProblemList-StaticJdk.txt b/test/langtools/ProblemList-StaticJdk.txt new file mode 100644 index 00000000000..85fa3a6e14d --- /dev/null +++ b/test/langtools/ProblemList-StaticJdk.txt @@ -0,0 +1,29 @@ +# Requires javadoc +jdk/javadoc/tool/6964914/TestStdDoclet.java 8346719 generic-all +jdk/javadoc/tool/6964914/TestUserDoclet.java 8346719 generic-all +jdk/javadoc/tool/AddOpensTest.java 8346719 generic-all +jdk/javadoc/tool/EncodingTest.java 8346719 generic-all +jdk/javadoc/tool/EnsureNewOldDoclet.java 8346719 generic-all +jdk/javadoc/tool/QuietOption.java 8346719 generic-all +jdk/javadoc/tool/testLocaleOption/TestLocaleOption.java 8346719 generic-all + +# Requires javac +tools/javac/ClassPathTest/ClassPathTest.java 8346719 generic-all +tools/javac/Paths/ClassPath.java 8346719 generic-all +tools/javac/Paths/WildcardMineField.java 8346719 generic-all +tools/javac/T8132562/ClassPathWithDoubleQuotesTest.java 8346719 generic-all +tools/javac/file/MultiReleaseJar/MultiReleaseJarTest.java 8346719 generic-all +tools/javac/modules/AllDefaultTest.java 8346719 generic-all +tools/javac/modules/EnvVarTest.java 8346719 generic-all +tools/javac/modules/InheritRuntimeEnvironmentTest.java 8346719 generic-all +tools/javac/modules/NPEEmptyFileTest.java 8346719 generic-all +tools/javac/newlines/NewLineTest.java 8346719 generic-all +tools/javac/options/smokeTests/OptionSmokeTest.java 8346719 generic-all +tools/javac/platform/PlatformProviderTest.java 8346719 generic-all +tools/javac/processing/options/testPrintProcessorInfo/TestWithXstdout.java 8346719 generic-all + +# Requires jar +tools/jdeps/MultiReleaseJar.java 8346719 generic-all + +# Requires jimage +tools/javac/Paths/MineField.java 8346719 generic-all diff --git a/test/langtools/TEST.ROOT b/test/langtools/TEST.ROOT index 9b1c5368e66..e3bd3b74bcf 100644 --- a/test/langtools/TEST.ROOT +++ b/test/langtools/TEST.ROOT @@ -15,7 +15,7 @@ keys=intermittent randomness needs-src needs-src-jdk_javadoc groups=TEST.groups # Minimum jtreg version -requiredVersion=7.5.1+1 +requiredVersion=7.5.2+1 # Use new module options useNewOptions=true diff --git a/test/langtools/jdk/javadoc/doclet/checkLibraryVersions/CheckLibraryVersions.java b/test/langtools/jdk/javadoc/doclet/checkLibraryVersions/CheckLibraryVersions.java index 4e731a42f10..f36ef92109a 100644 --- a/test/langtools/jdk/javadoc/doclet/checkLibraryVersions/CheckLibraryVersions.java +++ b/test/langtools/jdk/javadoc/doclet/checkLibraryVersions/CheckLibraryVersions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8293177 8324774 + * @bug 8293177 8324774 8357458 * @summary Verify version numbers in legal files * @library /test/lib * @build jtreg.SkippedException @@ -47,7 +47,7 @@ public class CheckLibraryVersions { static class SourceDirNotFound extends Error {} // Regex pattern for library name and version in legal Markdown file - static final Pattern versionPattern = Pattern.compile("## ([\\w\\s]+) v(\\d+(\\.\\d+){1,2})"); + static final Pattern versionPattern = Pattern.compile("## ([\\w\\s.]+) v(\\d+(\\.\\d+){1,2})"); // Map of 3rd party libraries. The keys are the names of files in the legal directory, // the values are lists of templates for library files with the following placeholders: @@ -56,7 +56,8 @@ static class SourceDirNotFound extends Error {} static final Map> libraries = Map.of( "jquery.md", List.of("jquery/jquery-%V%M.js"), "jqueryUI.md", List.of("jquery/jquery-ui%M.js", "jquery/jquery-ui%M.css"), - "dejavufonts.md", List.of("fonts/dejavu.css") + "dejavufonts.md", List.of("fonts/dejavu.css"), + "highlightjs.md", List.of("highlight.js") ); public static void main(String... args) throws Exception { diff --git a/test/langtools/jdk/javadoc/doclet/testLegalNotices/TestLegalNotices.java b/test/langtools/jdk/javadoc/doclet/testLegalNotices/TestLegalNotices.java index 29da4d98972..4c3f26b9d34 100644 --- a/test/langtools/jdk/javadoc/doclet/testLegalNotices/TestLegalNotices.java +++ b/test/langtools/jdk/javadoc/doclet/testLegalNotices/TestLegalNotices.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8259530 + * @bug 8259530 8357458 * @summary Generated docs contain MIT/GPL-licenced works without reproducing the licence * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -61,6 +61,10 @@ enum IndexKind { INDEX, NO_INDEX } + enum HighlightKind { + HIGHLIGHT, NO_HIGHLIGHT + } + @Test public void testCombo(Path base) throws IOException { @@ -71,14 +75,17 @@ public void testCombo(Path base) throws IOException { for (var optionKind : OptionKind.values()) { for (var indexKind : IndexKind.values()) { - test(base, src, legal, optionKind, indexKind); + for (var highlightKind : HighlightKind.values()) { + test(base, src, legal, optionKind, indexKind, highlightKind); + } } } } - void test(Path base, Path src, Path legal, OptionKind optionKind, IndexKind indexKind) throws IOException { - System.out.println("testing " + optionKind + " " + indexKind); - Path out = base.resolve(optionKind + "-" + indexKind).resolve("out"); + void test(Path base, Path src, Path legal, OptionKind optionKind, IndexKind indexKind, + HighlightKind highlightKind) throws IOException { + System.out.println("testing " + optionKind + " " + indexKind + " " + highlightKind); + Path out = base.resolve(optionKind + "-" + indexKind + "-" + highlightKind).resolve("out"); List args = new ArrayList<>(); args.addAll(List.of( "-d", out.toString())); @@ -87,6 +94,10 @@ void test(Path base, Path src, Path legal, OptionKind optionKind, IndexKind inde args.add("-noindex"); } + if (highlightKind == HighlightKind.HIGHLIGHT) { + args.add("--syntax-highlight"); + } + args.addAll(List.of( "-Xdoclint:-missing", "--source-path", src.toString(), @@ -103,7 +114,7 @@ void test(Path base, Path src, Path legal, OptionKind optionKind, IndexKind inde } javadoc(args.toArray(new String[0])); - Set expectFiles = getExpectFiles(optionKind, indexKind, legal); + Set expectFiles = getExpectFiles(optionKind, indexKind, highlightKind, legal); Set foundFiles = listFiles(out.resolve("legal")); checking("Checking legal notice files"); @@ -128,16 +139,18 @@ void test(Path base, Path src, Path legal, OptionKind optionKind, IndexKind inde } - Set getExpectFiles(OptionKind optionKind, IndexKind indexKind, Path legal) throws IOException { + Set getExpectFiles(OptionKind optionKind, IndexKind indexKind, HighlightKind highlightKind, + Path legal) throws IOException { switch (optionKind) { case UNSET, DEFAULT -> { Path javaHome = Path.of(System.getProperty("java.home")); Path legal_javadoc = javaHome.resolve("legal").resolve("jdk.javadoc"); return listFiles(legal_javadoc, p -> - switch (indexKind) { - case INDEX -> true; - case NO_INDEX -> !p.getFileName().toString().contains("jquery"); - }); + !(indexKind == IndexKind.NO_INDEX + && p.getFileName().toString().contains("jquery")) + && !(highlightKind == HighlightKind.NO_HIGHLIGHT + && p.getFileName().toString().equals("highlightjs.md")) + ); } case NONE -> { diff --git a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java index a6a04c80834..9a80ca4d089 100644 --- a/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testLinkOption/TestRedirectLinks.java @@ -24,6 +24,7 @@ /* * @test * @bug 8190312 + * @key intermittent * @summary test redirected URLs for -link * @library /tools/lib ../../lib /test/lib * @modules jdk.compiler/com.sun.tools.javac.api diff --git a/test/langtools/jdk/javadoc/doclet/testRelativeLinks/pkg/C.java b/test/langtools/jdk/javadoc/doclet/testRelativeLinks/pkg/C.java index e2f2d1f6f43..79a09b4f240 100644 --- a/test/langtools/jdk/javadoc/doclet/testRelativeLinks/pkg/C.java +++ b/test/langtools/jdk/javadoc/doclet/testRelativeLinks/pkg/C.java @@ -33,7 +33,7 @@ public class C { /** - * Here is a relative link in a field:\u0130 + * Here is a relative link in a field: * relative field link. */ public C field = null; diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java index 62782758215..a3e92584ae2 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetMarkup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8266666 8281969 8319339 + * @bug 8266666 8281969 8319339 8338833 * @summary Implementation for snippets * @library /tools/lib ../../lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -206,6 +206,50 @@ public void testLink(Path base) throws Exception { testPositive(base, testCases); } + /* + * Make sure an error is generated for links with invalid reference. + */ + @Test + public void testLinkReferenceNotFound(Path base) throws Exception { + Path srcDir = base.resolve("src"); + Path outDir = base.resolve("out"); + + new ClassBuilder(tb, "pkg.A") + .setModifiers("public", "class") + .addMembers( + ClassBuilder.MethodBuilder + .parse("public void inline() { }") + .setComments(""" + First sentence. + {@snippet : + First line // @link substring="First" target="String" + Second line // @link substring="Second" target="StringReader" + } + """)) + .write(srcDir); + + javadoc("-d", outDir.toString(), + "-sourcepath", srcDir.toString(), + "pkg"); + + checkExit(Exit.ERROR); + checkOutput(Output.OUT, false, + """ + error: reference not found: String + """); + checkOutput(Output.OUT, true, + """ + A.java:5: error: reference not found: StringReader + """); + checkOutput("pkg/A.html", true, + """ +

                + invalid reference +
                Second
                +
                """); + checkNoCrashes(); + } + @Test public void testCornerCases(Path base) throws Exception { var testCases = List.of( diff --git a/test/langtools/jdk/javadoc/doclet/testSyntaxHighlightOption/TestSyntaxHighlightOption.java b/test/langtools/jdk/javadoc/doclet/testSyntaxHighlightOption/TestSyntaxHighlightOption.java new file mode 100644 index 00000000000..f43b50504bf --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testSyntaxHighlightOption/TestSyntaxHighlightOption.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8348282 + * @summary Add option for syntax highlighting in javadoc snippets + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestSyntaxHighlightOption + */ + +import java.io.IOException; +import java.nio.file.Path; + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +public class TestSyntaxHighlightOption extends JavadocTester { + + public static void main(String... args) throws Exception { + var tester = new TestSyntaxHighlightOption(); + tester.runTests(); + } + + ToolBox tb = new ToolBox(); + Path src = Path.of("src"); + + + TestSyntaxHighlightOption() throws IOException { + tb.writeJavaFiles(src, """ + package p; + /** Class C. */ + public class C { + /** + * Method m. + */ + public void m() { + } + } + """); + + } + + @Test + public void testSyntaxHighlightOption(Path base) { + javadoc("-d", base.resolve("out").toString(), + "-sourcepath", src.toString(), + "--syntax-highlight", + "p"); + checkExit(Exit.OK); + checkOutput("resource-files/highlight.css", true, "Syntax highlight style sheet"); + checkOutput("script-files/highlight.js", true, "Highlight.js v11.11.1 (git: 08cb242e7d)"); + checkOutput("index-all.html", true, """ + + """); + checkOutput("p/package-summary.html", true, """ + + """); + checkOutput("p/C.html", true, """ + + """); + } + + @Test + public void testNoSyntaxHighlightOption(Path base) { + javadoc("-d", base.resolve("out").toString(), + "-sourcepath", src.toString(), + "p"); + checkExit(Exit.OK); + checkFiles(false, "resource-files/highlight.css", "script-files/highlight.js"); + checkOutput("index-all.html", false, "highlight.css", "highlight.js"); + checkOutput("p/package-summary.html", false, "highlight.css", "highlight.js"); + checkOutput("p/C.html", false, "highlight.css", "highlight.js"); + } +} diff --git a/test/langtools/jdk/jshell/AbstractStopExecutionTest.java b/test/langtools/jdk/jshell/AbstractStopExecutionTest.java new file mode 100644 index 00000000000..c38549b5128 --- /dev/null +++ b/test/langtools/jdk/jshell/AbstractStopExecutionTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.PrintWriter; +import java.io.StringWriter; + +import jdk.jshell.JShell; + +import static org.testng.Assert.fail; + +public abstract class AbstractStopExecutionTest extends KullaTesting { + + private final Object lock = new Object(); + private boolean isStopped; + + protected void scheduleStop(String src) throws InterruptedException { + JShell state = getState(); + isStopped = false; + StringWriter writer = new StringWriter(); + PrintWriter out = new PrintWriter(writer); + Thread t = new Thread(() -> { + int i = 1; + int n = 30; + synchronized (lock) { + do { + state.stop(); + if (!isStopped) { + out.println("Not stopped. Try again: " + i); + try { + lock.wait(1000); + } catch (InterruptedException ignored) { + } + } + } while (i++ < n && !isStopped); + if (!isStopped) { + System.err.println(writer.toString()); + fail("Evaluation was not stopped: '" + src + "'"); + } + } + }); + t.start(); + assertEval(src); + synchronized (lock) { + out.println("Evaluation was stopped successfully: '" + src + "'"); + isStopped = true; + lock.notify(); + } + // wait until the background thread finishes to prevent from calling 'stop' on closed state. + t.join(); + } +} diff --git a/test/langtools/jdk/jshell/CompletionSuggestionTest.java b/test/langtools/jdk/jshell/CompletionSuggestionTest.java index 8564c5d1da2..6bc7c41e62c 100644 --- a/test/langtools/jdk/jshell/CompletionSuggestionTest.java +++ b/test/langtools/jdk/jshell/CompletionSuggestionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466 8197439 8221759 8234896 8240658 8278039 8286206 8296789 8314662 8326333 8326333 + * @bug 8131025 8141092 8153761 8145263 8131019 8175886 8176184 8176241 8176110 8177466 8197439 8221759 8234896 8240658 8278039 8286206 8296789 8314662 8326333 8326333 8353581 * @summary Test Completion and Documentation * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -824,4 +824,14 @@ public void testArray() { assertCompletion("ints.cl|", "clone()"); assertCompletion("String[].|", "class"); } + + //JDK-8353581: completion for module imports: + public void testModuleImport() { + assertCompletionIncludesExcludes("import |", Set.of("module "), Set.of()); + assertCompletionIncludesExcludes("import module |", Set.of("java.base"), Set.of("java.", "module")); + assertCompletionIncludesExcludes("import module java.|", Set.of("java.base"), Set.of()); + assertCompletion("import module java.ba|", "java.base"); + assertCompletionIncludesExcludes("import module ja|", Set.of("java.base"), Set.of("jdk.compiler")); + assertCompletion("import module java/*c*/./*c*/ba|", "java.base"); + } } diff --git a/test/langtools/jdk/jshell/ConsoleTest.java b/test/langtools/jdk/jshell/ConsoleTest.java index 4aedc061939..a82e0753b56 100644 --- a/test/langtools/jdk/jshell/ConsoleTest.java +++ b/test/langtools/jdk/jshell/ConsoleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,9 +23,8 @@ /* * @test - * @bug 8298425 + * @bug 8298425 8344706 * @summary Verify behavior of System.console() - * @enablePreview * @build KullaTesting TestingInputStream * @run testng ConsoleTest */ @@ -68,13 +67,6 @@ public String readLine(String prompt) throws IOError { } }; assertEval("System.console().readLine(\"expected\")", "\"AB\""); - console = new ThrowingJShellConsole() { - @Override - public String readLine() throws IOError { - return "AB"; - } - }; - assertEval("System.console().readLine()", "\"AB\""); console = new ThrowingJShellConsole() { @Override public char[] readPassword(String prompt) throws IOError { @@ -157,6 +149,31 @@ public void close() throws IOException {} assertEquals(sb.toString(), expected); } + @Test + public void testConsoleUnicodeWritingTest() { + StringBuilder sb = new StringBuilder(); + console = new ThrowingJShellConsole() { + @Override + public PrintWriter writer() { + return new PrintWriter(new Writer() { + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + sb.append(cbuf, off, len); + } + @Override + public void flush() throws IOException {} + @Override + public void close() throws IOException {} + }); + } + }; + int count = 384; // 128-255, 384-511, 640-767, ... (JDK-8355371) + String testStr = "\u30A2"; // Japanese katakana (A2 >= 80) (JDK-8354910) + assertEval("System.console().writer().write(\"" + testStr + "\".repeat(" + count + "))"); + String expected = testStr.repeat(count); + assertEquals(sb.toString(), expected); + } + @Test public void testConsoleMultiThreading() { StringBuilder sb = new StringBuilder(); @@ -218,10 +235,6 @@ public String readLine(String prompt) throws IOError { return console.readLine(prompt); } @Override - public String readLine() throws IOError { - return console.readLine(); - } - @Override public char[] readPassword(String prompt) throws IOError { return console.readPassword(prompt); } @@ -252,10 +265,6 @@ public String readLine(String prompt) throws IOError { throw new IllegalStateException("Not expected!"); } @Override - public String readLine() throws IOError { - throw new IllegalStateException("Not expected!"); - } - @Override public char[] readPassword(String prompt) throws IOError { throw new IllegalStateException("Not expected!"); } diff --git a/test/langtools/jdk/jshell/ConsoleToolTest.java b/test/langtools/jdk/jshell/ConsoleToolTest.java index 0af85a61862..a1d9a612ae5 100644 --- a/test/langtools/jdk/jshell/ConsoleToolTest.java +++ b/test/langtools/jdk/jshell/ConsoleToolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8331535 8341631 + * @bug 8331535 8341631 8344706 * @summary Test the JShell tool Console handling * @modules jdk.internal.le/jdk.internal.org.jline.reader * jdk.jshell/jdk.internal.jshell.tool:+open @@ -59,33 +59,37 @@ public void testOutput() { @Test //JDK-8341631 public void testIO() { test(new String[] {"--enable-preview"}, - a -> {assertCommandWithOutputAndTerminal(a, - "java.io.IO.readln(\"%%s\");\ninput", //newline automatically appended + a -> {assertCommandWithOutputAndInput(a, + "java.lang.IO.readln(\"%%s\");", + "input\n", "$1 ==> \"input\"", + "%%s", """ - \u0005java.io.IO.readln(\"%%s\"); - %%sinput + \u0005java.lang.IO.readln(\"%%s\"); """);}, - a -> {assertCommandWithOutputAndTerminal(a, - "java.io.IO.readln();\ninput!", //newline automatically appended + a -> {assertCommandWithOutputAndInput(a, + "java.lang.IO.readln();", + "input!\n", "$2 ==> \"input!\"", + "", """ - \u0005java.io.IO.readln(); - input! + \u0005java.lang.IO.readln(); """);}, - a -> {assertCommandWithOutputAndTerminal(a, - "java.io.IO.println(\"Hello, World!\");", + a -> {assertCommandWithOutputAndInput(a, + "java.lang.IO.println(\"Hello, World!\");", + "", "", + "Hello, World!\n", """ - \u0005java.io.IO.println(\"Hello, World!\"); - Hello, World! + \u0005java.lang.IO.println(\"Hello, World!\"); """);}, - a -> {assertCommandWithOutputAndTerminal(a, - "java.io.IO.println();", + a -> {assertCommandWithOutputAndInput(a, + "java.lang.IO.println();", + "", "", + "\n", """ - \u0005java.io.IO.println(); - + \u0005java.lang.IO.println(); """);} ); } @@ -94,4 +98,8 @@ void assertCommandWithOutputAndTerminal(boolean a, String command, String out, S assertCommand(a, command, out, null, null, null, null, terminalOut); } + void assertCommandWithOutputAndInput(boolean a, String command, String input, String out, String print, String terminalOut) { + assertCommand(a, command, out, null, input, print, null, terminalOut); + } + } diff --git a/test/langtools/jdk/jshell/InputUITest.java b/test/langtools/jdk/jshell/InputUITest.java new file mode 100644 index 00000000000..d46c88aa797 --- /dev/null +++ b/test/langtools/jdk/jshell/InputUITest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8356165 + * @summary Check user input works properly + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jshell/jdk.internal.jshell.tool:open + * jdk.jshell/jdk.internal.jshell.tool.resources:open + * jdk.jshell/jdk.jshell:open + * @library /tools/lib + * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask + * @build Compiler UITesting + * @compile InputUITest.java + * @run testng/othervm -Dstderr.encoding=UTF-8 -Dstdin.encoding=UTF-8 -Dstdout.encoding=UTF-8 InputUITest + */ + +import java.util.function.Function; +import org.testng.annotations.Test; + +@Test +public class InputUITest extends UITesting { + + static final String LINE_SEPARATOR = System.getProperty("line.separator"); + static final String LINE_SEPARATOR_ESCAPED = LINE_SEPARATOR.replace("\n", "\\n") + .replace("\r", "\\r"); + + public InputUITest() { + super(true); + } + + public void testUserInputWithSurrogates() throws Exception { + Function genSnippet = + realCharsToRead -> "new String(System.in.readNBytes(" + + (realCharsToRead + LINE_SEPARATOR.length()) + + "))\n"; + doRunTest((inputSink, out) -> { + inputSink.write(genSnippet.apply(4) + "\uD83D\uDE03\n"); + waitOutput(out, patternQuote("\"\uD83D\uDE03" + LINE_SEPARATOR_ESCAPED + "\"")); + inputSink.write(genSnippet.apply(1) + "\uD83D\n"); + waitOutput(out, patternQuote("\"?" + LINE_SEPARATOR_ESCAPED + "\"")); + inputSink.write(genSnippet.apply(1) + "\uDE03\n"); + waitOutput(out, patternQuote("\"?" + LINE_SEPARATOR_ESCAPED + "\"")); + }, false); + } + +} \ No newline at end of file diff --git a/test/langtools/jdk/jshell/LocalExecutionControlExceptionTest.java b/test/langtools/jdk/jshell/LocalExecutionControlExceptionTest.java new file mode 100644 index 00000000000..afdf7d12e82 --- /dev/null +++ b/test/langtools/jdk/jshell/LocalExecutionControlExceptionTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8299934 + * @summary Test LocalExecutionControl + * @run junit LocalExecutionControlExceptionTest + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import jdk.jshell.EvalException; +import jdk.jshell.JShell; +import jdk.jshell.execution.LocalExecutionControlProvider; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.*; + +public class LocalExecutionControlExceptionTest { + + @Test + @ExtendWith(NoUncaughtExceptionHandleInterceptor.class) + public void testUncaughtExceptions() throws InterruptedException { + List excs = new ArrayList<>(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Thread.setDefaultUncaughtExceptionHandler((t, ex) -> excs.add(ex)); + try (var jshell = JShell.builder() + .err(new PrintStream(out)) + .out(new PrintStream(out)) + .executionEngine(new LocalExecutionControlProvider(), Map.of()) + .build()) { + { + var events = jshell.eval("throw new java.io.IOException();"); + Assertions.assertEquals(1, events.size()); + Assertions.assertNotNull(events.get(0).exception()); + Assertions.assertTrue(events.get(0).exception() instanceof EvalException); + Assertions.assertEquals("java.io.IOException", + ((EvalException) events.get(0).exception()).getExceptionClassName()); + Assertions.assertEquals(0, excs.size()); + Assertions.assertEquals(0, out.size()); + } + { + var events = jshell.eval("throw new IllegalAccessException();"); + Assertions.assertEquals(1, events.size()); + Assertions.assertNotNull(events.get(0).exception()); + Assertions.assertTrue(events.get(0).exception() instanceof EvalException); + Assertions.assertEquals("java.lang.IllegalAccessException", + ((EvalException) events.get(0).exception()).getExceptionClassName()); + Assertions.assertEquals(0, excs.size()); + Assertions.assertEquals(0, out.size()); + } + jshell.eval(""" + T t2(Throwable t) throws T { + throw (T) t; + } + """); + jshell.eval(""" + void t(Throwable t) { + throw t2(t); + } + """); + { + var events = jshell.eval(""" + { + var t = new Thread(() -> t(new java.io.IOException())); + t.start(); + t.join(); + } + """); + Assertions.assertEquals(1, events.size()); + Assertions.assertNull(events.get(0).exception()); + Assertions.assertEquals(0, excs.size()); + Assertions.assertEquals(0, out.size()); + } + { + var events = jshell.eval(""" + { + var t = new Thread(() -> t(new IllegalAccessException())); + t.start(); + t.join(); + } + """); + Assertions.assertEquals(1, events.size()); + Assertions.assertNull(events.get(0).exception()); + Assertions.assertEquals(0, excs.size()); + Assertions.assertEquals(0, out.size()); + } + Thread outsideOfJShell = new Thread(() -> { + t(new IOException()); + }); + outsideOfJShell.start(); + outsideOfJShell.join(); + Assertions.assertEquals(1, excs.size()); + } + } + + void t(Throwable t) { + throw t2(t); + } + + T t2(Throwable t) throws T { + throw (T) t; + } + + public static final class NoUncaughtExceptionHandleInterceptor implements InvocationInterceptor { + public void interceptTestMethod(Invocation invocation, + ReflectiveInvocationContext invocationContext, + ExtensionContext extensionContext) throws Throwable { + Throwable[] exc = new Throwable[1]; + //the tests normally run in a ThreadGroup which handles uncaught exception + //run in a ThreadGroup which does not handle the uncaught exceptions, and let them + //pass to the default uncaught handler for the test: + var thread = new Thread(Thread.currentThread().getThreadGroup().getParent(), "test-group") { + public void run() { + try { + invocation.proceed(); + } catch (Throwable ex) { + exc[0] = ex; + } + } + }; + thread.start(); + thread.join(); + if (exc[0] != null) { + throw exc[0]; + } + } + } +} diff --git a/test/langtools/jdk/jshell/LocalStopExecutionTest.java b/test/langtools/jdk/jshell/LocalStopExecutionTest.java new file mode 100644 index 00000000000..501c5cf7df9 --- /dev/null +++ b/test/langtools/jdk/jshell/LocalStopExecutionTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8355323 + * @summary Verify local execution can stop execution when there are no backward branches + * @modules jdk.jshell/jdk.internal.jshell.tool + * @build KullaTesting TestingInputStream + * @run testng LocalStopExecutionTest + */ + +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.util.Random; +import java.util.concurrent.CountDownLatch; + +import jdk.internal.jshell.tool.StopDetectingInputStream; +import jdk.internal.jshell.tool.StopDetectingInputStream.State; +import jdk.jshell.JShell; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +@Test +public class LocalStopExecutionTest extends AbstractStopExecutionTest { + + @BeforeMethod + @Override + public void setUp() { + setUp(b -> b.executionEngine("local")); + } + + @Test + public void testVeryLongRecursion() throws InterruptedException { + scheduleStop( + """ + // Note: there are no backward branches in this class + new Runnable() { + public void run() { + recurse(1); + recurse(10); + recurse(100); + recurse(1000); + recurse(10000); + recurse(100000); + recurse(1000000); + } + public void recurse(int depth) { + if (depth == 0) + return; + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); recurse(depth - 1); + } + }.run(); + """ + ); + } +} diff --git a/test/langtools/jdk/jshell/ReplToolTesting.java b/test/langtools/jdk/jshell/ReplToolTesting.java index d08c1008386..8bfae2fc390 100644 --- a/test/langtools/jdk/jshell/ReplToolTesting.java +++ b/test/langtools/jdk/jshell/ReplToolTesting.java @@ -57,19 +57,8 @@ public class ReplToolTesting { private final static String DEFAULT_STARTUP_MESSAGE = "| Welcome to"; - final static List START_UP_IMPORTS = Stream.of( - "java.io.*", - "java.math.*", - "java.net.*", - "java.nio.file.*", - "java.util.*", - "java.util.concurrent.*", - "java.util.function.*", - "java.util.prefs.*", - "java.util.regex.*", - "java.util.stream.*") - .map(s -> new ImportInfo("import " + s + ";", "", s)) - .collect(toList()); + final static List START_UP_IMPORTS = List.of( + new ImportInfo("import module java.base;", "", "java.base")); final static List START_UP_METHODS = Stream.of() .collect(toList()); final static List START_UP_CMD_METHOD = Stream.of() diff --git a/test/langtools/jdk/jshell/StartOptionTest-module-patch/jdk/jshell/tool/resources/PREVIEW_DEFAULT.jsh b/test/langtools/jdk/jshell/StartOptionTest-module-patch/jdk/jshell/tool/resources/PREVIEW_DEFAULT.jsh new file mode 100644 index 00000000000..0146b8af81d --- /dev/null +++ b/test/langtools/jdk/jshell/StartOptionTest-module-patch/jdk/jshell/tool/resources/PREVIEW_DEFAULT.jsh @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +//a patched version of PREVIEW_DEFAULT.jsh, used to verify the correct resource +//is selected when needed: +void sayHello() { + System.out.println("Hello!"); +} diff --git a/test/langtools/jdk/jshell/StartOptionTest.java b/test/langtools/jdk/jshell/StartOptionTest.java index 296fb397c4b..0d6a9d0d65f 100644 --- a/test/langtools/jdk/jshell/StartOptionTest.java +++ b/test/langtools/jdk/jshell/StartOptionTest.java @@ -22,15 +22,17 @@ */ /* - * @test 8151754 8080883 8160089 8170162 8166581 8172102 8171343 8178023 8186708 8179856 8185840 8190383 8341631 + * @test + * @bug 8151754 8080883 8160089 8170162 8166581 8172102 8171343 8178023 8186708 8179856 8185840 8190383 8341631 8341833 8344706 * @summary Testing startExCe-up options. * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool + * jdk.jshell/jdk.internal.jshell.tool.resources:+open * @library /tools/lib * @build Compiler toolbox.ToolBox - * @run testng StartOptionTest + * @run testng/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch StartOptionTest */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -38,13 +40,17 @@ import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.nio.file.Path; +import java.text.MessageFormat; import java.util.HashMap; import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; +import jdk.jshell.JShell; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; @@ -64,6 +70,7 @@ public class StartOptionTest { protected ByteArrayOutputStream userout; protected ByteArrayOutputStream usererr; protected InputStream cmdInStream; + private Map testPersistence; private JavaShellToolBuilder builder() { // turn on logging of launch failures @@ -73,12 +80,23 @@ private JavaShellToolBuilder builder() { .out(new PrintStream(cmdout), new PrintStream(console), new PrintStream(userout)) .err(new PrintStream(cmderr), new PrintStream(usererr)) .in(cmdInStream, null) - .persistence(new HashMap<>()) + .persistence(getThisTestPersistence()) .env(new HashMap<>()) .locale(Locale.ROOT); } + protected Map getThisTestPersistence() { + return testPersistence != null ? testPersistence + : new HashMap<>(); + } + protected int runShell(String... args) { + cmdout.reset(); + cmderr.reset(); + console.reset(); + userout.reset(); + usererr.reset(); + try { return builder() .start(Presets.addExecutionIfMissing(args)); @@ -146,6 +164,25 @@ protected void startCheckUserOutput(Consumer checkUserOutput, String... args) { runShell(args); check(userout, checkUserOutput, "userout"); + check(cmderr, null, "cmderr"); + check(usererr, null, "usererr"); + } + + protected void startCheckCommandUserOutput(Consumer checkCommandOutput, + Consumer checkUserOutput, + Consumer checkCombinedCommandUserOutput, + String... args) { + runShell(args); + check(cmdout, checkCommandOutput, "cmdout"); + check(userout, checkUserOutput, "userout"); + check(usererr, null, "usererr"); + } + + protected void startCheckError(Consumer checkError, + String... args) { + runShell(args); + check(cmderr, checkError, "userout"); + check(userout, null, "userout"); check(usererr, null, "usererr"); } @@ -214,8 +251,12 @@ public void setUp() { } protected String writeToFile(String stuff) { + return writeToFile("doit.repl", stuff); + } + + protected String writeToFile(String fileName, String stuff) { Compiler compiler = new Compiler(); - Path p = compiler.getPath("doit.repl"); + Path p = compiler.getPath(fileName); compiler.writeToFile(p, stuff); return p.toString(); } @@ -389,10 +430,19 @@ public void testPreviewEnabled() { System.out.println(\"suffix\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prefix\nsuffix\n"), - fn); startCheckUserOutput(s -> assertEquals(s, "prefix\njava.lang.invoke.MethodHandle\nsuffix\n"), - "--enable-preview", fn); + fn); + String fn24 = writeToFile( + """ + System.out.println(\"test\"); + /exit + """); + startCheckUserOutput(s -> assertEquals(s, "test\n"), + "-C--release", "-C24", fn24); + startCheckUserOutput(s -> assertEquals(s, "test\n"), + "-C--source", "-C24", fn24); + startCheckUserOutput(s -> assertEquals(s, "test\n"), + "-C-source", "-C24", fn24); //JDK-8341631: String fn2 = writeToFile( """ @@ -401,11 +451,87 @@ public void testPreviewEnabled() { System.out.println(\"suffix\"); /exit """); - startCheckUserOutput(s -> assertEquals(s, "prefix\nsuffix\n"), - fn2); startCheckUserOutput(s -> assertEquals(s, "prefix\ntest\nsuffix\n"), - "--enable-preview", fn2); + fn2); + //verify the correct resource is selected when --enable-preview, relies on + //--patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch + String fn2Preview = writeToFile( + """ + System.out.println(\"prefix\"); + sayHello(); + System.out.println(\"suffix\"); + /exit + """); + startCheckUserOutput(s -> assertEquals(s, "prefix\nHello!\nsuffix\n"), + "--enable-preview", fn2Preview, + "-"); + + testPersistence = new HashMap<>(); + + String newStartupScript = writeToFile("test-startup.repl", + """ + System.out.println("Custom start script"); + """); + String setStartup = writeToFile( + """ + /set start -retain {file} + /exit + """.replace("{file}", newStartupScript)); + startCheckUserOutput(s -> {}, setStartup); + String exit = writeToFile( + """ + /exit + """); + startCheckUserOutput(s -> assertEquals(s, "Custom start script\n"), + exit); + String clearStartup = writeToFile( + """ + /set start -retain -default + /exit + """); + startCheckUserOutput(s -> {}, clearStartup); + String retainTest = writeToFile( + """ + /set start + System.out.println(\"prefix\"); + System.out.println(MethodHandle.class.getName()); + System.out.println(\"suffix\"); + /exit + """); + startCheckCommandUserOutput(s -> assertEquals(s, "/set start -retain -default\n"), + s -> assertEquals(s, "prefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + s -> assertEquals(s, "/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + retainTest); + String retainTest24 = writeToFile( + """ + System.out.println(\"test\"); + /exit + """); + startCheckUserOutput(s -> assertEquals(s, "test\n"), + "-C--release", "-C24", retainTest24); + + String set24DefaultTest = writeToFile( + """ + /set start -default -retain + /exit + """); + startCheckUserOutput(s -> {}, + "-C--release", "-C24", set24DefaultTest); + + String checkDefaultAfterSet24Test = writeToFile( + """ + /set start + System.out.println(\"prefix\"); + System.out.println(MethodHandle.class.getName()); + System.out.println(\"suffix\"); + /exit + """); + startCheckCommandUserOutput(s -> assertEquals(s, "/set start -retain -default\n"), + s -> assertEquals(s, "prefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + s -> assertEquals(s, "/set start -retain -default\nprefix\njava.lang.invoke.MethodHandle\nsuffix\n"), + checkDefaultAfterSet24Test); } + public void testInput() { //readLine(String): String readLinePrompt = writeToFile( @@ -427,6 +553,25 @@ public void testInput() { readPasswordPrompt); } + public void testErroneousFile() { + String code = """ + var v = ( + System.console().readLine("prompt: "); + /exit + """; + String readLinePrompt = writeToFile(code); + String expectedErrorFormat = + ResourceBundle.getBundle("jdk.internal.jshell.tool.resources.l10n", + Locale.getDefault(), + JShell.class.getModule()) + .getString("jshell.err.incomplete.input"); + String expectedError = + new MessageFormat(expectedErrorFormat).format(new Object[] {code}); + startCheckError(s -> assertEquals(s, expectedError), + readLinePrompt); + } + + @AfterMethod public void tearDown() { cmdout = null; diff --git a/test/langtools/jdk/jshell/StopExecutionTest.java b/test/langtools/jdk/jshell/StopExecutionTest.java index 389794d35d2..b1584c0eb89 100644 --- a/test/langtools/jdk/jshell/StopExecutionTest.java +++ b/test/langtools/jdk/jshell/StopExecutionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,25 +33,18 @@ import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; -import java.io.PrintWriter; -import java.io.StringWriter; import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; import jdk.internal.jshell.tool.StopDetectingInputStream; import jdk.internal.jshell.tool.StopDetectingInputStream.State; -import jdk.jshell.JShell; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; @Test -public class StopExecutionTest extends KullaTesting { - - private final Object lock = new Object(); - private boolean isStopped; +public class StopExecutionTest extends AbstractStopExecutionTest { @Test(enabled = false) // TODO 8129546 public void testStopLoop() throws InterruptedException { @@ -68,42 +61,6 @@ public void testScriptCatchesStop() throws Exception { scheduleStop("for (int i = 0; i < 30; i++) { try { Thread.sleep(100); } catch (Throwable ex) { } }"); } - private void scheduleStop(String src) throws InterruptedException { - JShell state = getState(); - isStopped = false; - StringWriter writer = new StringWriter(); - PrintWriter out = new PrintWriter(writer); - Thread t = new Thread(() -> { - int i = 1; - int n = 30; - synchronized (lock) { - do { - state.stop(); - if (!isStopped) { - out.println("Not stopped. Try again: " + i); - try { - lock.wait(1000); - } catch (InterruptedException ignored) { - } - } - } while (i++ < n && !isStopped); - if (!isStopped) { - System.err.println(writer.toString()); - fail("Evaluation was not stopped: '" + src + "'"); - } - } - }); - t.start(); - assertEval(src); - synchronized (lock) { - out.println("Evaluation was stopped successfully: '" + src + "'"); - isStopped = true; - lock.notify(); - } - // wait until the background thread finishes to prevent from calling 'stop' on closed state. - t.join(); - } - public void testStopDetectingInputRandom() throws IOException { long seed = System.nanoTime(); Random r = new Random(seed); diff --git a/test/langtools/jdk/jshell/ToolCommandOptionTest.java b/test/langtools/jdk/jshell/ToolCommandOptionTest.java index ec137a3ec60..affeabacb7a 100644 --- a/test/langtools/jdk/jshell/ToolCommandOptionTest.java +++ b/test/langtools/jdk/jshell/ToolCommandOptionTest.java @@ -274,7 +274,7 @@ public void setStartTest() { (a) -> assertCommand(a, "/set start DEFAULT PRINTING", ""), (a) -> assertCommandOutputContains(a, "/set start", - "/set start DEFAULT PRINTING", "void println", "import java.util.*"), + "/set start DEFAULT PRINTING", "void println", "import module java.base;"), (a) -> assertCommand(a, "/set start " + startup.toString(), ""), (a) -> assertCommandOutputContains(a, "/set start", @@ -333,7 +333,7 @@ public void retainStartTest() { "| ---- PRINTING ----\n", "| int iAmHere = 1234;\n", "| void println(String s)", - "| import java.io.*;") + "| import module java.base;") ); } diff --git a/test/langtools/jdk/jshell/ToolEnablePreviewTest.java b/test/langtools/jdk/jshell/ToolEnablePreviewTest.java index 61a54254455..1825e7b39ad 100644 --- a/test/langtools/jdk/jshell/ToolEnablePreviewTest.java +++ b/test/langtools/jdk/jshell/ToolEnablePreviewTest.java @@ -28,6 +28,11 @@ * @run testng ToolEnablePreviewTest */ +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import org.testng.annotations.Test; import static org.testng.Assert.assertTrue; @@ -70,8 +75,14 @@ public void testCommandLineFlag() { } @Test - public void testCompilerTestFlagEnv() { - test(new String[] {"-C", "-XDforcePreview"}, + public void testCompilerTestFlagEnv() throws IOException { + Path startupFile = Paths.get("startup.repl"); + try (Writer w = Files.newBufferedWriter(startupFile)) { + w.write(""" + import java.util.function.*; + """); + } + test(new String[] {"-C", "-XDforcePreview", "-startup", startupFile.toString()}, (a) -> assertCommandOutputContains(a, "Function f = (var i) -> i + i", "Error", "preview feature"), (a) -> assertCommand(a, "/env --enable-preview", diff --git a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java index 6221f295103..bb6f4588968 100644 --- a/test/langtools/jdk/jshell/ToolLocalSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolLocalSimpleTest.java @@ -73,7 +73,7 @@ public void testOptionR() { public void testCompoundStart() { test(new String[]{"--startup", "DEFAULT", "--startup", "PRINTING", "--startup", "TOOLING"}, (a) -> assertCommandOutputContains(a, "/list -start", - "System.out.println", "import java.util.concurrent", "tools()") + "System.out.println", "import module java.base;", "tools()") ); } diff --git a/test/langtools/jdk/jshell/ToolProviderTest.java b/test/langtools/jdk/jshell/ToolProviderTest.java index 67038c878ab..1a600efe737 100644 --- a/test/langtools/jdk/jshell/ToolProviderTest.java +++ b/test/langtools/jdk/jshell/ToolProviderTest.java @@ -40,9 +40,10 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool:+open + * jdk.jshell/jdk.internal.jshell.tool.resources:+open * @library /tools/lib * @build Compiler toolbox.ToolBox - * @run testng ToolProviderTest + * @run testng/othervm --patch-module jdk.jshell=${test.src}/StartOptionTest-module-patch ToolProviderTest */ @Test public class ToolProviderTest extends StartOptionTest { @@ -71,11 +72,21 @@ protected void startCheckUserOutput(Consumer checkUserOutput, String... check(usererr, null, "usererr"); } + @Override + protected void startCheckCommandUserOutput(Consumer checkCommandOutput, + Consumer checkUserOutput, + Consumer checkCombinedCommandUserOutput, + String... args) { + runShell(args); + check(cmdout, checkCombinedCommandUserOutput, "userout"); + check(usererr, null, "usererr"); + } + @Override protected int runShell(String... args) { //make sure the JShell running during the test is not using persisted preferences from the machine: Function prevAugmentedToolBuilder = - getAndSetAugmentedToolBuilder(builder -> builder.persistence(new HashMap<>())); + getAndSetAugmentedToolBuilder(builder -> builder.persistence(getThisTestPersistence())); try { ServiceLoader sl = ServiceLoader.load(Tool.class); for (Tool provider : sl) { diff --git a/test/langtools/jdk/jshell/ToolSimpleTest.java b/test/langtools/jdk/jshell/ToolSimpleTest.java index 81f75a3863e..62ea2451fb4 100644 --- a/test/langtools/jdk/jshell/ToolSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolSimpleTest.java @@ -33,6 +33,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool + * java.desktop * @build KullaTesting TestingInputStream * @run testng ToolSimpleTest */ @@ -566,11 +567,11 @@ public void testListArgs() { s -> checkLineToList(s, START_UP)), a -> assertCommandCheckOutput(a, "/list -all", s -> checkLineToList(s, startVarList)), - a -> assertCommandOutputStartsWith(a, "/list s3", - "s3 : import"), - a -> assertCommandCheckOutput(a, "/list 1-2 s3", + a -> assertCommandOutputStartsWith(a, "/list s1", + "s1 : import"), + a -> assertCommandCheckOutput(a, "/list 1-2 s1", s -> { - assertTrue(Pattern.matches(".*aardvark.*\\R.*weevil.*\\R.*s3.*import.*", s.trim()), + assertTrue(Pattern.matches(".*aardvark.*\\R.*weevil.*\\R.*s1.*import.*", s.trim()), "No match: " + s); }), a -> assertCommandOutputStartsWith(a, "/list " + arg, @@ -977,4 +978,14 @@ public void testSelfReference() { (a) -> assertCommandOutputContains(a, "var a = a;", "cannot use 'var' on self-referencing variable") ); } + + @Test + public void testModuleImportShortenedTypes() { + test( + (a) -> assertCommandOutputContains(a, "import module java.desktop;", ""), + (a) -> assertCommandOutputContains(a, "var r1 = new JButton()", ""), + (a) -> assertCommandOutputContains(a, "/vars r1", "| JButton r1 =") + ); + } + } diff --git a/test/langtools/jdk/jshell/UITesting.java b/test/langtools/jdk/jshell/UITesting.java index 473ba36c5ae..70a1b12a943 100644 --- a/test/langtools/jdk/jshell/UITesting.java +++ b/test/langtools/jdk/jshell/UITesting.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * 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 java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -62,6 +63,10 @@ public UITesting(boolean laxLineEndings) { } protected void doRunTest(Test test) throws Exception { + doRunTest(test, true); + } + + protected void doRunTest(Test test, boolean setUserInput) throws Exception { // turn on logging of launch failures Logger.getLogger("jdk.jshell.execution").setLevel(Level.ALL); @@ -87,7 +92,7 @@ protected void doRunTest(Test test) throws Exception { Thread runner = new Thread(() -> { try { JavaShellToolBuilder.builder() - .in(input, input) + .in(input, setUserInput ? input : null) .out(outS) .err(outS) .promptCapture(true) diff --git a/test/langtools/tools/javac/6330920/T6330920.java b/test/langtools/tools/javac/6330920/T6330920.java index e9e31577295..39a65954dbc 100644 --- a/test/langtools/tools/javac/6330920/T6330920.java +++ b/test/langtools/tools/javac/6330920/T6330920.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6330920 * @summary Verify that javac doesn't duplicate method error on method with error - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T6330920.out -XDrawDiagnostics T6330920.java */ diff --git a/test/langtools/tools/javac/6457284/T6457284.java b/test/langtools/tools/javac/6457284/T6457284.java index a2a5b8a3f9c..f40d569ad91 100644 --- a/test/langtools/tools/javac/6457284/T6457284.java +++ b/test/langtools/tools/javac/6457284/T6457284.java @@ -25,7 +25,7 @@ * @test * @bug 6457284 * @summary Internationalize "unnamed package" when the term is used in diagnostics - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.util */ diff --git a/test/langtools/tools/javac/8351232/Anno.java b/test/langtools/tools/javac/8351232/Anno.java new file mode 100644 index 00000000000..592467c13eb --- /dev/null +++ b/test/langtools/tools/javac/8351232/Anno.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE_USE) +public @interface Anno {} diff --git a/test/langtools/tools/javac/8351232/Cls.java b/test/langtools/tools/javac/8351232/Cls.java new file mode 100644 index 00000000000..192f0d156b4 --- /dev/null +++ b/test/langtools/tools/javac/8351232/Cls.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class Cls { + + public static Cls newInstance() { + return new Cls<>(); + } + + public V1 doSomething(Intf1 arg) { + throw new UnsupportedOperationException(); + } + + public V1 doSomething(Intf2 arg) { + throw new UnsupportedOperationException(); + } +} diff --git a/test/langtools/tools/javac/8351232/Intf1.java b/test/langtools/tools/javac/8351232/Intf1.java new file mode 100644 index 00000000000..d35841edb8e --- /dev/null +++ b/test/langtools/tools/javac/8351232/Intf1.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public interface Intf1 { + + Object foo(Object bar); + +} diff --git a/test/langtools/tools/javac/8351232/Intf2.java b/test/langtools/tools/javac/8351232/Intf2.java new file mode 100644 index 00000000000..5fcc5ad008b --- /dev/null +++ b/test/langtools/tools/javac/8351232/Intf2.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public interface Intf2 extends Intf1 { +} diff --git a/test/langtools/tools/javac/8351232/TestClass.java b/test/langtools/tools/javac/8351232/TestClass.java new file mode 100644 index 00000000000..f4fce90bb73 --- /dev/null +++ b/test/langtools/tools/javac/8351232/TestClass.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +public class TestClass { + void test() { + Cls.newInstance() + .doSomething( + image -> { + return; + }); + } +} diff --git a/test/langtools/tools/javac/8351232/TypeAnnotationSymNullTest.java b/test/langtools/tools/javac/8351232/TypeAnnotationSymNullTest.java new file mode 100644 index 00000000000..2c32d599cfe --- /dev/null +++ b/test/langtools/tools/javac/8351232/TypeAnnotationSymNullTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8351232 + * @summary NPE when type annotation missing on classpath + * @modules jdk.compiler/com.sun.tools.javac.api + */ + +import java.io.File; +import com.sun.tools.javac.api.*; + +public class TypeAnnotationSymNullTest { + public static void main(String[] args) { + File testSrc = new File(System.getProperty("test.src", ".")); + + File ANNO = new File("ANNO"); + ANNO.mkdirs(); + + // first, compile Anno to the ANNO directory + compile(0, "-d", ANNO.getPath(), new File(testSrc, "Anno.java").getPath()); + + File CLP = new File("CLP"); + CLP.mkdirs(); + + // second, compile Cls, Intf1 and Intf2 to the CLP directory with ANNO on classpath + compile(0, "-cp", ANNO.getPath(), "-d", CLP.getPath(), new File(testSrc, "Cls.java").getPath(), + new File(testSrc, "Intf1.java").getPath(), + new File(testSrc, "Intf2.java").getPath()); + + // now compile TestClass with CLP on classpath (but Anno.class missing) + // compilation fails (exit code 1) but should not get NPE from compiler (exit code 4) + compile(1, "-cp", CLP.getPath(), "-d", ".", new File(testSrc, "TestClass.java").getPath()); + } + + private static void compile(int expectedExit, String... args) { + int exitCode = JavacTool.create().run(null, null, null, args); + if (exitCode != expectedExit) { + throw new AssertionError("test compilation failed with exit code: " + exitCode); + } + } +} diff --git a/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java index 7947b69b830..60d79d93129 100644 --- a/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java +++ b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java @@ -3,7 +3,6 @@ * @bug 8325805 * @summary Permit non-superclass instance field assignments before this/super in constructors * @compile/fail/ref=DA_DUConstructors.out -XDrawDiagnostics DA_DUConstructors.java - * @enablePreview */ public class DA_DUConstructors { diff --git a/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out index 78cd3d314a8..03cd6c2574b 100644 --- a/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out +++ b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out @@ -1,5 +1,3 @@ -DA_DUConstructors.java:23:17: compiler.err.var.might.already.be.assigned: x -DA_DUConstructors.java:42:23: compiler.err.var.might.not.have.been.initialized: x -- compiler.note.preview.filename: DA_DUConstructors.java, DEFAULT -- compiler.note.preview.recompile +DA_DUConstructors.java:22:17: compiler.err.var.might.already.be.assigned: x +DA_DUConstructors.java:41:23: compiler.err.var.might.not.have.been.initialized: x 2 errors diff --git a/test/langtools/tools/javac/ImplicitClass/ErrorRecovery.java b/test/langtools/tools/javac/ImplicitClass/ErrorRecovery.java index 883580893af..ed02e050ac8 100644 --- a/test/langtools/tools/javac/ImplicitClass/ErrorRecovery.java +++ b/test/langtools/tools/javac/ImplicitClass/ErrorRecovery.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 8338301 + * @bug 8338301 8344706 * @summary Verify error recovery and reporting related to implicitly declared classes * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -78,8 +78,7 @@ public void testMethodNoReturnType(Path base) throws Exception { Files.createDirectories(classes); List log = new JavacTask(tb) - .options("-XDrawDiagnostics", - "--enable-preview", "--release", SOURCE_VERSION) + .options("-XDrawDiagnostics") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.FAIL) @@ -87,8 +86,6 @@ public void testMethodNoReturnType(Path base) throws Exception { .getOutputLines(OutputKind.DIRECT); List expected = List.of( "Test.java:1:1: compiler.err.invalid.meth.decl.ret.type.req", - "- compiler.note.preview.filename: Test.java, DEFAULT", - "- compiler.note.preview.recompile", "1 error" ); if (!Objects.equals(expected, log)) { @@ -111,8 +108,7 @@ public void testStatement(Path base) throws Exception { List log = new JavacTask(tb) .options("-XDrawDiagnostics", - "-XDshould-stop.at=FLOW", - "--enable-preview", "--release", SOURCE_VERSION) + "-XDshould-stop.at=FLOW") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.FAIL) @@ -142,8 +138,7 @@ class C {}; Files.createDirectories(classes); new JavacTask(tb) - .options("-XDrawDiagnostics", - "--enable-preview", "--release", SOURCE_VERSION) + .options("-XDrawDiagnostics") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.SUCCESS) @@ -166,8 +161,7 @@ public void testVeryBroken(Path base) throws Exception { List expected; log = new JavacTask(tb) - .options("-XDrawDiagnostics", - "--enable-preview", "--release", SOURCE_VERSION) + .options("-XDrawDiagnostics") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.FAIL) @@ -191,7 +185,7 @@ public void testVeryBroken(Path base) throws Exception { .writeAll() .getOutputLines(OutputKind.DIRECT); expected = List.of( - "Test.java:1:1: compiler.err.expected4: class, interface, enum, record", + "Test.java:1:1: compiler.err.class.method.or.field.expected", "1 error" ); diff --git a/test/langtools/tools/javac/ImplicitClass/ImplicitClassRecovery.java b/test/langtools/tools/javac/ImplicitClass/ImplicitClassRecovery.java index 0057d779f8c..4998a342eae 100644 --- a/test/langtools/tools/javac/ImplicitClass/ImplicitClassRecovery.java +++ b/test/langtools/tools/javac/ImplicitClass/ImplicitClassRecovery.java @@ -1,6 +1,7 @@ /** * @test /nodynamiccopyright/ - * @compile/fail/ref=ImplicitClassRecovery.out -XDrawDiagnostics --enable-preview --source ${jdk.version} ImplicitClassRecovery.java + * @bug 8344706 + * @compile/fail/ref=ImplicitClassRecovery.out -XDrawDiagnostics ImplicitClassRecovery.java */ public void main() { //the following is intentionally missing a semicolon: diff --git a/test/langtools/tools/javac/ImplicitClass/ImplicitClassRecovery.out b/test/langtools/tools/javac/ImplicitClass/ImplicitClassRecovery.out index 7de6ac6b3ee..c9fca33b9bc 100644 --- a/test/langtools/tools/javac/ImplicitClass/ImplicitClassRecovery.out +++ b/test/langtools/tools/javac/ImplicitClass/ImplicitClassRecovery.out @@ -1,4 +1,2 @@ -ImplicitClassRecovery.java:7:33: compiler.err.expected: ';' -- compiler.note.preview.filename: ImplicitClassRecovery.java, DEFAULT -- compiler.note.preview.recompile +ImplicitClassRecovery.java:8:33: compiler.err.expected: ';' 1 error diff --git a/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java b/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java index 1362864d8fe..aefe7d36357 100644 --- a/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java +++ b/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 8325324 + * @bug 8325324 8344706 * @summary Verify behavior w.r.t. implicit imports * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -82,7 +82,6 @@ public static void main(String... args) { {//with --release: new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.SUCCESS) @@ -91,7 +90,6 @@ public static void main(String... args) { var out = new JavaTask(tb) .classpath(classes.toString()) .className("Test") - .vmOptions("--enable-preview") .run() .writeAll() .getOutputLines(Task.OutputKind.STDOUT); @@ -107,7 +105,6 @@ public static void main(String... args) { {//with --source: new JavacTask(tb) - .options("--enable-preview", "--source", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.SUCCESS) @@ -116,7 +113,6 @@ public static void main(String... args) { var out = new JavaTask(tb) .classpath(classes.toString()) .className("Test") - .vmOptions("--enable-preview") .run() .writeAll() .getOutputLines(Task.OutputKind.STDOUT); @@ -132,11 +128,9 @@ public static void main(String... args) { } @Test - public void testImplicitSimpleIOImport(Path base) throws Exception { + public void testNoImplicitSimpleIOImport(Path base) throws Exception { Path current = base.resolve("."); - Path patchClasses = prepareIOPatch(current); - Path src = current.resolve("src"); Path classes = current.resolve("classes"); tb.writeFile(src.resolve("Test.java"), @@ -148,28 +142,21 @@ public static void main(String... args) { Files.createDirectories(classes); - new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION, - "--patch-module", "java.base=" + patchClasses) - .outdir(classes) - .files(tb.findJavaFiles(src)) - .run(Task.Expect.SUCCESS) - .writeAll(); - - var out = new JavaTask(tb) - .classpath(classes.toString()) - .className("Test") - .vmOptions("--enable-preview", - "--patch-module", "java.base=" + patchClasses) - .run() + var log = new JavacTask(tb) + .options("-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) .writeAll() - .getOutputLines(Task.OutputKind.STDOUT); + .getOutputLines(OutputKind.DIRECT); - var expectedOut = List.of("Hello, World!"); + var expectedLog = List.of( + "Test.java:2:5: compiler.err.cant.resolve.location.args: kindname.method, println, , java.lang.String, (compiler.misc.location: kindname.class, Test, null)", + "1 error"); - if (!Objects.equals(expectedOut, out)) { - throw new AssertionError("Incorrect Output, expected: " + expectedOut + - ", actual: " + out); + if (!Objects.equals(expectedLog, log)) { + throw new AssertionError("Incorrect Output, expected: " + expectedLog + + ", actual: " + log); } } @@ -177,9 +164,6 @@ public static void main(String... args) { @Test public void testNoImplicitImportsForOrdinaryClasses(Path base) throws Exception { Path current = base.resolve("."); - - Path patchClasses = prepareIOPatch(current); - Path src = current.resolve("src"); Path classes = current.resolve("classes"); tb.writeFile(src.resolve("Test.java"), @@ -195,9 +179,7 @@ public static void main(String... args) { Files.createDirectories(classes); var log = new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION, - "--patch-module", "java.base=" + patchClasses, - "-XDrawDiagnostics") + .options("-XDrawDiagnostics") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.FAIL) @@ -218,31 +200,6 @@ public static void main(String... args) { } } - private Path prepareIOPatch(Path base) throws IOException { - Path patchSrc = base.resolve("patch-src"); - Path patchClasses = base.resolve("patch-classes"); - tb.writeJavaFiles(patchSrc, - """ - package java.io; - public class IO { - public static void println(Object o) { - System.out.println(o); - } - } - """); - - Files.createDirectories(patchClasses); - - new JavacTask(tb) - .options("--patch-module", "java.base=" + patchSrc) - .outdir(patchClasses) - .files(tb.findJavaFiles(patchSrc)) - .run(Task.Expect.SUCCESS) - .writeAll(); - - return patchClasses; - } - @Test public void testWithExplicitImport(Path base) throws Exception { Path current = base.resolve("."); @@ -260,7 +217,6 @@ public static void main(String... args) { Files.createDirectories(classes); new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.SUCCESS) @@ -269,7 +225,6 @@ public static void main(String... args) { var out = new JavaTask(tb) .classpath(classes.toString()) .className("Test") - .vmOptions("--enable-preview") .run() .writeAll() .getOutputLines(Task.OutputKind.STDOUT); diff --git a/test/langtools/tools/javac/ImplicitClass/NestedClasses.java b/test/langtools/tools/javac/ImplicitClass/NestedClasses.java index 19f070c4d48..4abddacddc8 100644 --- a/test/langtools/tools/javac/ImplicitClass/NestedClasses.java +++ b/test/langtools/tools/javac/ImplicitClass/NestedClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,7 @@ /* * @test - * @bug 8315458 - * @enablePreview + * @bug 8315458 8344706 * @summary Make sure nesting classes don't create symbol conflicts with implicit name. * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -77,7 +76,7 @@ static void compPass(String fileName, String code) throws IOException { String output = new JavacTask(TOOLBOX) .files(List.of(path)) .classpath(".") - .options("-encoding", "utf8", "--enable-preview", "-source", JAVA_VERSION) + .options("-encoding", "utf8") .run() .writeAll() .getOutput(Task.OutputKind.DIRECT); @@ -96,7 +95,7 @@ static void compFail(String fileName, String code) throws IOException { String output = new JavacTask(TOOLBOX) .files(List.of(path)) .classpath(".") - .options("-XDrawDiagnostics", "-encoding", "utf8", "--enable-preview", "-source", JAVA_VERSION) + .options("-XDrawDiagnostics", "-encoding", "utf8") .run(Task.Expect.FAIL) .writeAll() .getOutput(Task.OutputKind.DIRECT); diff --git a/test/langtools/tools/javac/ImplicitClass/NestedEnum.java b/test/langtools/tools/javac/ImplicitClass/NestedEnum.java index 75d4e63f6ab..014612054fa 100644 --- a/test/langtools/tools/javac/ImplicitClass/NestedEnum.java +++ b/test/langtools/tools/javac/ImplicitClass/NestedEnum.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,8 @@ /* * @test + * @bug 8344706 * @summary enums: ensure unnamed class is visible to java.lang.Enum - * @enablePreview * @compile NestedEnum.java */ diff --git a/test/langtools/tools/javac/ImplicitClass/SourceLevelErrorPosition.java b/test/langtools/tools/javac/ImplicitClass/SourceLevelErrorPosition.java index 786c228f11e..5dce53f4dd0 100644 --- a/test/langtools/tools/javac/ImplicitClass/SourceLevelErrorPosition.java +++ b/test/langtools/tools/javac/ImplicitClass/SourceLevelErrorPosition.java @@ -1,8 +1,8 @@ /** * @test /nodynamiccopyright/ - * @bug 8310314 + * @bug 8310314 8344706 * @summary Ensure proper error position for the "implicit classes not supported" error - * @compile/fail/ref=SourceLevelErrorPosition.out -XDrawDiagnostics SourceLevelErrorPosition.java + * @compile/fail/ref=SourceLevelErrorPosition.out --release 24 -XDrawDiagnostics SourceLevelErrorPosition.java */ class Nested {} void main() { diff --git a/test/langtools/tools/javac/ImplicitClass/SourceLevelErrorPosition.out b/test/langtools/tools/javac/ImplicitClass/SourceLevelErrorPosition.out index 1376183d9c6..83e35474f47 100644 --- a/test/langtools/tools/javac/ImplicitClass/SourceLevelErrorPosition.out +++ b/test/langtools/tools/javac/ImplicitClass/SourceLevelErrorPosition.out @@ -1,2 +1,2 @@ -SourceLevelErrorPosition.java:8:1: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.implicit.classes) +SourceLevelErrorPosition.java:8:1: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.implicit.classes), 24, 25 1 error diff --git a/test/langtools/tools/javac/ImplicitClass/TestImplicitClass.java b/test/langtools/tools/javac/ImplicitClass/TestImplicitClass.java index 673c31b6215..8bb666e2bd2 100644 --- a/test/langtools/tools/javac/ImplicitClass/TestImplicitClass.java +++ b/test/langtools/tools/javac/ImplicitClass/TestImplicitClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,7 @@ /* * @test - * @bug 8315458 - * @enablePreview + * @bug 8315458 8344706 * @build Implicit TestImplicitClass * @run main TestImplicitClass * @summary Basic checks of java.lang.Class support for implicit classes diff --git a/test/langtools/tools/javac/ImportModule.java b/test/langtools/tools/javac/ImportModule.java index a53bc92f1b0..f088dbef658 100644 --- a/test/langtools/tools/javac/ImportModule.java +++ b/test/langtools/tools/javac/ImportModule.java @@ -92,7 +92,6 @@ public static void main(String... args) { {//with --release: new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.SUCCESS) @@ -101,7 +100,6 @@ public static void main(String... args) { var out = new JavaTask(tb) .classpath(classes.toString()) .className("test.Test") - .vmOptions("--enable-preview") .run() .writeAll() .getOutputLines(Task.OutputKind.STDOUT); @@ -117,7 +115,6 @@ public static void main(String... args) { {//with --source: new JavacTask(tb) - .options("--enable-preview", "--source", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.SUCCESS) @@ -126,7 +123,6 @@ public static void main(String... args) { var out = new JavaTask(tb) .classpath(classes.toString()) .className("test.Test") - .vmOptions("--enable-preview") .run() .writeAll() .getOutputLines(Task.OutputKind.STDOUT); @@ -161,7 +157,7 @@ public class Test { actualErrors = new JavacTask(tb) - .options("--release", "21", "-XDrawDiagnostics") + .options("--release", "24", "-XDrawDiagnostics") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.FAIL) @@ -169,34 +165,22 @@ public class Test { .getOutputLines(Task.OutputKind.DIRECT); expectedErrors = List.of( - "Test.java:2:8: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.module.imports)", + "Test.java:2:8: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.module.imports), 24, 25", "1 error" ); if (!Objects.equals(expectedErrors, actualErrors)) { throw new AssertionError("Incorrect Output, expected: " + expectedErrors + - ", actual: " + out); + ", actual: " + actualErrors); } - actualErrors = - new JavacTask(tb) - .options("-XDrawDiagnostics") - .outdir(classes) - .files(tb.findJavaFiles(src)) - .run(Task.Expect.FAIL) - .writeAll() - .getOutputLines(Task.OutputKind.DIRECT); - - expectedErrors = List.of( - "Test.java:2:8: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.module.imports)", - "1 error" - ); - - if (!Objects.equals(expectedErrors, actualErrors)) { - throw new AssertionError("Incorrect Output, expected: " + expectedErrors + - ", actual: " + out); - } + new JavacTask(tb) + .options("-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); } @Test @@ -220,8 +204,7 @@ public class Test { List expectedErrors; new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION, - "-XDrawDiagnostics") + .options("-XDrawDiagnostics") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.SUCCESS) @@ -240,7 +223,6 @@ public class Test { """); new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run() @@ -258,7 +240,6 @@ public class Test { """); new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run() @@ -274,7 +255,6 @@ public class Test { """); new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run() @@ -292,8 +272,7 @@ public class Test { actualErrors = new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION, - "-XDrawDiagnostics") + .options("-XDrawDiagnostics") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.FAIL) @@ -302,8 +281,6 @@ public class Test { expectedErrors = List.of( "Test.java:5:5: compiler.err.ref.ambiguous: Date, kindname.class, java.sql.Date, java.sql, kindname.class, java.util.Date, java.util", - "- compiler.note.preview.filename: Test.java, DEFAULT", - "- compiler.note.preview.recompile", "1 error" ); @@ -325,7 +302,6 @@ public class Test { """); new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run() @@ -387,8 +363,7 @@ public static void main(String... args) { actualErrors = new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION, - "-p", libClasses.toString(), + .options("-p", libClasses.toString(), "--add-modules", "lib", "-XDrawDiagnostics") .outdir(classes) @@ -399,8 +374,6 @@ public static void main(String... args) { expectedErrors = List.of( "Test.java:6:9: compiler.err.cant.resolve.location: kindname.class, Impl, , , (compiler.misc.location: kindname.class, test.Test, null)", - "- compiler.note.preview.filename: Test.java, DEFAULT", - "- compiler.note.preview.recompile", "1 error" ); @@ -412,8 +385,7 @@ public static void main(String... args) { actualErrors = new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION, - "-p", libClasses.toString(), + .options("-p", libClasses.toString(), "-XDdev", "-XDrawDiagnostics") .outdir(classes) @@ -425,8 +397,6 @@ public static void main(String... args) { expectedErrors = List.of( "Test.java:2:1: compiler.err.import.module.does.not.read.unnamed: lib", "Test.java:6:9: compiler.err.cant.resolve.location: kindname.class, Impl, , , (compiler.misc.location: kindname.class, test.Test, null)", - "- compiler.note.preview.filename: Test.java, DEFAULT", - "- compiler.note.preview.recompile", "2 errors" ); @@ -444,8 +414,7 @@ public static void main(String... args) { actualErrors = new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION, - "-p", libClasses.toString(), + .options("-p", libClasses.toString(), "-XDdev", "-XDrawDiagnostics") .outdir(classes) @@ -457,8 +426,6 @@ public static void main(String... args) { expectedErrors = List.of( "Test.java:2:1: compiler.err.import.module.does.not.read: test.module, lib", "Test.java:6:9: compiler.err.cant.resolve.location: kindname.class, Impl, , , (compiler.misc.location: kindname.class, test.Test, null)", - "- compiler.note.preview.filename: Test.java, DEFAULT", - "- compiler.note.preview.recompile", "2 errors" ); @@ -539,8 +506,7 @@ public class Impl2 { Files.createDirectories(libClasses); new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION, - "--module-source-path", libSrc.toString(), + .options("--module-source-path", libSrc.toString(), "-XDrawDiagnostics") .outdir(libClasses) .files(tb.findJavaFiles(libSrc)) @@ -591,8 +557,7 @@ public class Test2 { actualErrors = new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION, - "--module-path", libClasses.toString(), + .options("--module-path", libClasses.toString(), "-XDrawDiagnostics") .outdir(classes) .files(tb.findJavaFiles(src)) @@ -611,8 +576,6 @@ public class Test2 { "Test2.java:7:5: compiler.err.cant.resolve.location: kindname.class, Impl1, , , (compiler.misc.location: kindname.class, test.Test2, null)", "Test2.java:10:5: compiler.err.cant.resolve.location: kindname.class, Api6, , , (compiler.misc.location: kindname.class, test.Test2, null)", "Test2.java:11:5: compiler.err.cant.resolve.location: kindname.class, Impl2, , , (compiler.misc.location: kindname.class, test.Test2, null)", - "- compiler.note.preview.plural: DEFAULT", - "- compiler.note.preview.recompile", "10 errors" ); @@ -640,7 +603,6 @@ public class Test { List kinds = new ArrayList<>(); new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) .outdir(classes) .callback(task -> { task.addTaskListener(new TaskListener() { @@ -699,7 +661,6 @@ public class ModuleModuleClass { List kinds = new ArrayList<>(); new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.SUCCESS) @@ -721,7 +682,7 @@ void main() { Files.createDirectories(classes); new JavacTask(tb) - .options("--enable-preview", "--release", SOURCE_VERSION) + .options("--enable-preview", "--release", SOURCE_VERSION) //for implicitly declared classes .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.SUCCESS) @@ -761,8 +722,7 @@ public class C {} Files.createDirectories(classes); List actualErrors = new JavacTask(tb) - .options("-XDrawDiagnostics", - "--enable-preview", "--release", SOURCE_VERSION) + .options("-XDrawDiagnostics") .outdir(classes) .files(tb.findJavaFiles(src)) .run(Task.Expect.FAIL) @@ -772,8 +732,6 @@ public class C {} List expectedErrors = List.of( "module-info.java:3:18: compiler.warn.module.not.found: M1", "module-info.java:6:9: compiler.err.cant.resolve: kindname.class, A, , ", - "- compiler.note.preview.filename: module-info.java, DEFAULT", - "- compiler.note.preview.recompile", "1 error", "1 warning" ); @@ -816,7 +774,7 @@ public class Test { "- compiler.warn.option.obsolete.source: 8", "- compiler.warn.option.obsolete.target: 8", "- compiler.warn.option.obsolete.suppression", - "Test.java:2:8: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.module.imports)", + "Test.java:2:8: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.module.imports), 8, 25", "Test.java:2:1: compiler.err.import.module.not.found: java.base", "Test.java:4:5: compiler.err.cant.resolve.location: kindname.class, List, , , (compiler.misc.location: kindname.class, test.Test, null)", "3 errors", @@ -825,7 +783,7 @@ public class Test { if (!Objects.equals(expectedErrors, actualErrors)) { throw new AssertionError("Incorrect Output, expected: " + expectedErrors + - ", actual: " + out); + ", actual: " + actualErrors); } } @@ -878,7 +836,6 @@ public class Test { List actualErrors = new JavacTask(tb) .options("-XDrawDiagnostics", - "--enable-preview", "--release", SOURCE_VERSION, "--module-source-path", src.toString()) .outdir(classes) .files(tb.findJavaFiles(src)) @@ -888,8 +845,6 @@ public class Test { List expectedErrors = List.of( "Test.java:5:5: compiler.err.ref.ambiguous: A, kindname.class, mb.p1.A, mb.p1, kindname.class, ma.p1.A, ma.p1", - "- compiler.note.preview.filename: Test.java, DEFAULT", - "- compiler.note.preview.recompile", "1 error" ); @@ -914,7 +869,6 @@ public class Test { new JavacTask(tb) .options("-XDrawDiagnostics", - "--enable-preview", "--release", SOURCE_VERSION, "--module-source-path", src.toString()) .outdir(classes) .files(tb.findJavaFiles(src)) @@ -1001,7 +955,8 @@ public static void main(String... args) { Files.createDirectories(maClasses); List actualErrors = new JavacTask(tb) - .options("-XDrawDiagnostics") + .options("-XDrawDiagnostics", + "--release", "24") .outdir(maClasses) .files(tb.findJavaFiles(ma)) .run(Task.Expect.FAIL) @@ -1009,7 +964,7 @@ public static void main(String... args) { .getOutputLines(Task.OutputKind.DIRECT); List expectedErrors = List.of( - "module-info.java:2:4: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.java.base.transitive)", + "module-info.java:2:4: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.java.base.transitive), 24, 25", "1 error" ); @@ -1034,8 +989,7 @@ public static void main(String... args) { } new JavacTask(tb) - .options("-XDrawDiagnostics", - "--enable-preview", "--release", SOURCE_VERSION) + .options("-XDrawDiagnostics") .outdir(maClasses) .files(tb.findJavaFiles(ma)) .run() @@ -1043,7 +997,7 @@ public static void main(String... args) { Path maModuleInfo2 = maClasses.resolve("module-info.class"); - if (ClassFile.of().parse(maModuleInfo2).minorVersion() != ClassFile.PREVIEW_MINOR_VERSION) { + if (ClassFile.of().parse(maModuleInfo2).minorVersion() != 0) { throw new AssertionError("wrong minor version"); } } diff --git a/test/langtools/tools/javac/LocalClassCtorPrologue.java b/test/langtools/tools/javac/LocalClassCtorPrologue.java index 2a7178ed857..b5bd35f4745 100644 --- a/test/langtools/tools/javac/LocalClassCtorPrologue.java +++ b/test/langtools/tools/javac/LocalClassCtorPrologue.java @@ -3,7 +3,6 @@ * @bug 8328649 * @summary Verify local classes in constructor prologues don't have enclosing instances * @compile/fail/ref=LocalClassCtorPrologue.out -XDrawDiagnostics LocalClassCtorPrologue.java - * @enablePreview */ class LocalClassCtorPrologue { diff --git a/test/langtools/tools/javac/LocalClassCtorPrologue.out b/test/langtools/tools/javac/LocalClassCtorPrologue.out index 65f3418825d..086addaacd0 100644 --- a/test/langtools/tools/javac/LocalClassCtorPrologue.out +++ b/test/langtools/tools/javac/LocalClassCtorPrologue.out @@ -1,4 +1,2 @@ -LocalClassCtorPrologue.java:16:17: compiler.err.cant.ref.before.ctor.called: x -- compiler.note.preview.filename: LocalClassCtorPrologue.java, DEFAULT -- compiler.note.preview.recompile +LocalClassCtorPrologue.java:15:17: compiler.err.cant.ref.before.ctor.called: x 1 error diff --git a/test/langtools/tools/javac/OverrideChecks/InterfaceImplements.java b/test/langtools/tools/javac/OverrideChecks/InterfaceImplements.java index 205ee3fa8a4..bb248b13ea1 100644 --- a/test/langtools/tools/javac/OverrideChecks/InterfaceImplements.java +++ b/test/langtools/tools/javac/OverrideChecks/InterfaceImplements.java @@ -25,7 +25,7 @@ * @test * @bug 6399361 * @summary java.lang.Override specification should be revised - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile InterfaceImplements.java */ diff --git a/test/langtools/tools/javac/OverrideChecks/InterfaceOverride.java b/test/langtools/tools/javac/OverrideChecks/InterfaceOverride.java index d985a41fe97..0b7b9de6857 100644 --- a/test/langtools/tools/javac/OverrideChecks/InterfaceOverride.java +++ b/test/langtools/tools/javac/OverrideChecks/InterfaceOverride.java @@ -25,7 +25,7 @@ * @test * @bug 6399361 * @summary java.lang.Override specification should be revised - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile InterfaceOverride.java */ diff --git a/test/langtools/tools/javac/OverrideChecks/Private.java b/test/langtools/tools/javac/OverrideChecks/Private.java index 1b52fbfe461..b69e3601228 100644 --- a/test/langtools/tools/javac/OverrideChecks/Private.java +++ b/test/langtools/tools/javac/OverrideChecks/Private.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6399361 * @summary java.lang.Override specification should be revised - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=Private.out -XDrawDiagnostics Private.java */ diff --git a/test/langtools/tools/javac/OverrideChecks/T6326485.java b/test/langtools/tools/javac/OverrideChecks/T6326485.java index 8b4622d8304..76b3e64f954 100644 --- a/test/langtools/tools/javac/OverrideChecks/T6326485.java +++ b/test/langtools/tools/javac/OverrideChecks/T6326485.java @@ -25,7 +25,7 @@ * @test * @bug 6326485 * @summary Compiler does not enforce rule that interfaces may not use Override annotation - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6326485.java */ diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview1.java b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview1.java index abb6bacbc8f..0d7938d7216 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview1.java +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview1.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8334258 * @summary Disallow early assignment if FLEXIBLE_CONSTRUCTORS preview feature is not enabled - * @compile/fail/ref=EarlyAssignmentNoPreview1.out -XDrawDiagnostics EarlyAssignmentNoPreview1.java + * @compile/fail/ref=EarlyAssignmentNoPreview1.out --release 24 -XDrawDiagnostics EarlyAssignmentNoPreview1.java */ public class EarlyAssignmentNoPreview1 { diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview1.out b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview1.out index 6c5afbbd12b..c28d53b3774 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview1.out +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview1.out @@ -1,2 +1,2 @@ -EarlyAssignmentNoPreview1.java:12:14: compiler.err.preview.feature.disabled: (compiler.misc.feature.flexible.constructors) +EarlyAssignmentNoPreview1.java:12:14: compiler.err.feature.not.supported.in.source: (compiler.misc.feature.flexible.constructors), 24, 25 1 error diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview2.java b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview2.java index 3c33734f42a..64332244e01 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview2.java +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview2.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8334258 * @summary Disallow early assignment if FLEXIBLE_CONSTRUCTORS preview feature is not enabled - * @compile/fail/ref=EarlyAssignmentNoPreview2.out -XDrawDiagnostics EarlyAssignmentNoPreview2.java + * @compile/fail/ref=EarlyAssignmentNoPreview2.out --release 24 -XDrawDiagnostics EarlyAssignmentNoPreview2.java */ public class EarlyAssignmentNoPreview2 { diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview2.out b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview2.out index 38fb885684e..1250c714c4a 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview2.out +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview2.out @@ -1,2 +1,2 @@ -EarlyAssignmentNoPreview2.java:12:14: compiler.err.preview.feature.disabled: (compiler.misc.feature.flexible.constructors) +EarlyAssignmentNoPreview2.java:12:14: compiler.err.feature.not.supported.in.source: (compiler.misc.feature.flexible.constructors), 24, 25 1 error diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview3.java b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview3.java index f6269f2cb1f..e021d80e6c1 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview3.java +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview3.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8334258 * @summary Disallow early assignment if FLEXIBLE_CONSTRUCTORS preview feature is not enabled - * @compile/fail/ref=EarlyAssignmentNoPreview3.out -XDrawDiagnostics EarlyAssignmentNoPreview3.java + * @compile/fail/ref=EarlyAssignmentNoPreview3.out --release 24 -XDrawDiagnostics EarlyAssignmentNoPreview3.java */ public class EarlyAssignmentNoPreview3 { diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview3.out b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview3.out index def9f4f3722..f1ccf9cfa7d 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview3.out +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignmentNoPreview3.out @@ -1,2 +1,2 @@ -EarlyAssignmentNoPreview3.java:12:39: compiler.err.preview.feature.disabled: (compiler.misc.feature.flexible.constructors) +EarlyAssignmentNoPreview3.java:12:39: compiler.err.feature.not.supported.in.source: (compiler.misc.feature.flexible.constructors), 24, 25 1 error diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignments.java b/test/langtools/tools/javac/SuperInit/EarlyAssignments.java index c3cad5d7016..0168ed9f4b4 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignments.java +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignments.java @@ -3,7 +3,6 @@ * @bug 8325805 * @summary Permit non-superclass instance field assignments before this/super in constructors * @compile/fail/ref=EarlyAssignments.out -XDrawDiagnostics EarlyAssignments.java - * @enablePreview */ public class EarlyAssignments { diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignments.out b/test/langtools/tools/javac/SuperInit/EarlyAssignments.out index 38182c2d312..ac765c141e7 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyAssignments.out +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignments.out @@ -1,29 +1,27 @@ -EarlyAssignments.java:21:17: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:22:17: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:23:23: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:31:21: compiler.err.cant.ref.before.ctor.called: super -EarlyAssignments.java:32:21: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:33:26: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:34:34: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:36:36: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:40:17: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:44:21: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:48:22: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:66:13: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:67:17: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:68:25: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:69:31: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:98:17: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:104:22: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:110:35: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:119:17: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:124:22: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:129:29: compiler.err.cant.ref.before.ctor.called: x -EarlyAssignments.java:134:17: compiler.err.cant.ref.before.ctor.called: super -EarlyAssignments.java:139:23: compiler.err.cant.ref.before.ctor.called: this -EarlyAssignments.java:148:13: compiler.err.cant.assign.initialized.before.ctor.called: x -EarlyAssignments.java:157:13: compiler.err.cant.assign.val.to.var: final, x -EarlyAssignments.java:168:13: compiler.err.cant.ref.before.ctor.called: this -- compiler.note.preview.filename: EarlyAssignments.java, DEFAULT -- compiler.note.preview.recompile +EarlyAssignments.java:20:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:21:17: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:22:23: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:30:21: compiler.err.cant.ref.before.ctor.called: super +EarlyAssignments.java:31:21: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:32:26: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:33:34: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:35:36: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:39:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:43:21: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:47:22: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:65:13: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:66:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:67:25: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:68:31: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:97:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:103:22: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:109:35: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:118:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:123:22: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:128:29: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:133:17: compiler.err.cant.ref.before.ctor.called: super +EarlyAssignments.java:138:23: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:147:13: compiler.err.cant.assign.initialized.before.ctor.called: x +EarlyAssignments.java:156:13: compiler.err.cant.assign.val.to.var: final, x +EarlyAssignments.java:167:13: compiler.err.cant.ref.before.ctor.called: this 26 errors diff --git a/test/langtools/tools/javac/SuperInit/EarlyInnerAccessErrorMessageTest.java b/test/langtools/tools/javac/SuperInit/EarlyInnerAccessErrorMessageTest.java index a8ee3a2aea5..c8279543244 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyInnerAccessErrorMessageTest.java +++ b/test/langtools/tools/javac/SuperInit/EarlyInnerAccessErrorMessageTest.java @@ -3,7 +3,6 @@ * @bug 8334488 * @summary Verify the error message generated for early access from inner class * @compile/fail/ref=EarlyInnerAccessErrorMessageTest.out -XDrawDiagnostics EarlyInnerAccessErrorMessageTest.java - * @enablePreview */ public class EarlyInnerAccessErrorMessageTest { int x; diff --git a/test/langtools/tools/javac/SuperInit/EarlyInnerAccessErrorMessageTest.out b/test/langtools/tools/javac/SuperInit/EarlyInnerAccessErrorMessageTest.out index a8d690a4c23..2bea02bed10 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyInnerAccessErrorMessageTest.out +++ b/test/langtools/tools/javac/SuperInit/EarlyInnerAccessErrorMessageTest.out @@ -1,4 +1,2 @@ -EarlyInnerAccessErrorMessageTest.java:12:34: compiler.err.cant.ref.before.ctor.called: x -- compiler.note.preview.filename: EarlyInnerAccessErrorMessageTest.java, DEFAULT -- compiler.note.preview.recompile +EarlyInnerAccessErrorMessageTest.java:11:34: compiler.err.cant.ref.before.ctor.called: x 1 error diff --git a/test/langtools/tools/javac/SuperInit/EarlyLambdaReturn.java b/test/langtools/tools/javac/SuperInit/EarlyLambdaReturn.java index fd63f4c1a3b..a56974ea252 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLambdaReturn.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLambdaReturn.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8345438 * @summary Verify 'return' allowed in a lambda declared in an early construction context - * @enablePreview */ public class EarlyLambdaReturn { diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java index 1c68de603fb..5ac5aba82ed 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java @@ -3,7 +3,6 @@ * @bug 8325805 * @summary Verify local class in early construction context has no outer instance * @compile/fail/ref=EarlyLocalClass.out -XDrawDiagnostics EarlyLocalClass.java - * @enablePreview */ public class EarlyLocalClass { EarlyLocalClass() { diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out index ee01f9c403d..1024b5bdf26 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out @@ -1,4 +1,2 @@ -EarlyLocalClass.java:12:32: compiler.err.cant.ref.before.ctor.called: this -- compiler.note.preview.filename: EarlyLocalClass.java, DEFAULT -- compiler.note.preview.recompile +EarlyLocalClass.java:11:32: compiler.err.cant.ref.before.ctor.called: this 1 error diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalCtorRef.java b/test/langtools/tools/javac/SuperInit/EarlyLocalCtorRef.java index 3346d6ff4f7..6d0c2c74dfe 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalCtorRef.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalCtorRef.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8334248 * @summary Allow early construction local class constructor method references - * @enablePreview */ import java.util.function.Supplier; diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest1.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest1.java index 5d9060da83c..a51189c11c9 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalTest1.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8333313 * @summary Verify references to local classes declared in early construction contexts - * @enablePreview */ public class EarlyLocalTest1 { diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest2.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest2.java index ba90f06dc5e..09dbc66e2d3 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalTest2.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8333313 * @summary Verify references to local classes declared in early construction contexts - * @enablePreview */ public class EarlyLocalTest2 { diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest3.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest3.java index bf8d6faa099..34d280532c3 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalTest3.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8333313 * @summary Verify references to local classes declared in early construction contexts - * @enablePreview */ public class EarlyLocalTest3 { diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest4.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest4.java index cce6092f606..7f6fa032ec7 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalTest4.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest4.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8333313 * @summary Verify references to local classes declared in early construction contexts - * @enablePreview */ public class EarlyLocalTest4 { diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest5.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest5.java index 6858e068af8..c75b97c6beb 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalTest5.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8333313 * @summary Verify references to local classes declared in early construction contexts - * @enablePreview */ import java.util.concurrent.atomic.AtomicReference; diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest6.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest6.java index 742496a48d5..35eda1a5257 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalTest6.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8333313 * @summary Verify references to local classes declared in early construction contexts - * @enablePreview */ import java.util.concurrent.atomic.AtomicReference; diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest7.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest7.java index 1ce63bc04ba..885783eb9b0 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalTest7.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest7.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8333313 * @summary Verify references to local classes declared in early construction contexts - * @enablePreview */ import java.util.concurrent.atomic.AtomicReference; diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalTest8.java b/test/langtools/tools/javac/SuperInit/EarlyLocalTest8.java index 806903e9017..d09e12fcd5d 100644 --- a/test/langtools/tools/javac/SuperInit/EarlyLocalTest8.java +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalTest8.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8333313 * @summary Verify references to local classes declared in early construction contexts - * @enablePreview */ import java.util.concurrent.atomic.AtomicReference; diff --git a/test/langtools/tools/javac/SuperInit/LambdaLocalEarlyCrash.java b/test/langtools/tools/javac/SuperInit/LambdaLocalEarlyCrash.java index 660e7d19f4e..2d2f8c030ee 100644 --- a/test/langtools/tools/javac/SuperInit/LambdaLocalEarlyCrash.java +++ b/test/langtools/tools/javac/SuperInit/LambdaLocalEarlyCrash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8334037 * @summary Test for compiler crash when local class created in early lambda - * @enablePreview */ public class LambdaLocalEarlyCrash { diff --git a/test/langtools/tools/javac/SuperInit/LambdaOuterCapture.java b/test/langtools/tools/javac/SuperInit/LambdaOuterCapture.java index 261b23dc298..f1f8535e2dd 100644 --- a/test/langtools/tools/javac/SuperInit/LambdaOuterCapture.java +++ b/test/langtools/tools/javac/SuperInit/LambdaOuterCapture.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8334252 * @summary Test lambda declared in early construction context - * @enablePreview */ public class LambdaOuterCapture { diff --git a/test/langtools/tools/javac/SuperInit/MultiLevelOuterInstance.java b/test/langtools/tools/javac/SuperInit/MultiLevelOuterInstance.java index e47e70a3bdc..5bdec42f483 100644 --- a/test/langtools/tools/javac/SuperInit/MultiLevelOuterInstance.java +++ b/test/langtools/tools/javac/SuperInit/MultiLevelOuterInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,6 @@ * @test * @bug 8334121 * @summary Anonymous class capturing two enclosing instances fails to compile - * @enablePreview */ public class MultiLevelOuterInstance { diff --git a/test/langtools/tools/javac/SuperInit/SuperInitFails.java b/test/langtools/tools/javac/SuperInit/SuperInitFails.java index feb5b81c1b0..f9cfe5cd7c4 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitFails.java +++ b/test/langtools/tools/javac/SuperInit/SuperInitFails.java @@ -3,7 +3,6 @@ * @bug 8194743 * @summary Permit additional statements before this/super in constructors * @compile/fail/ref=SuperInitFails.out -XDrawDiagnostics SuperInitFails.java - * @enablePreview */ import java.util.concurrent.atomic.AtomicReference; public class SuperInitFails extends AtomicReference implements Iterable { diff --git a/test/langtools/tools/javac/SuperInit/SuperInitFails.out b/test/langtools/tools/javac/SuperInit/SuperInitFails.out index a6cabb6f5ed..1a8e8797135 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitFails.out +++ b/test/langtools/tools/javac/SuperInit/SuperInitFails.out @@ -1,36 +1,34 @@ -SuperInitFails.java:57:9: compiler.err.cant.ref.before.ctor.called: hashCode() -SuperInitFails.java:62:9: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:67:9: compiler.err.cant.ref.before.ctor.called: super -SuperInitFails.java:72:23: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:77:23: compiler.err.cant.ref.before.ctor.called: super -SuperInitFails.java:94:9: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:99:33: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:104:14: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:108:20: compiler.err.not.encl.class: java.lang.Object -SuperInitFails.java:112:17: compiler.err.cant.ref.before.ctor.called: super -SuperInitFails.java:119:22: compiler.err.call.must.only.appear.in.ctor -SuperInitFails.java:125:9: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:133:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record1 -SuperInitFails.java:138:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record2 -SuperInitFails.java:155:31: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:159:15: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:168:13: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:172:17: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:176:24: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:180:18: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:186:28: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:195:25: compiler.err.return.before.superclass.initialized -SuperInitFails.java:200:33: compiler.err.ctor.calls.not.allowed.here -SuperInitFails.java:205:29: compiler.err.redundant.superclass.init -SuperInitFails.java:33:13: compiler.err.call.must.only.appear.in.ctor -SuperInitFails.java:37:14: compiler.err.call.must.only.appear.in.ctor -SuperInitFails.java:41:14: compiler.err.call.must.only.appear.in.ctor -SuperInitFails.java:45:13: compiler.err.call.must.only.appear.in.ctor -SuperInitFails.java:49:33: compiler.err.call.must.only.appear.in.ctor -SuperInitFails.java:53:32: compiler.err.call.must.only.appear.in.ctor -SuperInitFails.java:83:18: compiler.err.ctor.calls.not.allowed.here -SuperInitFails.java:89:13: compiler.err.return.before.superclass.initialized -SuperInitFails.java:150:18: compiler.err.call.must.only.appear.in.ctor -- compiler.note.preview.filename: SuperInitFails.java, DEFAULT -- compiler.note.preview.recompile +SuperInitFails.java:56:9: compiler.err.cant.ref.before.ctor.called: hashCode() +SuperInitFails.java:61:9: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:66:9: compiler.err.cant.ref.before.ctor.called: super +SuperInitFails.java:71:23: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:76:23: compiler.err.cant.ref.before.ctor.called: super +SuperInitFails.java:93:9: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:98:33: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:103:14: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:107:20: compiler.err.not.encl.class: java.lang.Object +SuperInitFails.java:111:17: compiler.err.cant.ref.before.ctor.called: super +SuperInitFails.java:118:22: compiler.err.call.must.only.appear.in.ctor +SuperInitFails.java:124:9: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:132:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record1 +SuperInitFails.java:137:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record2 +SuperInitFails.java:154:31: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:158:15: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:167:13: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:171:17: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:175:24: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:179:18: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:185:28: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:194:25: compiler.err.return.before.superclass.initialized +SuperInitFails.java:199:33: compiler.err.ctor.calls.not.allowed.here +SuperInitFails.java:204:29: compiler.err.redundant.superclass.init +SuperInitFails.java:32:13: compiler.err.call.must.only.appear.in.ctor +SuperInitFails.java:36:14: compiler.err.call.must.only.appear.in.ctor +SuperInitFails.java:40:14: compiler.err.call.must.only.appear.in.ctor +SuperInitFails.java:44:13: compiler.err.call.must.only.appear.in.ctor +SuperInitFails.java:48:33: compiler.err.call.must.only.appear.in.ctor +SuperInitFails.java:52:32: compiler.err.call.must.only.appear.in.ctor +SuperInitFails.java:82:18: compiler.err.ctor.calls.not.allowed.here +SuperInitFails.java:88:13: compiler.err.return.before.superclass.initialized +SuperInitFails.java:149:18: compiler.err.call.must.only.appear.in.ctor 33 errors diff --git a/test/langtools/tools/javac/SuperInit/SuperInitGood.java b/test/langtools/tools/javac/SuperInit/SuperInitGood.java index 11b845f7d32..5952ecc6615 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitGood.java +++ b/test/langtools/tools/javac/SuperInit/SuperInitGood.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,8 @@ */ /* * @test - * @bug 8194743 + * @bug 8194743 8345438 8356551 8349754 * @summary Test valid placements of super()/this() in constructors - * @enablePreview */ import java.util.concurrent.atomic.AtomicReference; @@ -454,7 +453,7 @@ public void bar() { } } - // Lambdas within constructors + // Lambdas within constructors (JDK-8345438) public static class Test22 { public Test22() { Runnable r = () -> System.out.println(); @@ -490,6 +489,29 @@ class A { } } + // Receiver parameter syntax (JDK-8356551) + public static class Test23 { + public Test23() { + class Local { + Local(Test23 Test23.this) { + } + } + super(); + new Local(); + } + } + + // Test for JDK-8349754 + public static class Test24 { + private int i; + class Sub extends Test24 { + Sub() { + i = 3; // here "i" refers to "Test23.this.i", not "this.i" - so it's OK + super(); + } + } + } + public static void main(String[] args) { new Test0(); new Test1(); @@ -535,5 +557,7 @@ public static void main(String[] args) { new Test21((int)123); new Test21((float)123); new Test22('x'); + new Test23(); + new Test24(); } } diff --git a/test/langtools/tools/javac/T4093617/T4093617.java b/test/langtools/tools/javac/T4093617/T4093617.java index 8fa7dfaca55..35b6dcaadb8 100644 --- a/test/langtools/tools/javac/T4093617/T4093617.java +++ b/test/langtools/tools/javac/T4093617/T4093617.java @@ -25,7 +25,6 @@ * @test * @bug 4093617 * @summary Object has no superclass - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/module=java.base/fail/ref=T4093617.out -XDrawDiagnostics java/lang/Object.java */ - diff --git a/test/langtools/tools/javac/T4848619/T4848619a.java b/test/langtools/tools/javac/T4848619/T4848619a.java index 859c3b4e1f7..dd76ff1d4dd 100644 --- a/test/langtools/tools/javac/T4848619/T4848619a.java +++ b/test/langtools/tools/javac/T4848619/T4848619a.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 4848619 * @summary static final variable declared after use and self initialized - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T4848619a.out -XDrawDiagnostics T4848619a.java */ diff --git a/test/langtools/tools/javac/T4848619/T4848619b.java b/test/langtools/tools/javac/T4848619/T4848619b.java index b1677c60091..1db06329796 100644 --- a/test/langtools/tools/javac/T4848619/T4848619b.java +++ b/test/langtools/tools/javac/T4848619/T4848619b.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 4848619 * @summary static final variable declared after use and self initialized - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T4848619b.out -XDrawDiagnostics T4848619b.java */ diff --git a/test/langtools/tools/javac/T4994049/DeprecatedYES.java b/test/langtools/tools/javac/T4994049/DeprecatedYES.java index ec59558dcc7..6812543d904 100644 --- a/test/langtools/tools/javac/T4994049/DeprecatedYES.java +++ b/test/langtools/tools/javac/T4994049/DeprecatedYES.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6229758 * @summary deprecatedNOT! is - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile -Xlint:deprecation DeprecatedYES.java * @compile/fail/ref=DeprecatedYES.out -XDrawDiagnostics -Werror -Xlint:deprecation DeprecatedYES.java */ diff --git a/test/langtools/tools/javac/T4994049/T4994049.java b/test/langtools/tools/javac/T4994049/T4994049.java index efbddd2da38..1886b989b9b 100644 --- a/test/langtools/tools/javac/T4994049/T4994049.java +++ b/test/langtools/tools/javac/T4994049/T4994049.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 4994049 * @summary Improved diagnostics while parsing enums - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T4994049.out -XDrawDiagnostics T4994049.java */ diff --git a/test/langtools/tools/javac/T5003235/T5003235a.java b/test/langtools/tools/javac/T5003235/T5003235a.java index 3a14d960f5d..c146c964f69 100644 --- a/test/langtools/tools/javac/T5003235/T5003235a.java +++ b/test/langtools/tools/javac/T5003235/T5003235a.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5003235 * @summary Private inner class accessible from subclasses - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T5003235a.out -XDrawDiagnostics T5003235a.java */ diff --git a/test/langtools/tools/javac/T5003235/T5003235b.java b/test/langtools/tools/javac/T5003235/T5003235b.java index 8cb9bdaf85f..5d129fe335a 100644 --- a/test/langtools/tools/javac/T5003235/T5003235b.java +++ b/test/langtools/tools/javac/T5003235/T5003235b.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5003235 * @summary Accessibility of private inner class - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T5003235b.out -XDrawDiagnostics T5003235b.java */ diff --git a/test/langtools/tools/javac/T5003235/T5003235c.java b/test/langtools/tools/javac/T5003235/T5003235c.java index 991c63ac984..38c51457352 100644 --- a/test/langtools/tools/javac/T5003235/T5003235c.java +++ b/test/langtools/tools/javac/T5003235/T5003235c.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5003235 * @summary Access to private inner classes - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T5003235c.out -XDrawDiagnostics T5003235c.java */ diff --git a/test/langtools/tools/javac/T5092545.java b/test/langtools/tools/javac/T5092545.java index f56677ffc7a..0191c789e6c 100644 --- a/test/langtools/tools/javac/T5092545.java +++ b/test/langtools/tools/javac/T5092545.java @@ -25,7 +25,7 @@ * @test * @bug 5092545 * @summary Assertion failed in javac (ClassWriter.java:513) - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé */ interface A { void g(); } diff --git a/test/langtools/tools/javac/T5105890.java b/test/langtools/tools/javac/T5105890.java index 867c5a73fb3..12e579a8349 100644 --- a/test/langtools/tools/javac/T5105890.java +++ b/test/langtools/tools/javac/T5105890.java @@ -25,7 +25,7 @@ * @test * @bug 5105890 * @summary (codegen) constant folding broken for conditional operator - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé */ public class T5105890 { diff --git a/test/langtools/tools/javac/T6180021/AbstractSub.java b/test/langtools/tools/javac/T6180021/AbstractSub.java index f5b28abf17f..67334bdfc71 100644 --- a/test/langtools/tools/javac/T6180021/AbstractSub.java +++ b/test/langtools/tools/javac/T6180021/AbstractSub.java @@ -25,7 +25,7 @@ * @test * @bug 6180021 * @summary CompletionFailure during TypeTrans - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile Super.java * @clean Missing * @compile AbstractSub.java diff --git a/test/langtools/tools/javac/T6180021/Sub.java b/test/langtools/tools/javac/T6180021/Sub.java index c1ed3e9a704..3233b9a2bf0 100644 --- a/test/langtools/tools/javac/T6180021/Sub.java +++ b/test/langtools/tools/javac/T6180021/Sub.java @@ -25,7 +25,7 @@ * @test * @bug 6180021 * @summary CompletionFailure during TypeTrans - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile Super.java * @clean Missing * @compile Sub.java diff --git a/test/langtools/tools/javac/T6231246/T6231246.java b/test/langtools/tools/javac/T6231246/T6231246.java index c2d259ff10c..34835d9e454 100644 --- a/test/langtools/tools/javac/T6231246/T6231246.java +++ b/test/langtools/tools/javac/T6231246/T6231246.java @@ -25,7 +25,7 @@ * @test * @bug 6231246 * @summary Javac crash with -g:none - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile -g:none T6231246.java */ diff --git a/test/langtools/tools/javac/T6231847.java b/test/langtools/tools/javac/T6231847.java index 8d4ef4112e7..fa3102f9afd 100644 --- a/test/langtools/tools/javac/T6231847.java +++ b/test/langtools/tools/javac/T6231847.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6231847 * @summary Crash in com.sun.tools.javac.comp.Attr.visitNewClass:1352 - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T6231847.out -XDdev -XDrawDiagnostics T6231847.java */ diff --git a/test/langtools/tools/javac/T6266772.java b/test/langtools/tools/javac/T6266772.java index 8a5e5133766..79ae48a28fc 100644 --- a/test/langtools/tools/javac/T6266772.java +++ b/test/langtools/tools/javac/T6266772.java @@ -25,7 +25,7 @@ * @test * @bug 6266772 * @summary javac crashes, assertion failure in Lower.java - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé */ public class T6266772 { diff --git a/test/langtools/tools/javac/T6407257.java b/test/langtools/tools/javac/T6407257.java index 7d5da43cab0..0b6b339fdc2 100644 --- a/test/langtools/tools/javac/T6407257.java +++ b/test/langtools/tools/javac/T6407257.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6407257 * @summary javac locks up when encountering cyclic inheritance - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T6407257.out -XDrawDiagnostics T6407257.java */ diff --git a/test/langtools/tools/javac/T8036019.out b/test/langtools/tools/javac/T8036019.out index 2c874175793..b940093a57f 100644 --- a/test/langtools/tools/javac/T8036019.out +++ b/test/langtools/tools/javac/T8036019.out @@ -5,6 +5,6 @@ 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 +T8036019.java:43:27: compiler.err.class.method.or.field.expected +T8036019.java:46:1: compiler.err.class.method.or.field.expected 9 errors \ No newline at end of file diff --git a/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java b/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java index ff3f2cf3200..95a9ef2dd53 100644 --- a/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java +++ b/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -151,7 +151,7 @@ public com.sun.tools.javac.code.Type attribStat(JCTree tree, Env en com.sun.tools.javac.code.Type result = super.attribStat(tree, env); if (tree.hasTag(TRY)) { JCTry tryTree = (JCTry)tree; - lineNumber = env.toplevel.lineMap.getLineNumber(tryTree.finalizer.endpos); + lineNumber = env.toplevel.lineMap.getLineNumber(tryTree.finalizer.bracePos); } return result; } diff --git a/test/langtools/tools/javac/T8347530.java b/test/langtools/tools/javac/T8347530.java new file mode 100644 index 00000000000..e4db1eb6031 --- /dev/null +++ b/test/langtools/tools/javac/T8347530.java @@ -0,0 +1,29 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8347530 + * @summary Improve error message with invalid permits clauses + * @compile/fail/ref=T8347530.out -XDrawDiagnostics T8347530.java + */ + +class T8347530 { + // sealed interfaces + sealed interface A0 permits B0 {} + class B0 {} // class {0} must implement sealed interface + + sealed interface A1 permits B1 {} + record B1() {} // record {0} must implement sealed interface + + sealed interface A2 permits B2 {} + enum B2 {} // enum {0} must implement sealed interface + + sealed interface A3 permits B3 {} + interface B3 {} // interface {0} must implement sealed interface + + // sealed classes + sealed class C0 permits S0 {} + class S0 {} // class {0} must extend sealed class + + // record cannot extend other classes in general + // enums cannot extend other classes in general + // interfaces cannot extend other classes in general +} diff --git a/test/langtools/tools/javac/T8347530.out b/test/langtools/tools/javac/T8347530.out new file mode 100644 index 00000000000..d1252f39717 --- /dev/null +++ b/test/langtools/tools/javac/T8347530.out @@ -0,0 +1,6 @@ +T8347530.java:10:33: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.implement.sealed: kindname.class, T8347530.B0) +T8347530.java:13:33: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.implement.sealed: kindname.record, T8347530.B1) +T8347530.java:16:33: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.implement.sealed: kindname.enum, T8347530.B2) +T8347530.java:19:33: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.implement.sealed: kindname.interface, T8347530.B3) +T8347530.java:23:29: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.extend.sealed: T8347530.S0) +5 errors diff --git a/test/langtools/tools/javac/annotations/neg/NoAnnotationMethods.java b/test/langtools/tools/javac/annotations/neg/NoAnnotationMethods.java index e13c537230d..1f22cefa0cf 100644 --- a/test/langtools/tools/javac/annotations/neg/NoAnnotationMethods.java +++ b/test/langtools/tools/javac/annotations/neg/NoAnnotationMethods.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6393539 * @summary no compile-time error for clone, etc. in annotation type - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=NoAnnotationMethods.out -XDrawDiagnostics NoAnnotationMethods.java */ diff --git a/test/langtools/tools/javac/annotations/neg/NoClone.java b/test/langtools/tools/javac/annotations/neg/NoClone.java index 13237fe91a7..8979ca1cdd0 100644 --- a/test/langtools/tools/javac/annotations/neg/NoClone.java +++ b/test/langtools/tools/javac/annotations/neg/NoClone.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6393539 * @summary no compile-time error for clone, etc. in annotation type - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=NoClone.out -XDrawDiagnostics NoClone.java */ diff --git a/test/langtools/tools/javac/annotations/neg/NoObjectMethods.java b/test/langtools/tools/javac/annotations/neg/NoObjectMethods.java index 8e4df05f7bd..668aa8c47bd 100644 --- a/test/langtools/tools/javac/annotations/neg/NoObjectMethods.java +++ b/test/langtools/tools/javac/annotations/neg/NoObjectMethods.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6393539 * @summary no compile-time error for clone, etc. in annotation type - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=NoObjectMethods.out -XDrawDiagnostics NoObjectMethods.java */ diff --git a/test/langtools/tools/javac/annotations/pos/AnnotationMethods.java b/test/langtools/tools/javac/annotations/pos/AnnotationMethods.java index c0f02bf1b82..129fe57b667 100644 --- a/test/langtools/tools/javac/annotations/pos/AnnotationMethods.java +++ b/test/langtools/tools/javac/annotations/pos/AnnotationMethods.java @@ -25,7 +25,7 @@ * @test * @bug 6393539 * @summary no compile-time error for clone, etc. in annotation type - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile AnnotationMethods.java */ diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/RichFormatterWithTypeAnnotationsReentrantTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/RichFormatterWithTypeAnnotationsReentrantTest.java new file mode 100644 index 00000000000..8b0afb50e65 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/RichFormatterWithTypeAnnotationsReentrantTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025, 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 8356441 + * @summary Recursive formatting in RichDiagnosticFormatter + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.main jdk.compiler/com.sun.tools.javac.api + * @build toolbox.ToolBox toolbox.JavacTask + * @run main RichFormatterWithTypeAnnotationsReentrantTest + */ +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +public class RichFormatterWithTypeAnnotationsReentrantTest extends TestRunner { + ToolBox tb; + + public RichFormatterWithTypeAnnotationsReentrantTest() { + super(System.err); + tb = new ToolBox(); + } + + public static void main(String[] args) throws Exception { + new RichFormatterWithTypeAnnotationsReentrantTest() + .runTests(m -> new Object[] {Paths.get(m.getName())}); + } + + @Test + public void test(Path base) throws Exception { + Path libClasses = base.resolve("libclasses"); + Files.createDirectories(libClasses); + new JavacTask(tb) + .outdir(libClasses) + .sources( + """ + package lib; + enum Bar { + BAZ + } + """, + """ + package lib; + import java.lang.annotation.ElementType; + import java.lang.annotation.Retention; + import java.lang.annotation.RetentionPolicy; + import java.lang.annotation.Target; + + @Retention(RetentionPolicy.RUNTIME) + @interface Foo { + Bar value(); + } + """, + """ + package lib; + import java.lang.annotation.ElementType; + import java.lang.annotation.Retention; + import java.lang.annotation.RetentionPolicy; + import java.lang.annotation.Target; + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE_USE, ElementType.PARAMETER}) + @Foo(Bar.BAZ) + @interface A {} + """, + """ + package lib; + public interface M { + String f(@A String k, @A String v); + } + """) + .run() + .writeAll(); + Files.delete(libClasses.resolve("lib").resolve("Bar.class")); + String code = + """ + import lib.M; + class T implements M { + } + """; + // verify that the compilation fails wtih an error, and does not crash + new JavacTask(tb) + .classpath(libClasses) + .sources(code) + .run(Task.Expect.FAIL); + } +} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/RichFormatterWithTypeAnnotationsTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/RichFormatterWithTypeAnnotationsTest.java new file mode 100644 index 00000000000..4482bd46854 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/RichFormatterWithTypeAnnotationsTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2025, 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 8355065 + * @summary ConcurrentModificationException in RichDiagnosticFormatter + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.main jdk.compiler/com.sun.tools.javac.api + * @build toolbox.ToolBox toolbox.JavacTask + * @run main RichFormatterWithTypeAnnotationsTest + */ +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +public class RichFormatterWithTypeAnnotationsTest extends TestRunner { + ToolBox tb; + + public RichFormatterWithTypeAnnotationsTest() { + super(System.err); + tb = new ToolBox(); + } + + public static void main(String[] args) throws Exception { + new RichFormatterWithTypeAnnotationsTest() + .runTests(m -> new Object[] {Paths.get(m.getName())}); + } + + @Test + public void test(Path base) throws Exception { + Path libClasses = base.resolve("libclasses"); + Files.createDirectories(libClasses); + new JavacTask(tb) + .outdir(libClasses) + .sources( + """ + package lib; + enum Bar { + BAZ + } + """, + """ + package lib; + import java.lang.annotation.ElementType; + import java.lang.annotation.Retention; + import java.lang.annotation.RetentionPolicy; + import java.lang.annotation.Target; + + @Retention(RetentionPolicy.RUNTIME) + @interface Foo { + Bar value(); + } + """, + """ + package lib; + import java.lang.annotation.ElementType; + import java.lang.annotation.Retention; + import java.lang.annotation.RetentionPolicy; + import java.lang.annotation.Target; + + @Retention(RetentionPolicy.RUNTIME) + @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) + @Foo(Bar.BAZ) + @interface A {} + """, + """ + package lib; + public interface M { + @A + V f(K k, V v); + } + """) + .options() + .run() + .writeAll(); + Files.delete(libClasses.resolve("lib").resolve("Bar.class")); + String code = + """ + import lib.M; + class T { + protected M m; + + public void f() { + m.f(null, 0); + } + } + """; + List output = + new JavacTask(tb) + .classpath(libClasses) + .sources(code) + .options("-Xlint:all", "-Werror", "-XDrawDiagnostics") + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + List expected = + Arrays.asList( + "T.java:3:13: compiler.warn.raw.class.use: lib.M, lib.M", + "T.java:6:8: compiler.warn.unchecked.call.mbr.of.raw.type: f(K,V), lib.M", + "- compiler.err.warnings.and.werror", + "1 error", + "2 warnings"); + tb.checkEqual(expected, output); + } +} diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out index d202af7bd77..4b28708932d 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out @@ -1,7 +1,7 @@ AnnotatedImport.java:10:13: compiler.err.expected: token.identifier -AnnotatedImport.java:10:16: compiler.err.expected4: class, interface, enum, record -AnnotatedImport.java:11:1: compiler.err.expected4: class, interface, enum, record -AnnotatedImport.java:11:11: compiler.err.expected4: class, interface, enum, record -AnnotatedImport.java:12:1: compiler.err.expected4: class, interface, enum, record -AnnotatedImport.java:12:21: compiler.err.expected4: class, interface, enum, record +AnnotatedImport.java:10:16: compiler.err.class.method.or.field.expected +AnnotatedImport.java:11:1: compiler.err.class.method.or.field.expected +AnnotatedImport.java:11:11: compiler.err.class.method.or.field.expected +AnnotatedImport.java:12:1: compiler.err.class.method.or.field.expected +AnnotatedImport.java:12:21: compiler.err.class.method.or.field.expected 6 errors diff --git a/test/langtools/tools/javac/api/6400303/T6400303.java b/test/langtools/tools/javac/api/6400303/T6400303.java index 06e9b419cfe..c3a01c007b3 100644 --- a/test/langtools/tools/javac/api/6400303/T6400303.java +++ b/test/langtools/tools/javac/api/6400303/T6400303.java @@ -25,7 +25,7 @@ * @test * @bug 6400303 * @summary REGRESSION: javadoc crashes in b75 - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.code * jdk.compiler/com.sun.tools.javac.comp diff --git a/test/langtools/tools/javac/api/6410643/T6410643.java b/test/langtools/tools/javac/api/6410643/T6410643.java index e15a5272152..a551f802d62 100644 --- a/test/langtools/tools/javac/api/6410643/T6410643.java +++ b/test/langtools/tools/javac/api/6410643/T6410643.java @@ -25,7 +25,7 @@ * @test * @bug 6410643 * @summary JSR 199: The method JavaCompilerTool.run fails to handle null arguments - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6411310/T6411310.java b/test/langtools/tools/javac/api/6411310/T6411310.java index 55945e61fbc..2714117962f 100644 --- a/test/langtools/tools/javac/api/6411310/T6411310.java +++ b/test/langtools/tools/javac/api/6411310/T6411310.java @@ -25,7 +25,7 @@ * @test * @bug 6411310 * @summary JSR 199: FileObject should support user-friendly names via getName() - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6411333/T6411333.java b/test/langtools/tools/javac/api/6411333/T6411333.java index f33e6f63a28..83726143964 100644 --- a/test/langtools/tools/javac/api/6411333/T6411333.java +++ b/test/langtools/tools/javac/api/6411333/T6411333.java @@ -25,7 +25,7 @@ * @test * @bug 6411333 6400208 6400225 6400267 * @summary Ensure 6400208, 6400225, and 6400267 are tested - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6412656/T6412656.java b/test/langtools/tools/javac/api/6412656/T6412656.java index 0924d5df55e..b7976e036fd 100644 --- a/test/langtools/tools/javac/api/6412656/T6412656.java +++ b/test/langtools/tools/javac/api/6412656/T6412656.java @@ -25,7 +25,7 @@ * @test * @bug 6412656 6443062 * @summary JSR 199: pass annotation processor instances to compiler - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6415780/T6415780.java b/test/langtools/tools/javac/api/6415780/T6415780.java index dc74aa96fb0..99c0a476bee 100644 --- a/test/langtools/tools/javac/api/6415780/T6415780.java +++ b/test/langtools/tools/javac/api/6415780/T6415780.java @@ -26,7 +26,7 @@ * @bug 6415780 * @summary JSR 199: javax.tools.JavaFileManager.getClassLoader always fails * @author igor.tseytin@... - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6418694/T6418694.java b/test/langtools/tools/javac/api/6418694/T6418694.java index 8eb237586b7..9e8ee8e850b 100644 --- a/test/langtools/tools/javac/api/6418694/T6418694.java +++ b/test/langtools/tools/javac/api/6418694/T6418694.java @@ -25,7 +25,7 @@ * @test * @bug 6418694 * @summary JSR 199: JavaFileManager.hasLocation(Location) - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6420409/T6420409.java b/test/langtools/tools/javac/api/6420409/T6420409.java index 60cfc4272d8..d12274f5f3b 100644 --- a/test/langtools/tools/javac/api/6420409/T6420409.java +++ b/test/langtools/tools/javac/api/6420409/T6420409.java @@ -25,7 +25,7 @@ * @test * @bug 6420409 * @summary JSR 199: StandardFileManager: cannot set CLASS_PATH location - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/api/6421111/T6421111.java b/test/langtools/tools/javac/api/6421111/T6421111.java index 699c771e38e..9497e2ca22f 100644 --- a/test/langtools/tools/javac/api/6421111/T6421111.java +++ b/test/langtools/tools/javac/api/6421111/T6421111.java @@ -25,7 +25,7 @@ * @test * @bug 6421111 * @summary NullPointerException thrown when retrieving bounds for the type parameter - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6421756/T6421756.java b/test/langtools/tools/javac/api/6421756/T6421756.java index 9e2cfb8cbc8..00efff6971c 100644 --- a/test/langtools/tools/javac/api/6421756/T6421756.java +++ b/test/langtools/tools/javac/api/6421756/T6421756.java @@ -25,7 +25,7 @@ * @test * @bug 6421756 * @summary 6421756 JSR 199: In the method JavaCompilerTool.getTask 'options' can be supplied in the place of 'classes' - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6422215/T6422215.java b/test/langtools/tools/javac/api/6422215/T6422215.java index 1c25a6e38da..425d47616f0 100644 --- a/test/langtools/tools/javac/api/6422215/T6422215.java +++ b/test/langtools/tools/javac/api/6422215/T6422215.java @@ -25,7 +25,7 @@ * @test * @bug 6422215 * @summary JSR 199: What happens if a directory is missing - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6422327/T6422327.java b/test/langtools/tools/javac/api/6422327/T6422327.java index 5029a199408..94a31101f16 100644 --- a/test/langtools/tools/javac/api/6422327/T6422327.java +++ b/test/langtools/tools/javac/api/6422327/T6422327.java @@ -25,7 +25,7 @@ * @test * @bug 6422327 * @summary JSR 199: JavaCompilerTool can compile and generate '.class' of non '.java' files - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6423003/T6423003.java b/test/langtools/tools/javac/api/6423003/T6423003.java index 810789b93ab..893f2dd6344 100644 --- a/test/langtools/tools/javac/api/6423003/T6423003.java +++ b/test/langtools/tools/javac/api/6423003/T6423003.java @@ -25,7 +25,7 @@ * @test * @bug 6423003 * @summary JSR 199: confusing help message with compiler API - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6431257/T6431257.java b/test/langtools/tools/javac/api/6431257/T6431257.java index 291d4222cc0..c772a3c129c 100644 --- a/test/langtools/tools/javac/api/6431257/T6431257.java +++ b/test/langtools/tools/javac/api/6431257/T6431257.java @@ -25,7 +25,7 @@ * @test * @bug 6431257 * @summary JSR 199: Changes to JavaFileManager to support JSR 269 Filer API - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6437999/T6437999.java b/test/langtools/tools/javac/api/6437999/T6437999.java index a44bd2b0d6a..167c7feda11 100644 --- a/test/langtools/tools/javac/api/6437999/T6437999.java +++ b/test/langtools/tools/javac/api/6437999/T6437999.java @@ -25,7 +25,7 @@ * @test * @bug 6437999 * @summary Unit test for encoding argument to standard file manager - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6440333/T6440333.java b/test/langtools/tools/javac/api/6440333/T6440333.java index 21a1247a2b6..5da878273b3 100644 --- a/test/langtools/tools/javac/api/6440333/T6440333.java +++ b/test/langtools/tools/javac/api/6440333/T6440333.java @@ -25,7 +25,7 @@ * @test * @bug 6440333 * @summary SimpleJavaFileObject.toString() generates URI with some extra message - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6440528/T6440528.java b/test/langtools/tools/javac/api/6440528/T6440528.java index ef94ccb96a7..3b72fd39255 100644 --- a/test/langtools/tools/javac/api/6440528/T6440528.java +++ b/test/langtools/tools/javac/api/6440528/T6440528.java @@ -25,7 +25,7 @@ * @test * @bug 6440528 * @summary javac deposits package-info.class in bogus directory - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler/com.sun.tools.javac.file diff --git a/test/langtools/tools/javac/api/6452876/T6452876.java b/test/langtools/tools/javac/api/6452876/T6452876.java index cab4f118558..49a25a3bd32 100644 --- a/test/langtools/tools/javac/api/6452876/T6452876.java +++ b/test/langtools/tools/javac/api/6452876/T6452876.java @@ -25,7 +25,7 @@ * @test * @bug 6452876 * @summary JSR 199: DiagnosticCollector.report(null) should throw NPE - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6468404/T6468404.java b/test/langtools/tools/javac/api/6468404/T6468404.java index 14580a51be4..c06e37e84b8 100644 --- a/test/langtools/tools/javac/api/6468404/T6468404.java +++ b/test/langtools/tools/javac/api/6468404/T6468404.java @@ -26,7 +26,7 @@ * @bug 6468404 * @summary ExecutableElement.getParameters() uses raw type for class loaded from -g bytecode * @author jesse.glick@... - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/api/6471599/Main.java b/test/langtools/tools/javac/api/6471599/Main.java index 735cebb4bee..fa66ecc51d3 100644 --- a/test/langtools/tools/javac/api/6471599/Main.java +++ b/test/langtools/tools/javac/api/6471599/Main.java @@ -25,7 +25,7 @@ * @test * @bug 6471599 * @summary Type of rhs cannot be obtained when assigning to erroneous symbol - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler/com.sun.tools.javac.util * @compile Main.java * @run main Main diff --git a/test/langtools/tools/javac/api/Sibling.java b/test/langtools/tools/javac/api/Sibling.java index b19ba4be7b9..d70548caa63 100644 --- a/test/langtools/tools/javac/api/Sibling.java +++ b/test/langtools/tools/javac/api/Sibling.java @@ -25,7 +25,7 @@ * @test * @bug 6399602 * @summary Verify that files are created relative to sibling - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/api/T6257235.java b/test/langtools/tools/javac/api/T6257235.java index 2ced708aa5f..095d2e83d3b 100644 --- a/test/langtools/tools/javac/api/T6257235.java +++ b/test/langtools/tools/javac/api/T6257235.java @@ -25,7 +25,7 @@ * @test * @bug 6257235 * @summary setOption() and setExtendedOption() of JavacTool throws NullPointerException for undefined options - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/api/T6258271.java b/test/langtools/tools/javac/api/T6258271.java index 1ceb4becfd6..2092f5825a0 100644 --- a/test/langtools/tools/javac/api/T6258271.java +++ b/test/langtools/tools/javac/api/T6258271.java @@ -25,7 +25,7 @@ * @test * @bug 6258271 * @summary DiagnosticMessage exposes internal name __input - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/api/T6265137.java b/test/langtools/tools/javac/api/T6265137.java index c004833963d..2a8a1fcb9ad 100644 --- a/test/langtools/tools/javac/api/T6265137.java +++ b/test/langtools/tools/javac/api/T6265137.java @@ -25,7 +25,7 @@ * @test * @bug 6265137 * @summary setOption() and setExtendedOption() of JavacTool will throw exception for some defined options - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/api/T6306137.java b/test/langtools/tools/javac/api/T6306137.java index 2a8a788230a..fe443950e52 100644 --- a/test/langtools/tools/javac/api/T6306137.java +++ b/test/langtools/tools/javac/api/T6306137.java @@ -29,7 +29,7 @@ * jdk.compiler * @compile -encoding utf-8 T6306137.java * @run main T6306137 - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé */ import java.io.File; diff --git a/test/langtools/tools/javac/api/T6358786.java b/test/langtools/tools/javac/api/T6358786.java index c3e91ccb617..f8ffb829b2a 100644 --- a/test/langtools/tools/javac/api/T6358786.java +++ b/test/langtools/tools/javac/api/T6358786.java @@ -25,7 +25,7 @@ * @test * @bug 6358786 * @summary Doccomments are not returned from Tree API - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler/com.sun.tools.javac.api * @run main T6358786 T6358786.java */ diff --git a/test/langtools/tools/javac/api/T6397104.java b/test/langtools/tools/javac/api/T6397104.java index 74b840fa6b7..7d63c322371 100644 --- a/test/langtools/tools/javac/api/T6397104.java +++ b/test/langtools/tools/javac/api/T6397104.java @@ -25,7 +25,7 @@ * @test * @bug 6397104 * @summary JSR 199: JavaFileManager.getFileForOutput should have sibling argument - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/api/T6400205.java b/test/langtools/tools/javac/api/T6400205.java index 075ad74cc7c..a942e7c6624 100644 --- a/test/langtools/tools/javac/api/T6400205.java +++ b/test/langtools/tools/javac/api/T6400205.java @@ -25,7 +25,7 @@ * @test * @bug 6400205 * @summary getClassLoader(location) returns null if getLocation(location) returns null - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/api/T6400207.java b/test/langtools/tools/javac/api/T6400207.java index 7747553d21e..47bf297ce72 100644 --- a/test/langtools/tools/javac/api/T6400207.java +++ b/test/langtools/tools/javac/api/T6400207.java @@ -25,7 +25,7 @@ * @test * @bug 6400207 * @summary JSR 199: JavaFileManager.list and unset location - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/api/T6407011.java b/test/langtools/tools/javac/api/T6407011.java index d4420cc1623..9991efd1a5d 100644 --- a/test/langtools/tools/javac/api/T6407011.java +++ b/test/langtools/tools/javac/api/T6407011.java @@ -25,7 +25,7 @@ * @test * @bug 6407011 6407066 * @summary javac crashes in b78 with NPE in JavacFileManager:293 - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/api/TestEvalExpression.java b/test/langtools/tools/javac/api/TestEvalExpression.java index e627191d868..41e61548d55 100644 --- a/test/langtools/tools/javac/api/TestEvalExpression.java +++ b/test/langtools/tools/javac/api/TestEvalExpression.java @@ -25,7 +25,7 @@ * @test * @bug 4164450 * @summary JSR 199: Standard interface for Java compilers - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * java.desktop * jdk.compiler diff --git a/test/langtools/tools/javac/api/TestGetSourceVersions.java b/test/langtools/tools/javac/api/TestGetSourceVersions.java index caac5eb2a3d..4df60355aad 100644 --- a/test/langtools/tools/javac/api/TestGetSourceVersions.java +++ b/test/langtools/tools/javac/api/TestGetSourceVersions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,9 +24,9 @@ /* * @test * @bug 6395981 6458819 7025784 8028543 8028544 8193291 8193292 8193292 8205393 8245585 8245585 8245585 8286034 - * 8296150 8306585 8319414 8330183 8342982 + * 8296150 8306585 8319414 8330183 8342982 8355748 * @summary JavaCompilerTool and Tool must specify version of JLS and JVMS - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler * @run main/fail TestGetSourceVersions @@ -37,7 +37,7 @@ * RELEASE_8 RELEASE_9 RELEASE_10 RELEASE_11 RELEASE_12 * RELEASE_13 RELEASE_14 RELEASE_15 RELEASE_16 RELEASE_17 * RELEASE_18 RELEASE_19 RELEASE_20 RELEASE_21 RELEASE_22 - * RELEASE_23 RELEASE_24 RELEASE_25 + * RELEASE_23 RELEASE_24 RELEASE_25 RELEASE_26 */ import java.util.EnumSet; diff --git a/test/langtools/tools/javac/api/TestGetTree.java b/test/langtools/tools/javac/api/TestGetTree.java index 524ad8a1fe2..545645a3541 100644 --- a/test/langtools/tools/javac/api/TestGetTree.java +++ b/test/langtools/tools/javac/api/TestGetTree.java @@ -25,7 +25,7 @@ * @test * @bug 6344177 6392177 * @summary Can't get tree from a top level class - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler * @compile TestGetTree.java * @compile -processor TestGetTree -proc:only TestGetTree.java diff --git a/test/langtools/tools/javac/api/TestJavacTask.java b/test/langtools/tools/javac/api/TestJavacTask.java index c17f7d05777..2d86a732a41 100644 --- a/test/langtools/tools/javac/api/TestJavacTask.java +++ b/test/langtools/tools/javac/api/TestJavacTask.java @@ -25,7 +25,7 @@ * @test * @bug 4813736 8015073 * @summary Provide a basic test of access to the Java Model from javac, and error messages - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler/com.sun.tools.javac.api * @run main TestJavacTask TestJavacTask.java */ diff --git a/test/langtools/tools/javac/api/TestJavacTaskScanner.java b/test/langtools/tools/javac/api/TestJavacTaskScanner.java index 0d09a81cd70..4f920d96fb0 100644 --- a/test/langtools/tools/javac/api/TestJavacTaskScanner.java +++ b/test/langtools/tools/javac/api/TestJavacTaskScanner.java @@ -25,7 +25,7 @@ * @test * @bug 4813736 8013256 * @summary Additional functionality test of task and JSR 269 - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ./lib * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.code diff --git a/test/langtools/tools/javac/api/TestOperators.java b/test/langtools/tools/javac/api/TestOperators.java index 91d58bb3657..99448e3e389 100644 --- a/test/langtools/tools/javac/api/TestOperators.java +++ b/test/langtools/tools/javac/api/TestOperators.java @@ -25,7 +25,7 @@ * @test * @bug 6338064 6346249 6340951 6392177 * @summary Tree API: can't determine kind of operator - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../lib * @modules jdk.compiler * @build JavacTestingAbstractProcessor TestOperators diff --git a/test/langtools/tools/javac/api/TestResolveIdent.java b/test/langtools/tools/javac/api/TestResolveIdent.java index c72f652ce3e..d5f5a6bb93e 100644 --- a/test/langtools/tools/javac/api/TestResolveIdent.java +++ b/test/langtools/tools/javac/api/TestResolveIdent.java @@ -25,7 +25,7 @@ * @test * @bug 6374357 6308351 * @summary PackageElement.getEnclosedElements() throws ClassReader$BadClassFileException - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.code * jdk.compiler/com.sun.tools.javac.comp diff --git a/test/langtools/tools/javac/api/guide/Test.java b/test/langtools/tools/javac/api/guide/Test.java index 64b2a304016..5bf881a590c 100644 --- a/test/langtools/tools/javac/api/guide/Test.java +++ b/test/langtools/tools/javac/api/guide/Test.java @@ -25,7 +25,7 @@ * @test * @bug 6427274 6347778 6469079 * @summary Various bugs fixed while writing Compiler API Guide - * @author Peter von der Ah\u0081 + * @author Peter von der Ahé * @library ../lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/attr/AttrRecoveryTest.java b/test/langtools/tools/javac/attr/AttrRecoveryTest.java index f5589a8093f..d4455a656ce 100644 --- a/test/langtools/tools/javac/attr/AttrRecoveryTest.java +++ b/test/langtools/tools/javac/attr/AttrRecoveryTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /** * @test - * @bug 8273039 + * @bug 8273039 8344706 * @summary Verify error recovery in Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -84,7 +84,7 @@ public class Test { """, "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:51: compiler.err.class.method.or.field.expected", "Test.java:2:26: compiler.err.unexpected.type: kindname.value, kindname.class", "3 errors"), new TestCase("b", @@ -95,7 +95,7 @@ public class Test { """, null, "Test.java:2:30: compiler.err.dot.class.expected", - "Test.java:2:39: compiler.err.expected4: class, interface, enum, record", + "Test.java:2:39: compiler.err.class.method.or.field.expected", "Test.java:2:26: compiler.err.unexpected.type: kindname.value, kindname.class", "3 errors") }; diff --git a/test/langtools/tools/javac/boxing/T5082929.java b/test/langtools/tools/javac/boxing/T5082929.java index 07ea7a37776..0a4be48a89e 100644 --- a/test/langtools/tools/javac/boxing/T5082929.java +++ b/test/langtools/tools/javac/boxing/T5082929.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5082929 * @summary Comparing Float and Integer - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T5082929.out -XDrawDiagnostics T5082929.java */ diff --git a/test/langtools/tools/javac/boxing/T6348760.java b/test/langtools/tools/javac/boxing/T6348760.java index 98b580fdb90..010bcbfd324 100644 --- a/test/langtools/tools/javac/boxing/T6348760.java +++ b/test/langtools/tools/javac/boxing/T6348760.java @@ -25,7 +25,7 @@ * @test * @bug 6348760 * @summary crash: java.lang.AssertionError at com.sun.tools.javac.comp.Lower.abstractLval(Lower.java:1853) - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @run main/othervm T6348760 */ diff --git a/test/langtools/tools/javac/cast/5043020/T5043020.java b/test/langtools/tools/javac/cast/5043020/T5043020.java index da561cef9f8..13152c57a64 100644 --- a/test/langtools/tools/javac/cast/5043020/T5043020.java +++ b/test/langtools/tools/javac/cast/5043020/T5043020.java @@ -25,7 +25,7 @@ * @test * @bug 5043020 * @summary Spurious unchecked cast warning - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile -Werror -Xlint:unchecked T5043020.java */ diff --git a/test/langtools/tools/javac/cast/6302214/T6302214a.java b/test/langtools/tools/javac/cast/6302214/T6302214a.java index 605894f6bb0..eeb8735e4a4 100644 --- a/test/langtools/tools/javac/cast/6302214/T6302214a.java +++ b/test/langtools/tools/javac/cast/6302214/T6302214a.java @@ -25,7 +25,7 @@ * @test * @bug 6302214 * @summary erroneus "inconvertible types" error - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile -Xlint:unchecked -Werror T6302214a.java */ diff --git a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java index c12ff311bdb..6afa7ad9e30 100644 --- a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java +++ b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @bug 7157626 8001112 8188870 8173382 8193290 8205619 8245586 8257453 8306586 8330184 - * 8342983 + * 8342983 8355751 * @summary Test major version for all legal combinations for -source and -target * @author sgoel * @@ -61,6 +61,7 @@ private static enum Version { TWENTY_THREE("23", 67), TWENTY_FOUR("24", 68), TWENTY_FIVE("25", 69), + TWENTY_SIX("26", 70), ; // Reduce code churn when appending new constants private Version(String release, int classFileVer) { diff --git a/test/langtools/tools/javac/diags/CheckResourceKeys.java b/test/langtools/tools/javac/diags/CheckResourceKeys.java index 9f6f37dc23d..1675d99275e 100644 --- a/test/langtools/tools/javac/diags/CheckResourceKeys.java +++ b/test/langtools/tools/javac/diags/CheckResourceKeys.java @@ -32,6 +32,7 @@ import java.io.*; import java.util.*; import java.util.regex.*; +import java.util.stream.Stream; import javax.tools.*; import java.lang.classfile.*; import java.lang.classfile.constantpool.*; @@ -175,14 +176,7 @@ void findDeadKeys(Set codeStrings, Set resourceKeys) { //check lint description keys: if (s.startsWith("opt.Xlint.desc.")) { String option = s.substring(15); - boolean found = false; - - for (LintCategory lc : LintCategory.values()) { - if (option.equals(lc.option)) - found = true; - } - - if (found) + if (LintCategory.options().contains(option)) continue; } diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index 39bcec33654..b29f20e5ebb 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -120,6 +120,7 @@ compiler.warn.illegal.char.for.encoding compiler.warn.incubating.modules # requires adjusted classfile compiler.warn.invalid.archive.file compiler.warn.invalid.utf8.in.classfile # bad class file +compiler.warn.is.preview # difficult to produce reliably despite future changes to java.base compiler.warn.is.preview.reflective # difficult to produce reliably despite future changes to java.base compiler.warn.output.file.clash # this warning is not generated on Linux compiler.warn.override.bridge @@ -144,8 +145,6 @@ compiler.note.multiple.elements # needs user code compiler.err.preview.feature.disabled.classfile # preview feature support: needs compilation against classfile compiler.warn.preview.feature.use.classfile # preview feature support: needs compilation against classfile compiler.note.preview.plural.additional # preview feature support: diag test causes intermittent failures (see JDK-8201498) -compiler.misc.bad.intersection.target.for.functional.expr # currently not generated, should be removed? -compiler.misc.not.an.intf.component compiler.warn.declared.using.preview # after making sealed classes a final feature there is no other # preview feature but we should keep this key for future use just # in case diff --git a/test/langtools/tools/javac/diags/examples/AttemptToSynchronizeOnInstanceOfVbc.java b/test/langtools/tools/javac/diags/examples/AttemptToSynchronizeOnInstanceOfVbc.java index 9d63a2af0a4..e677c4b3b8a 100644 --- a/test/langtools/tools/javac/diags/examples/AttemptToSynchronizeOnInstanceOfVbc.java +++ b/test/langtools/tools/javac/diags/examples/AttemptToSynchronizeOnInstanceOfVbc.java @@ -22,7 +22,7 @@ */ // key: compiler.warn.attempt.to.synchronize.on.instance.of.value.based.class -// options: -Xlint:synchronization +// options: -Xlint:identity class AttemptToSynchronizeOnInstanceOfVbc { void foo(Integer i) { diff --git a/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java b/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java index 55f5d19451d..0d19a9a9a12 100644 --- a/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java +++ b/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,10 +21,7 @@ * questions. */ - // key: compiler.note.preview.filename - // key: compiler.note.preview.recompile // key: compiler.err.cant.assign.initialized.before.ctor.called - // options: --enable-preview -source ${jdk.version} class CantAssignInitializedBeforeCtorCalled { int x = 1; diff --git a/test/langtools/tools/javac/diags/examples/Expected3.java b/test/langtools/tools/javac/diags/examples/Expected3.java index 1a527034ff3..641c8bc0352 100644 --- a/test/langtools/tools/javac/diags/examples/Expected3.java +++ b/test/langtools/tools/javac/diags/examples/Expected3.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ */ // key: compiler.err.expected3 -// options: --release 15 -int Expected3; +public class Expected3 { + public void test(int i {} +} diff --git a/test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java b/test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java index 6bdff09e96f..269e0bda687 100644 --- a/test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java +++ b/test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,8 @@ */ // key: compiler.misc.feature.flexible.constructors - // key: compiler.warn.preview.feature.use - // options: --enable-preview -source ${jdk.version} -Xlint:preview + // key: compiler.err.feature.not.supported.in.source + // options: --release 24 class FeatureFlexibleConstructors { FeatureFlexibleConstructors() { diff --git a/test/langtools/tools/javac/diags/examples/IllegalCharLiteralMultipleSurrogates.java b/test/langtools/tools/javac/diags/examples/IllegalCharLiteralMultipleSurrogates.java new file mode 100644 index 00000000000..5c7f7c41475 --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/IllegalCharLiteralMultipleSurrogates.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.illegal.char.literal.multiple.surrogates + +class IllegalCharLiteralMultipleSurrogates { + char c = '\uD83D\uDE0A'; +} diff --git a/test/langtools/tools/javac/diags/examples/IllegalStartOfStmt.java b/test/langtools/tools/javac/diags/examples/IllegalStartOfStmt.java index 88102faff97..d09af8071c4 100644 --- a/test/langtools/tools/javac/diags/examples/IllegalStartOfStmt.java +++ b/test/langtools/tools/javac/diags/examples/IllegalStartOfStmt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ // key: compiler.err.illegal.start.of.stmt // key: compiler.err.expected4 +// options: --release 24 class IllegalStartOfStmt { void m() { diff --git a/test/langtools/tools/javac/diags/examples/ImplicitClass.java b/test/langtools/tools/javac/diags/examples/ImplicitClass.java index 30285293b18..a206c2f7717 100644 --- a/test/langtools/tools/javac/diags/examples/ImplicitClass.java +++ b/test/langtools/tools/javac/diags/examples/ImplicitClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,8 @@ */ // key: compiler.misc.feature.implicit.classes -// key: compiler.warn.preview.feature.use.plural -// key: compiler.warn.is.preview -// options: -source ${jdk.version} --enable-preview -Xlint:preview +// key: compiler.err.feature.not.supported.in.source.plural +// options: --release 24 public static void main(String... args) { } diff --git a/test/langtools/tools/javac/diags/examples/ImplicitClassBad-Filename.java b/test/langtools/tools/javac/diags/examples/ImplicitClassBad-Filename.java index e3bc3d67783..35c4698df46 100644 --- a/test/langtools/tools/javac/diags/examples/ImplicitClassBad-Filename.java +++ b/test/langtools/tools/javac/diags/examples/ImplicitClassBad-Filename.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,6 @@ */ // key: compiler.err.bad.file.name - // key: compiler.note.preview.filename - // key: compiler.note.preview.recompile - // options: -source ${jdk.version} --enable-preview public static void main(String... args) { } diff --git a/test/langtools/tools/javac/diags/examples/ImplicitClassHasPackage.java b/test/langtools/tools/javac/diags/examples/ImplicitClassHasPackage.java index c90e0f3dfbc..d6493a54c76 100644 --- a/test/langtools/tools/javac/diags/examples/ImplicitClassHasPackage.java +++ b/test/langtools/tools/javac/diags/examples/ImplicitClassHasPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,6 @@ */ // key: compiler.err.implicit.class.should.not.have.package.declaration - // key: compiler.note.preview.filename - // key: compiler.note.preview.recompile - // options: -source ${jdk.version} --enable-preview package implicit.classes; diff --git a/test/langtools/tools/javac/diags/examples/ImplicitClassNoMain.java b/test/langtools/tools/javac/diags/examples/ImplicitClassNoMain.java index 4c82341f5ac..45abf2cb7e1 100644 --- a/test/langtools/tools/javac/diags/examples/ImplicitClassNoMain.java +++ b/test/langtools/tools/javac/diags/examples/ImplicitClassNoMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,6 @@ */ // key: compiler.err.implicit.class.does.not.have.main.method - // key: compiler.note.preview.filename - // key: compiler.note.preview.recompile - // options: -source ${jdk.version} --enable-preview public void ordinaryMethod() { } diff --git a/test/langtools/tools/javac/diags/examples/ImportModule.java b/test/langtools/tools/javac/diags/examples/ImportModule.java index 2a0a39f5fad..f924a59acd4 100644 --- a/test/langtools/tools/javac/diags/examples/ImportModule.java +++ b/test/langtools/tools/javac/diags/examples/ImportModule.java @@ -22,8 +22,8 @@ */ // key: compiler.misc.feature.module.imports - // key: compiler.warn.preview.feature.use.plural - // options: --release ${jdk.version} --enable-preview -Xlint:preview + // key: compiler.err.feature.not.supported.in.source.plural + // options: --release 24 -Xlint:preview import module java.base; diff --git a/test/langtools/tools/javac/diags/examples/ImportModuleDoesNotRead/module-info.java b/test/langtools/tools/javac/diags/examples/ImportModuleDoesNotRead/module-info.java index e8f9c952fbc..8c84bc009da 100644 --- a/test/langtools/tools/javac/diags/examples/ImportModuleDoesNotRead/module-info.java +++ b/test/langtools/tools/javac/diags/examples/ImportModuleDoesNotRead/module-info.java @@ -22,7 +22,5 @@ */ // key: compiler.err.import.module.does.not.read -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --release ${jdk.version} --enable-preview + module m {} diff --git a/test/langtools/tools/javac/diags/examples/ImportModuleDoesNotReadUnnamed.java b/test/langtools/tools/javac/diags/examples/ImportModuleDoesNotReadUnnamed.java index 37ae9673cc8..d25e7593170 100644 --- a/test/langtools/tools/javac/diags/examples/ImportModuleDoesNotReadUnnamed.java +++ b/test/langtools/tools/javac/diags/examples/ImportModuleDoesNotReadUnnamed.java @@ -22,9 +22,7 @@ */ // key: compiler.err.import.module.does.not.read.unnamed -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --release ${jdk.version} --enable-preview --limit-modules java.base +// options: --limit-modules java.base import module java.compiler; diff --git a/test/langtools/tools/javac/diags/examples/ImportModuleNotFound.java b/test/langtools/tools/javac/diags/examples/ImportModuleNotFound.java index 8a12fc0bd03..7e5f98e1a36 100644 --- a/test/langtools/tools/javac/diags/examples/ImportModuleNotFound.java +++ b/test/langtools/tools/javac/diags/examples/ImportModuleNotFound.java @@ -22,9 +22,6 @@ */ // key: compiler.err.import.module.not.found - // key: compiler.note.preview.filename - // key: compiler.note.preview.recompile - // options: --release ${jdk.version} --enable-preview import module unknown; diff --git a/test/langtools/tools/javac/diags/examples/ModifierNotAllowed/module-info.java b/test/langtools/tools/javac/diags/examples/ModifierNotAllowed/module-info.java index 02cb11f5ac2..fd57f81117a 100644 --- a/test/langtools/tools/javac/diags/examples/ModifierNotAllowed/module-info.java +++ b/test/langtools/tools/javac/diags/examples/ModifierNotAllowed/module-info.java @@ -21,8 +21,9 @@ * questions. */ -// key: compiler.err.preview.feature.disabled.plural +// key: compiler.err.feature.not.supported.in.source.plural // key: compiler.misc.feature.java.base.transitive +// options: --release 24 module m { requires transitive java.base; diff --git a/test/langtools/tools/javac/diags/examples/NotAnInterfaceComponent.java b/test/langtools/tools/javac/diags/examples/NotAnInterfaceComponent.java index ae97a70e0f7..9adb4daf5b1 100644 --- a/test/langtools/tools/javac/diags/examples/NotAnInterfaceComponent.java +++ b/test/langtools/tools/javac/diags/examples/NotAnInterfaceComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,9 +21,9 @@ * questions. */ -// key: compiler.misc.not.a.functional.intf.1 +// key: compiler.misc.bad.intersection.target.for.functional.expr +// key: compiler.misc.not.an.intf.component // key: compiler.err.prob.found.req -// key: compiler.misc.incompatible.abstracts class NotAnInterfaceComponent { Object o = (String & Runnable) ()-> { }; diff --git a/test/langtools/tools/javac/diags/examples/PreviewFeatureUse.java b/test/langtools/tools/javac/diags/examples/PreviewFeatureUse.java index 799775cf5f8..455ddddab86 100644 --- a/test/langtools/tools/javac/diags/examples/PreviewFeatureUse.java +++ b/test/langtools/tools/javac/diags/examples/PreviewFeatureUse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,14 +21,15 @@ * questions. */ -//key: compiler.warn.preview.feature.use.plural -//key: compiler.misc.feature.var.syntax.in.implicit.lambda +//key: compiler.warn.preview.feature.use +//key: compiler.misc.feature.flexible.constructors //options: -Xlint:preview -XDforcePreview -source ${jdk.version} --enable-preview import java.util.function.Function; class PreviewFeatureUse { - void test() { - Function f = (var s) -> s; + PreviewFeatureUse() { + System.out.println("early init!"); + super(); } } diff --git a/test/langtools/tools/javac/diags/examples/PreviewFeatureUsePlural.java b/test/langtools/tools/javac/diags/examples/PreviewFeatureUsePlural.java new file mode 100644 index 00000000000..ae6bccecadd --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/PreviewFeatureUsePlural.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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.warn.preview.feature.use.plural +//key: compiler.misc.feature.var.syntax.in.implicit.lambda +//options: -Xlint:preview -XDforcePreview -source ${jdk.version} --enable-preview + +import java.util.function.Function; + +class PreviewFeatureUsePlural { + void test() { + Function f = (var s) -> s; + } +} diff --git a/test/langtools/tools/javac/diags/examples/RequiresIdentity.java b/test/langtools/tools/javac/diags/examples/RequiresIdentity.java new file mode 100644 index 00000000000..005de46ab7c --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/RequiresIdentity.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.warn.attempt.to.use.value.based.where.identity.expected +// options: -Xlint:identity --add-exports java.base/jdk.internal=ALL-UNNAMED + +class RequiresIdentity<@jdk.internal.RequiresIdentity T> { + RequiresIdentity field; // should warn +} diff --git a/test/langtools/tools/javac/diags/examples/ReturnBeforeSuperclassInit.java b/test/langtools/tools/javac/diags/examples/ReturnBeforeSuperclassInit.java index dc883b59b8f..033a8430625 100644 --- a/test/langtools/tools/javac/diags/examples/ReturnBeforeSuperclassInit.java +++ b/test/langtools/tools/javac/diags/examples/ReturnBeforeSuperclassInit.java @@ -22,9 +22,6 @@ */ // key: compiler.err.return.before.superclass.initialized -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} class ReturnBeforeSuperclassInit { ReturnBeforeSuperclassInit(boolean maybe) { diff --git a/test/langtools/tools/javac/diags/examples/SubtypeDoesntImplementSealed.java b/test/langtools/tools/javac/diags/examples/SubtypeDoesntImplementSealed.java new file mode 100644 index 00000000000..223b7dc5ef5 --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/SubtypeDoesntImplementSealed.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// key: compiler.err.invalid.permits.clause +// key: compiler.misc.doesnt.implement.sealed + +sealed interface A3 permits B3 {} +interface B3 {} + diff --git a/test/langtools/tools/javac/enum/6424358/T6424358.java b/test/langtools/tools/javac/enum/6424358/T6424358.java index 9042f65264e..6a5d403ada5 100644 --- a/test/langtools/tools/javac/enum/6424358/T6424358.java +++ b/test/langtools/tools/javac/enum/6424358/T6424358.java @@ -25,7 +25,7 @@ * @test * @bug 6424358 7025809 * @summary Synthesized static enum method values() is final - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library /tools/javac/lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/enum/NoFinal.java b/test/langtools/tools/javac/enum/NoFinal.java index e48008e803f..b6babaf9ac9 100644 --- a/test/langtools/tools/javac/enum/NoFinal.java +++ b/test/langtools/tools/javac/enum/NoFinal.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5097250 5087624 * @summary Finalize methods on enums must be compile time error - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=NoFinal.out -XDrawDiagnostics NoFinal.java */ diff --git a/test/langtools/tools/javac/enum/NoFinal2.java b/test/langtools/tools/javac/enum/NoFinal2.java index 1c69e0c1e51..372cb7bbab2 100644 --- a/test/langtools/tools/javac/enum/NoFinal2.java +++ b/test/langtools/tools/javac/enum/NoFinal2.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5097250 5087624 * @summary Finalize methods on enums must be compile time error - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=NoFinal2.out -XDrawDiagnostics NoFinal2.java */ diff --git a/test/langtools/tools/javac/enum/NoFinal3.java b/test/langtools/tools/javac/enum/NoFinal3.java index 742ad4276f7..114fe3f2304 100644 --- a/test/langtools/tools/javac/enum/NoFinal3.java +++ b/test/langtools/tools/javac/enum/NoFinal3.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5097250 5087624 * @summary Finalize methods on enums must be compile time error - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=NoFinal3.out -XDrawDiagnostics NoFinal3.java */ diff --git a/test/langtools/tools/javac/enum/NoFinal4.java b/test/langtools/tools/javac/enum/NoFinal4.java index ee382d3b78e..35d325eeeae 100644 --- a/test/langtools/tools/javac/enum/NoFinal4.java +++ b/test/langtools/tools/javac/enum/NoFinal4.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5097250 5087624 * @summary Finalize methods on enums must be compile time error - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=NoFinal4.out -XDrawDiagnostics NoFinal4.java */ diff --git a/test/langtools/tools/javac/enum/NoFinal5.java b/test/langtools/tools/javac/enum/NoFinal5.java index 6ec5e7c0fcc..c3f3f99813d 100644 --- a/test/langtools/tools/javac/enum/NoFinal5.java +++ b/test/langtools/tools/javac/enum/NoFinal5.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5097250 5087624 * @summary Finalize methods on enums must be compile time error - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=NoFinal5.out -XDrawDiagnostics NoFinal5.java */ diff --git a/test/langtools/tools/javac/enum/OkFinal.java b/test/langtools/tools/javac/enum/OkFinal.java index 4f6c2d63abe..a37de61ae5c 100644 --- a/test/langtools/tools/javac/enum/OkFinal.java +++ b/test/langtools/tools/javac/enum/OkFinal.java @@ -25,7 +25,7 @@ * @test * @bug 5097250 * @summary Finalize methods on enums must be compile time error - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé */ public enum OkFinal { diff --git a/test/langtools/tools/javac/enum/T5075242.java b/test/langtools/tools/javac/enum/T5075242.java index 33cf45783da..29e90bd39fd 100644 --- a/test/langtools/tools/javac/enum/T5075242.java +++ b/test/langtools/tools/javac/enum/T5075242.java @@ -25,7 +25,7 @@ * @test * @bug 5075242 * @summary Cannot make compound type involving Enums - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * * @compile T5075242.java */ diff --git a/test/langtools/tools/javac/enum/T5081785.java b/test/langtools/tools/javac/enum/T5081785.java index 25d40bf5e4a..d4e08431e97 100644 --- a/test/langtools/tools/javac/enum/T5081785.java +++ b/test/langtools/tools/javac/enum/T5081785.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5081785 * @summary enums should be allowed in non-static contexts - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T5081785.out -XDrawDiagnostics --release 15 T5081785.java * @compile T5081785.java */ diff --git a/test/langtools/tools/javac/enum/forwardRef/T6425594.java b/test/langtools/tools/javac/enum/forwardRef/T6425594.java index e7a5bc177ba..26613735e70 100644 --- a/test/langtools/tools/javac/enum/forwardRef/T6425594.java +++ b/test/langtools/tools/javac/enum/forwardRef/T6425594.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6424491 * @summary javac accepts illegal forward references - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T6425594.out -XDrawDiagnostics -XDuseBeforeDeclarationWarning T6425594.java */ diff --git a/test/langtools/tools/javac/enum/forwardRef/TestEnum1.java b/test/langtools/tools/javac/enum/forwardRef/TestEnum1.java index 737ed620eff..658ea56dbc7 100644 --- a/test/langtools/tools/javac/enum/forwardRef/TestEnum1.java +++ b/test/langtools/tools/javac/enum/forwardRef/TestEnum1.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6209839 * @summary Illegal forward reference to enum constants allowed by javac - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=TestEnum1.out -XDrawDiagnostics TestEnum1.java */ diff --git a/test/langtools/tools/javac/enum/forwardRef/TestEnum2.java b/test/langtools/tools/javac/enum/forwardRef/TestEnum2.java index cae8d1e8286..16b5ef9e57f 100644 --- a/test/langtools/tools/javac/enum/forwardRef/TestEnum2.java +++ b/test/langtools/tools/javac/enum/forwardRef/TestEnum2.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6209839 * @summary Illegal forward reference to enum constants allowed by javac - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=TestEnum2.out -XDrawDiagnostics TestEnum2.java */ diff --git a/test/langtools/tools/javac/enum/forwardRef/TestEnum3.java b/test/langtools/tools/javac/enum/forwardRef/TestEnum3.java index 2e22fd5552b..497d4644d40 100644 --- a/test/langtools/tools/javac/enum/forwardRef/TestEnum3.java +++ b/test/langtools/tools/javac/enum/forwardRef/TestEnum3.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6209839 * @summary Illegal forward reference to enum constants allowed by javac - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=TestEnum3.out -XDrawDiagnostics TestEnum3.java */ diff --git a/test/langtools/tools/javac/enum/forwardRef/TestEnum4.java b/test/langtools/tools/javac/enum/forwardRef/TestEnum4.java index 5b863302db0..6acfc3ead5f 100644 --- a/test/langtools/tools/javac/enum/forwardRef/TestEnum4.java +++ b/test/langtools/tools/javac/enum/forwardRef/TestEnum4.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6209839 * @summary Illegal forward reference to enum constants allowed by javac - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=TestEnum4.out -XDrawDiagnostics TestEnum4.java */ diff --git a/test/langtools/tools/javac/enum/forwardRef/TestEnum5.java b/test/langtools/tools/javac/enum/forwardRef/TestEnum5.java index 36928c1ef5f..35ae7244daa 100644 --- a/test/langtools/tools/javac/enum/forwardRef/TestEnum5.java +++ b/test/langtools/tools/javac/enum/forwardRef/TestEnum5.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6209839 * @summary Illegal forward reference to enum constants allowed by javac - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=TestEnum5.out -XDrawDiagnostics TestEnum5.java */ diff --git a/test/langtools/tools/javac/enum/forwardRef/TestEnum6.java b/test/langtools/tools/javac/enum/forwardRef/TestEnum6.java index ccf003d1694..305a38559fd 100644 --- a/test/langtools/tools/javac/enum/forwardRef/TestEnum6.java +++ b/test/langtools/tools/javac/enum/forwardRef/TestEnum6.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6424491 * @summary Cannot initialise nested enums - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=TestEnum6.out -XDrawDiagnostics TestEnum6.java */ diff --git a/test/langtools/tools/javac/flow/LVTHarness.java b/test/langtools/tools/javac/flow/LVTHarness.java index 7afe90c1991..996b611d304 100644 --- a/test/langtools/tools/javac/flow/LVTHarness.java +++ b/test/langtools/tools/javac/flow/LVTHarness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,6 +157,7 @@ void checkMethod(MethodModel method, AliveRanges ranges) { if (i < infoFromRanges.size()) { error(infoFromLVT, infoFromRanges, method.methodName().stringValue()); + System.err.println(method.toDebugString()); } } diff --git a/test/langtools/tools/javac/generics/5086027/T5086027.java b/test/langtools/tools/javac/generics/5086027/T5086027.java index 631550ad7a1..4d6902890be 100644 --- a/test/langtools/tools/javac/generics/5086027/T5086027.java +++ b/test/langtools/tools/javac/generics/5086027/T5086027.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5086027 * @summary Inner class of generic class cannot extend Throwable - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T5086027.out -XDrawDiagnostics T5086027.java */ diff --git a/test/langtools/tools/javac/generics/5086027/T5086027pos.java b/test/langtools/tools/javac/generics/5086027/T5086027pos.java index 28e3d482b3d..e1b00372580 100644 --- a/test/langtools/tools/javac/generics/5086027/T5086027pos.java +++ b/test/langtools/tools/javac/generics/5086027/T5086027pos.java @@ -25,7 +25,7 @@ * @test * @bug 5086027 * @summary Inner class of generic class cannot extend Throwable - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T5086027pos.java */ diff --git a/test/langtools/tools/javac/generics/6192945/Method.java b/test/langtools/tools/javac/generics/6192945/Method.java index 9d81bfd2c92..0d3698ad75d 100644 --- a/test/langtools/tools/javac/generics/6192945/Method.java +++ b/test/langtools/tools/javac/generics/6192945/Method.java @@ -25,7 +25,7 @@ * @test * @bug 6192945 * @summary Declaration order of interdependent generic types should not matter - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile Method.java */ diff --git a/test/langtools/tools/javac/generics/6207386/Test.java b/test/langtools/tools/javac/generics/6207386/Test.java index 7dcebc7511c..7725abb6ceb 100644 --- a/test/langtools/tools/javac/generics/6207386/Test.java +++ b/test/langtools/tools/javac/generics/6207386/Test.java @@ -25,7 +25,7 @@ * @test * @bug 6207386 * @summary Undecidable type system leads to crash - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile Test.java */ diff --git a/test/langtools/tools/javac/generics/6227936/T6227936.java b/test/langtools/tools/javac/generics/6227936/T6227936.java index 2e0f0b7dc81..8a9b32261a5 100644 --- a/test/langtools/tools/javac/generics/6227936/T6227936.java +++ b/test/langtools/tools/javac/generics/6227936/T6227936.java @@ -25,7 +25,7 @@ * @test * @bug 6227936 * @summary Wrong type of inherited method using specialized type parameter - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6227936.java */ diff --git a/test/langtools/tools/javac/generics/6245699/T6245699c.java b/test/langtools/tools/javac/generics/6245699/T6245699c.java index fc5f2299587..5105684a7c2 100644 --- a/test/langtools/tools/javac/generics/6245699/T6245699c.java +++ b/test/langtools/tools/javac/generics/6245699/T6245699c.java @@ -25,7 +25,7 @@ * @test * @bug 6245699 * @summary Missing bridge for final method (gives AbstractMethodError at runtime) - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé */ public class T6245699c { diff --git a/test/langtools/tools/javac/generics/6292765/T6292765.java b/test/langtools/tools/javac/generics/6292765/T6292765.java index 874ff4d02ea..c58127f15f1 100644 --- a/test/langtools/tools/javac/generics/6292765/T6292765.java +++ b/test/langtools/tools/javac/generics/6292765/T6292765.java @@ -25,7 +25,7 @@ * @test * @bug 6292765 * @summary NPE at Check.checkCompatibleConcretes - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6292765.java */ diff --git a/test/langtools/tools/javac/generics/6332204/T6332204.java b/test/langtools/tools/javac/generics/6332204/T6332204.java index 8e70d592dda..6c61304cc6d 100644 --- a/test/langtools/tools/javac/generics/6332204/T6332204.java +++ b/test/langtools/tools/javac/generics/6332204/T6332204.java @@ -25,7 +25,7 @@ * @test * @bug 6332204 * @summary com.sun.tools.javac.code.Types.lub() throws NPE - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6332204.java */ diff --git a/test/langtools/tools/javac/generics/6413682/TestPos.java b/test/langtools/tools/javac/generics/6413682/TestPos.java index 4df4d458cfd..1da09adc591 100644 --- a/test/langtools/tools/javac/generics/6413682/TestPos.java +++ b/test/langtools/tools/javac/generics/6413682/TestPos.java @@ -25,7 +25,7 @@ * @test * @bug 6413682 * @summary Compiler confused about implicit type args and arrays - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler */ diff --git a/test/langtools/tools/javac/generics/T6391995.java b/test/langtools/tools/javac/generics/T6391995.java index 6ff82f30cab..ef01a6405b2 100644 --- a/test/langtools/tools/javac/generics/T6391995.java +++ b/test/langtools/tools/javac/generics/T6391995.java @@ -25,7 +25,7 @@ * @test * @bug 6391995 * @summary removal of "rvalue conversion" causes problems - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6391995.java */ diff --git a/test/langtools/tools/javac/generics/inference/5073060/Neg.java b/test/langtools/tools/javac/generics/inference/5073060/Neg.java index 1658e29e23a..6a42c06239b 100644 --- a/test/langtools/tools/javac/generics/inference/5073060/Neg.java +++ b/test/langtools/tools/javac/generics/inference/5073060/Neg.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5073060 * @summary Package private members not found for intersection types - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=Neg.out -XDrawDiagnostics NegHelper.java Neg.java */ diff --git a/test/langtools/tools/javac/generics/inference/5073060/T5073060a.java b/test/langtools/tools/javac/generics/inference/5073060/T5073060a.java index 270daf1bfb7..be3364099b9 100644 --- a/test/langtools/tools/javac/generics/inference/5073060/T5073060a.java +++ b/test/langtools/tools/javac/generics/inference/5073060/T5073060a.java @@ -25,7 +25,7 @@ * @test * @bug 5073060 * @summary Package private members not found for intersection types - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé */ public class T5073060a { diff --git a/test/langtools/tools/javac/generics/inference/5081782/Neg.java b/test/langtools/tools/javac/generics/inference/5081782/Neg.java index eedee463f23..1ef3d22a5cc 100644 --- a/test/langtools/tools/javac/generics/inference/5081782/Neg.java +++ b/test/langtools/tools/javac/generics/inference/5081782/Neg.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5081782 * @summary type arguments to non-generic methods - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=Neg.out -XDrawDiagnostics Neg.java */ diff --git a/test/langtools/tools/javac/generics/inference/5081782/Pos.java b/test/langtools/tools/javac/generics/inference/5081782/Pos.java index 577f463c04c..5a0b3eb88ee 100644 --- a/test/langtools/tools/javac/generics/inference/5081782/Pos.java +++ b/test/langtools/tools/javac/generics/inference/5081782/Pos.java @@ -25,7 +25,7 @@ * @test * @bug 5081782 * @summary type arguments to non-generic methods - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile Pos.java */ diff --git a/test/langtools/tools/javac/generics/inference/6215213/T6215213.java b/test/langtools/tools/javac/generics/inference/6215213/T6215213.java index 6736f92ce7a..98dd5ff1e3f 100644 --- a/test/langtools/tools/javac/generics/inference/6215213/T6215213.java +++ b/test/langtools/tools/javac/generics/inference/6215213/T6215213.java @@ -25,7 +25,7 @@ * @test * @bug 6215213 * @summary Compiler JDK1.5 crashes with uses of generics - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6215213.java */ diff --git a/test/langtools/tools/javac/generics/inference/6278587/T6278587.java b/test/langtools/tools/javac/generics/inference/6278587/T6278587.java index 403ca2d63e6..76d7bdb4e8b 100644 --- a/test/langtools/tools/javac/generics/inference/6278587/T6278587.java +++ b/test/langtools/tools/javac/generics/inference/6278587/T6278587.java @@ -25,7 +25,7 @@ * @test * @bug 6278587 * @summary Inference broken for subtypes of subtypes of F-bounded types - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6278587.java */ diff --git a/test/langtools/tools/javac/generics/inference/6278587/T6278587Neg.java b/test/langtools/tools/javac/generics/inference/6278587/T6278587Neg.java index 3963c641fa3..02dd1fe25ee 100644 --- a/test/langtools/tools/javac/generics/inference/6278587/T6278587Neg.java +++ b/test/langtools/tools/javac/generics/inference/6278587/T6278587Neg.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6278587 8007464 * @summary Inference broken for subtypes of subtypes of F-bounded types - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6278587Neg.java */ diff --git a/test/langtools/tools/javac/generics/inference/6302954/T6456971.java b/test/langtools/tools/javac/generics/inference/6302954/T6456971.java index d3e195463ae..03ba90132ae 100644 --- a/test/langtools/tools/javac/generics/inference/6302954/T6456971.java +++ b/test/langtools/tools/javac/generics/inference/6302954/T6456971.java @@ -25,7 +25,7 @@ * @test * @bug 6456971 * @summary Varargs and inference problem - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6456971.java */ diff --git a/test/langtools/tools/javac/generics/inference/6359106/T6359106.java b/test/langtools/tools/javac/generics/inference/6359106/T6359106.java index 73c07765311..478cbf465c2 100644 --- a/test/langtools/tools/javac/generics/inference/6359106/T6359106.java +++ b/test/langtools/tools/javac/generics/inference/6359106/T6359106.java @@ -25,7 +25,7 @@ * @test * @bug 6359106 * @summary Valid generics code does not compile - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile Orig.java T6359106.java */ diff --git a/test/langtools/tools/javac/generics/rawOverride/AttributeSet.java b/test/langtools/tools/javac/generics/rawOverride/AttributeSet.java index 664dca0c805..c09dbdb29ff 100644 --- a/test/langtools/tools/javac/generics/rawOverride/AttributeSet.java +++ b/test/langtools/tools/javac/generics/rawOverride/AttributeSet.java @@ -26,7 +26,7 @@ * @bug 5073079 * @summary Allow unchecked override of generified methods in * parameterless classes - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * * @compile -Xlint:unchecked -Werror AttributeSet.java */ diff --git a/test/langtools/tools/javac/generics/rawOverride/Fail1.java b/test/langtools/tools/javac/generics/rawOverride/Fail1.java index 1b73b9742fb..e93402d830a 100644 --- a/test/langtools/tools/javac/generics/rawOverride/Fail1.java +++ b/test/langtools/tools/javac/generics/rawOverride/Fail1.java @@ -3,7 +3,7 @@ * @bug 5073079 * @summary Allow unchecked override of generified methods in * parameterless classes - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * * @compile/fail/ref=Fail1.out -XDrawDiagnostics Fail1.java */ diff --git a/test/langtools/tools/javac/generics/rawOverride/T6178365.java b/test/langtools/tools/javac/generics/rawOverride/T6178365.java index dc3afc800ef..9a7a97c76aa 100644 --- a/test/langtools/tools/javac/generics/rawOverride/T6178365.java +++ b/test/langtools/tools/javac/generics/rawOverride/T6178365.java @@ -25,7 +25,7 @@ * @test * @bug 6178365 * @summary REGRESSION: Compile Error - Abstract error in LoginModule - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @run main T6178365 */ diff --git a/test/langtools/tools/javac/generics/rawOverride/Warn1.java b/test/langtools/tools/javac/generics/rawOverride/Warn1.java index e4fa90a8931..134a43ce460 100644 --- a/test/langtools/tools/javac/generics/rawOverride/Warn1.java +++ b/test/langtools/tools/javac/generics/rawOverride/Warn1.java @@ -3,7 +3,7 @@ * @bug 5073079 * @summary Allow unchecked override of generified methods in * parameterless classes - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * * @compile Warn1.java * @compile/fail/ref=Warn1.out -XDrawDiagnostics -Xlint:unchecked -Werror Warn1.java diff --git a/test/langtools/tools/javac/generics/rawOverride/Warn2.java b/test/langtools/tools/javac/generics/rawOverride/Warn2.java index e4bc3aff0d6..252dcaa32eb 100644 --- a/test/langtools/tools/javac/generics/rawOverride/Warn2.java +++ b/test/langtools/tools/javac/generics/rawOverride/Warn2.java @@ -3,7 +3,7 @@ * @bug 5073079 * @summary Allow unchecked override of generified methods in * parameterless classes - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * * @compile Warn2.java * @compile/fail/ref=Warn2.out -XDrawDiagnostics -Xlint:unchecked -Werror Warn2.java diff --git a/test/langtools/tools/javac/generics/typevars/4856983/T4856983.java b/test/langtools/tools/javac/generics/typevars/4856983/T4856983.java index c90a2aacf5a..ceac89e0397 100644 --- a/test/langtools/tools/javac/generics/typevars/4856983/T4856983.java +++ b/test/langtools/tools/javac/generics/typevars/4856983/T4856983.java @@ -25,7 +25,7 @@ * @test * @bug 4856983 * @summary (crash) mutually f-bounded type vars with multiple bounds may crash javac - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * * @compile T4856983.java */ diff --git a/test/langtools/tools/javac/generics/typevars/4856983/T4856983a.java b/test/langtools/tools/javac/generics/typevars/4856983/T4856983a.java index ff722efe5c7..52a2c02ba81 100644 --- a/test/langtools/tools/javac/generics/typevars/4856983/T4856983a.java +++ b/test/langtools/tools/javac/generics/typevars/4856983/T4856983a.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 4856983 * @summary (crash) mutually f-bounded type vars with multiple bounds may crash javac - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T4856983a.out -XDrawDiagnostics T4856983a.java */ diff --git a/test/langtools/tools/javac/generics/typevars/4856983/T4856983b.java b/test/langtools/tools/javac/generics/typevars/4856983/T4856983b.java index ba013aeaf6d..beef1776105 100644 --- a/test/langtools/tools/javac/generics/typevars/4856983/T4856983b.java +++ b/test/langtools/tools/javac/generics/typevars/4856983/T4856983b.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 4856983 * @summary (crash) mutually f-bounded type vars with multiple bounds may crash javac - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T4856983b.out -XDrawDiagnostics T4856983b.java */ diff --git a/test/langtools/tools/javac/generics/typevars/5060485/Compatibility.java b/test/langtools/tools/javac/generics/typevars/5060485/Compatibility.java index 6564a37b367..228d7245eef 100644 --- a/test/langtools/tools/javac/generics/typevars/5060485/Compatibility.java +++ b/test/langtools/tools/javac/generics/typevars/5060485/Compatibility.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5060485 * @summary The scope of a class type parameter is too wide - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=Compatibility.out -XDrawDiagnostics Compatibility.java */ diff --git a/test/langtools/tools/javac/generics/typevars/5060485/Method.java b/test/langtools/tools/javac/generics/typevars/5060485/Method.java index fc3121e1559..2603727b411 100644 --- a/test/langtools/tools/javac/generics/typevars/5060485/Method.java +++ b/test/langtools/tools/javac/generics/typevars/5060485/Method.java @@ -25,7 +25,7 @@ * @test * @bug 5060485 * @summary The scope of a class type parameter is too wide - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile Method.java */ diff --git a/test/langtools/tools/javac/generics/typevars/5060485/Neg1.java b/test/langtools/tools/javac/generics/typevars/5060485/Neg1.java index 380ef7501da..58a56c602ac 100644 --- a/test/langtools/tools/javac/generics/typevars/5060485/Neg1.java +++ b/test/langtools/tools/javac/generics/typevars/5060485/Neg1.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5060485 * @summary The scope of a class type parameter is too wide - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=Neg1.out -XDrawDiagnostics Neg1.java */ diff --git a/test/langtools/tools/javac/generics/typevars/5060485/Neg2.java b/test/langtools/tools/javac/generics/typevars/5060485/Neg2.java index c96080d1777..0ea9c2c7ef8 100644 --- a/test/langtools/tools/javac/generics/typevars/5060485/Neg2.java +++ b/test/langtools/tools/javac/generics/typevars/5060485/Neg2.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5060485 * @summary The scope of a class type parameter is too wide - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=Neg2.out -XDrawDiagnostics Neg2.java */ diff --git a/test/langtools/tools/javac/generics/typevars/5060485/Pos.java b/test/langtools/tools/javac/generics/typevars/5060485/Pos.java index 74017c2ef16..29cc91f0c04 100644 --- a/test/langtools/tools/javac/generics/typevars/5060485/Pos.java +++ b/test/langtools/tools/javac/generics/typevars/5060485/Pos.java @@ -25,7 +25,7 @@ * @test * @bug 5060485 * @summary The scope of a class type parameter is too wide - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile Pos.java */ diff --git a/test/langtools/tools/javac/generics/typevars/6182630/T6182630.java b/test/langtools/tools/javac/generics/typevars/6182630/T6182630.java index a7a9720467c..e2e51610d4e 100644 --- a/test/langtools/tools/javac/generics/typevars/6182630/T6182630.java +++ b/test/langtools/tools/javac/generics/typevars/6182630/T6182630.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6182630 * @summary Method with parameter bound to raw type avoids unchecked warning - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/ref=T6182630.out -XDrawDiagnostics -Xlint:unchecked T6182630.java */ diff --git a/test/langtools/tools/javac/generics/typevars/6486430/T6486430.java b/test/langtools/tools/javac/generics/typevars/6486430/T6486430.java index 5de2ae54da0..dfa0ce443a9 100644 --- a/test/langtools/tools/javac/generics/typevars/6486430/T6486430.java +++ b/test/langtools/tools/javac/generics/typevars/6486430/T6486430.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6486430 * @summary Compiler fails to reject access to static member in parameterized type - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T6486430.out -XDrawDiagnostics T6486430.java */ diff --git a/test/langtools/tools/javac/generics/typevars/6486430/T6486430a.java b/test/langtools/tools/javac/generics/typevars/6486430/T6486430a.java index 35056db6daa..6b6941055a0 100644 --- a/test/langtools/tools/javac/generics/typevars/6486430/T6486430a.java +++ b/test/langtools/tools/javac/generics/typevars/6486430/T6486430a.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6486430 * @summary Compiler fails to reject access to static member in parameterized type - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T6486430a.out -XDrawDiagnostics T6486430a.java */ diff --git a/test/langtools/tools/javac/generics/wildcards/6330931/T6330931.java b/test/langtools/tools/javac/generics/wildcards/6330931/T6330931.java index 550efc2d54a..db551e72b1e 100644 --- a/test/langtools/tools/javac/generics/wildcards/6330931/T6330931.java +++ b/test/langtools/tools/javac/generics/wildcards/6330931/T6330931.java @@ -25,7 +25,7 @@ * @test * @bug 6330931 * @summary Super wildcard has incorrect upper bound - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6330931.java */ diff --git a/test/langtools/tools/javac/generics/wildcards/6437894/T6437894.java b/test/langtools/tools/javac/generics/wildcards/6437894/T6437894.java index e380be8832a..5e1233442c9 100644 --- a/test/langtools/tools/javac/generics/wildcards/6437894/T6437894.java +++ b/test/langtools/tools/javac/generics/wildcards/6437894/T6437894.java @@ -3,7 +3,7 @@ * @bug 6437894 * @summary Javac throws a NullPointerException * @author jan.lahoda@... - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile A.java B.java * @clean a.A * @compile/fail/ref=T6437894.out -XDrawDiagnostics T6437894.java diff --git a/test/langtools/tools/javac/generics/wildcards/T5097548.java b/test/langtools/tools/javac/generics/wildcards/T5097548.java index b8b074fcfd2..46459ffa675 100644 --- a/test/langtools/tools/javac/generics/wildcards/T5097548.java +++ b/test/langtools/tools/javac/generics/wildcards/T5097548.java @@ -25,7 +25,7 @@ * @test * @bug 5097548 * @summary (crash) Stack overflow in capture conversion - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T5097548.java * @run main T5097548 */ diff --git a/test/langtools/tools/javac/generics/wildcards/T5097548b.java b/test/langtools/tools/javac/generics/wildcards/T5097548b.java index d5c1b6586be..2ce974fb2ca 100644 --- a/test/langtools/tools/javac/generics/wildcards/T5097548b.java +++ b/test/langtools/tools/javac/generics/wildcards/T5097548b.java @@ -25,7 +25,7 @@ * @test * @bug 5097548 * @summary Stack overflow in capture conversion - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T5097548b.java */ diff --git a/test/langtools/tools/javac/inference_context_min/SupplementaryInferenceContextTest.java b/test/langtools/tools/javac/inference_context_min/SupplementaryInferenceContextTest.java new file mode 100644 index 00000000000..25605d71c96 --- /dev/null +++ b/test/langtools/tools/javac/inference_context_min/SupplementaryInferenceContextTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8325859 + * @summary potential information loss during type inference + * @modules jdk.compiler/com.sun.tools.javac.util + */ + +import com.sun.tools.javac.util.Assert; + +public class SupplementaryInferenceContextTest { + static String result; + public static void main(String... args) { + runT(() -> supplyNull(Integer.valueOf(1))); + Assert.check(result.equals("class java.lang.Integer")); + } + + static R supplyNull(X... varargs) { + result = varargs.getClass().getComponentType().toString(); + System.err.println("result is =" + result); + return null; + } + + static void runT(Runnable runnable) { runnable.run(); } +} diff --git a/test/langtools/tools/javac/jvm/6397652/T6397652.java b/test/langtools/tools/javac/jvm/6397652/T6397652.java index f134ed08dfa..3b6c78f4ed5 100644 --- a/test/langtools/tools/javac/jvm/6397652/T6397652.java +++ b/test/langtools/tools/javac/jvm/6397652/T6397652.java @@ -26,7 +26,7 @@ * @bug 6397652 * @summary javac compilation failure when imported class with $ sign in the name * @author Yuri Gaevsky - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile com/test/Test.java com/test/Test$Test.java com/test/Test$Test$Test.java * @compile T6397652.java */ diff --git a/test/langtools/tools/javac/lambda/ClassInIntersectionTypeTest.java b/test/langtools/tools/javac/lambda/ClassInIntersectionTypeTest.java new file mode 100644 index 00000000000..a0b2ce60229 --- /dev/null +++ b/test/langtools/tools/javac/lambda/ClassInIntersectionTypeTest.java @@ -0,0 +1,49 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8322810 + * @summary Lambda expressions can implement classes + * @compile/fail/ref=ClassInIntersectionTypeTest.out -XDrawDiagnostics ClassInIntersectionTypeTest.java + */ + +import java.io.Serializable; +import java.lang.annotation.Annotation; + +public class ClassInIntersectionTypeTest { + // test 1 + void m1() { + ClassInIntersectionTypeTest r1 = (ClassInIntersectionTypeTest & Runnable) () -> System.out.println("Hello, World!"); + ClassInIntersectionTypeTest r2 = (ClassInIntersectionTypeTest & Runnable) ClassInIntersectionTypeTest::run1; + } + + static void run1() {} + + // test 2 + static void foo() { + run2(() -> System.out.println("Hello, World!")); + run2(ClassInIntersectionTypeTest::run1); + } + + static void run2(T t) { + t.run(); + } + + static Class myAnnoType() { return null; } + @interface Anno {} + @interface Anno2 {} + + Anno anno1 = (Anno & Serializable) ()-> null; // annotations not allowed + Anno anno2 = (Serializable & Anno & Anno2) ()-> null; // annotations not allowed + Anno anno3 = (Anno & Serializable) ClassInIntersectionTypeTest::myAnnoType; // annotations not allowed + Anno anno4 = (Serializable & Anno2 & Anno) ClassInIntersectionTypeTest::myAnnoType; // annotations not allowed + + static void bar() { + annotationType(() -> null); + annotationType(ClassInIntersectionTypeTest::myAnnoType); + } + + static void annotationType(T t) { + t.annotationType(); + } + + Anno anno5 = ()-> null; // annotations are not functional interfaces +} diff --git a/test/langtools/tools/javac/lambda/ClassInIntersectionTypeTest.out b/test/langtools/tools/javac/lambda/ClassInIntersectionTypeTest.out new file mode 100644 index 00000000000..b0a6bc2ab84 --- /dev/null +++ b/test/langtools/tools/javac/lambda/ClassInIntersectionTypeTest.out @@ -0,0 +1,12 @@ +ClassInIntersectionTypeTest.java:14:83: compiler.err.prob.found.req: (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest)) +ClassInIntersectionTypeTest.java:15:83: compiler.err.prob.found.req: (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest)) +ClassInIntersectionTypeTest.java:22:13: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest))) +ClassInIntersectionTypeTest.java:23:13: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest))) +ClassInIntersectionTypeTest.java:34:40: compiler.err.prob.found.req: (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest.Anno)) +ClassInIntersectionTypeTest.java:35:48: compiler.err.prob.found.req: (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest.Anno)) +ClassInIntersectionTypeTest.java:36:40: compiler.err.prob.found.req: (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest.Anno)) +ClassInIntersectionTypeTest.java:37:48: compiler.err.prob.found.req: (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest.Anno2)) +ClassInIntersectionTypeTest.java:40:23: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest.Anno))) +ClassInIntersectionTypeTest.java:41:23: compiler.err.prob.found.req: (compiler.misc.infer.no.conforming.assignment.exists: T, (compiler.misc.bad.intersection.target.for.functional.expr: (compiler.misc.not.an.intf.component: ClassInIntersectionTypeTest.Anno))) +ClassInIntersectionTypeTest.java:48:18: compiler.err.prob.found.req: (compiler.misc.not.a.functional.intf: ClassInIntersectionTypeTest.Anno) +11 errors diff --git a/test/langtools/tools/javac/launcher/BasicSourceLauncherTests.java b/test/langtools/tools/javac/launcher/BasicSourceLauncherTests.java index eb000276e14..2083f0751e7 100644 --- a/test/langtools/tools/javac/launcher/BasicSourceLauncherTests.java +++ b/test/langtools/tools/javac/launcher/BasicSourceLauncherTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,8 +32,7 @@ /* * @test - * @enablePreview - * @bug 8304400 + * @bug 8304400 8344706 * @summary Test basic features of javac's source-code launcher * @modules jdk.compiler/com.sun.tools.javac.launcher * @run junit BasicSourceLauncherTests @@ -98,7 +97,7 @@ void main() { } """); - var run = Run.of(hi, List.of("--enable-preview"), List.of()); + var run = Run.of(hi, List.of(), List.of()); assertAll("# " + run, () -> assertLinesMatch( """ diff --git a/test/langtools/tools/javac/launcher/GetResourceTest.java b/test/langtools/tools/javac/launcher/GetResourceTest.java index acdc1e5c429..34bffa5adeb 100644 --- a/test/langtools/tools/javac/launcher/GetResourceTest.java +++ b/test/langtools/tools/javac/launcher/GetResourceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,8 @@ /* * @test - * @bug 8210009 8321739 - * @summary Source Launcher classloader should support getResource and getResourceAsStream + * @bug 8210009 8321739 8336470 + * @summary Source Launcher classloader should support getResource/s and getResourceAsStream * @modules jdk.compiler * @library /tools/lib * @build toolbox.JavaTask toolbox.ToolBox @@ -44,12 +44,12 @@ * in order to test the classloader used to launch such programs. */ public class GetResourceTest { - public static void main(String... args) throws Exception { + public static void main(String... args) { GetResourceTest t = new GetResourceTest(); t.run(); } - void run() throws Exception { + void run() { ToolBox tb = new ToolBox(); Path file = Paths.get(tb.testSrc).resolve("src/p/q").resolve("CLTest.java"); new JavaTask(tb) diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 3676ced9535..017abb74456 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8192920 8204588 8246774 8248843 8268869 8235876 8328339 8335896 + * @bug 8192920 8204588 8246774 8248843 8268869 8235876 8328339 8335896 8344706 * @summary Test source launcher * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -283,6 +283,46 @@ void testSuccess(Path file, String expect) throws IOException { checkNull("exception", r.exception); } + + @Test + public void testMainNoParams(Path base) throws IOException { + tb.writeJavaFiles(base, + "package hello;\n" + + "import java.util.Arrays;\n" + + "class World {\n" + + " public static void main(String... args) {\n" + + " System.out.println(\"Hello World! \" + Arrays.toString(args));\n" + + " }\n" + + "}"); + testSuccess(base.resolve("hello").resolve("World.java"), "Hello World! [1, 2, 3]\n"); + } + + @Test + public void testMainNotPublic(Path base) throws IOException { + tb.writeJavaFiles(base, + "package hello;\n" + + "import java.util.Arrays;\n" + + "class World {\n" + + " static void main(String... args) {\n" + + " System.out.println(\"Hello World! \" + Arrays.toString(args));\n" + + " }\n" + + "}"); + testSuccess(base.resolve("hello").resolve("World.java"), "Hello World! [1, 2, 3]\n"); + } + + @Test + public void testMainNotStatic(Path base) throws IOException { + tb.writeJavaFiles(base, + "package hello;\n" + + "import java.util.Arrays;\n" + + "class World {\n" + + " public void main(String... args) {\n" + + " System.out.println(\"Hello World! \" + Arrays.toString(args));\n" + + " }\n" + + "}"); + testSuccess(base.resolve("hello").resolve("World.java"), "Hello World! [1, 2, 3]\n"); + } + /* * Negative tests: such as cannot find or execute main method. */ @@ -302,7 +342,7 @@ public void testHelloWorldWithShebangJava(Path base) throws IOException { file + ":1: error: illegal character: '#'\n" + "#!/usr/bin/java --source " + thisVersion + "\n" + "^\n" + - file + ":1: error: class, interface, enum, or record expected\n" + + file + ":1: error: class, interface, annotation type, enum, record, method or field expected\n" + "#!/usr/bin/java --source " + thisVersion + "\n" + " ^\n" + "2 errors\n", @@ -516,7 +556,7 @@ public void testBadShebang(Path base) throws IOException { file + ":1: error: illegal character: '#'\n" + "#/usr/bin/java --source " + thisVersion + "\n" + "^\n" + - file + ":1: error: class, interface, enum, or record expected\n" + + file + ":1: error: class, interface, annotation type, enum, record, method or field expected\n" + "#/usr/bin/java --source " + thisVersion + "\n" + " ^\n" + "2 errors\n", @@ -561,31 +601,15 @@ public void testEnablePreviewNoSource(Path base) throws IOException { public void testNoMain(Path base) throws IOException { tb.writeJavaFiles(base, "class NoMain { }"); testError(base.resolve("NoMain.java"), "", - "error: can't find main(String[]) method in class: NoMain"); + "error: can't find main(String[]) or main() method in class: NoMain"); } @Test public void testMainBadParams(Path base) throws IOException { tb.writeJavaFiles(base, - "class BadParams { public static void main() { } }"); + "class BadParams { public static void main(int n) { } }"); testError(base.resolve("BadParams.java"), "", - "error: can't find main(String[]) method in class: BadParams"); - } - - @Test - public void testMainNotPublic(Path base) throws IOException { - tb.writeJavaFiles(base, - "class NotPublic { static void main(String... args) { } }"); - testError(base.resolve("NotPublic.java"), "", - "error: can't find main(String[]) method in class: NotPublic"); - } - - @Test - public void testMainNotStatic(Path base) throws IOException { - tb.writeJavaFiles(base, - "class NotStatic { public void main(String... args) { } }"); - testError(base.resolve("NotStatic.java"), "", - "error: can't find main(String[]) method in class: NotStatic"); + "error: can't find main(String[]) or main() method in class: BadParams"); } @Test @@ -593,7 +617,7 @@ public void testMainNotVoid(Path base) throws IOException { tb.writeJavaFiles(base, "class NotVoid { public static int main(String... args) { return 0; } }"); testError(base.resolve("NotVoid.java"), "", - "error: can't find main(String[]) method in class: NotVoid"); + "error: can't find main(String[]) or main() method in class: NotVoid"); } @Test @@ -750,6 +774,82 @@ private static void markModuleAsIncubator(Path moduleInfoFile) throws Exception } } + @Test + public void testAbstractClassInstanceMain(Path base) throws IOException { + tb.writeJavaFiles(base, + """ + public abstract class AbstractMain { + void main(String[] args) {} + } + """); + testError(base.resolve("AbstractMain.java"), "", + "error: abstract class: AbstractMain can not be instantiated"); + } + + @Test + public void testWrongMainPrivate(Path base) throws IOException { + tb.writeJavaFiles(base, + """ + public class WrongMainPrivate { + private static void main(String[] args) {} + void main() { + System.out.println("correct"); + } + } + """); + testSuccess(base.resolve("WrongMainPrivate.java"), + "correct\n"); + } + + @Test + public void testWrongMainPrivateInstance(Path base) throws IOException { + tb.writeJavaFiles(base, + """ + public class WrongMainPrivate { + private void main(String[] args) {} + void main() { + System.out.println("correct"); + } + } + """); + testSuccess(base.resolve("WrongMainPrivate.java"), + "correct\n"); + } + + @Test + public void testWrongMainReturnType(Path base) throws IOException { + tb.writeJavaFiles(base, + """ + public class WrongMainReturnType { + public static int main(String[] args) { + return -1; + } + void main() { + System.out.println("correct"); + } + } + """); + testSuccess(base.resolve("WrongMainReturnType.java"), + "correct\n"); + } + + @Test + public void testWrongMainReturnTypeInstance(Path base) throws IOException { + tb.writeJavaFiles(base, + """ + public class WrongMainReturnType { + public int main(String[] args) { + return -1; + } + void main() { + System.out.println("correct"); + } + } + """); + testSuccess(base.resolve("WrongMainReturnType.java"), + "correct\n"); + } + Result run(Path file, List runtimeArgs, List appArgs) { List args = new ArrayList<>(); args.add(file.toString()); diff --git a/test/langtools/tools/javac/launcher/src/META-INF/services/java.util.spi.ToolProvider b/test/langtools/tools/javac/launcher/src/META-INF/services/java.util.spi.ToolProvider new file mode 100644 index 00000000000..a475bbc4127 --- /dev/null +++ b/test/langtools/tools/javac/launcher/src/META-INF/services/java.util.spi.ToolProvider @@ -0,0 +1 @@ +Tool diff --git a/test/langtools/tools/javac/launcher/src/Tool.java b/test/langtools/tools/javac/launcher/src/Tool.java new file mode 100644 index 00000000000..1082452c113 --- /dev/null +++ b/test/langtools/tools/javac/launcher/src/Tool.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +// unnamed package + +import java.io.PrintWriter; +import java.util.spi.ToolProvider; + +public class Tool implements ToolProvider { + @Override + public String name() { + return "Tool"; + } + + @Override + public int run(PrintWriter out, PrintWriter err, String... args) { + out.println("Tool/out"); + err.println("Tool/err"); + return 0; + } +} diff --git a/test/langtools/tools/javac/launcher/src/p/q/CLTest.java b/test/langtools/tools/javac/launcher/src/p/q/CLTest.java index 71840d3f29d..938512e1501 100644 --- a/test/langtools/tools/javac/launcher/src/p/q/CLTest.java +++ b/test/langtools/tools/javac/launcher/src/p/q/CLTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,23 +39,42 @@ import java.util.*; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassFile; +import java.util.spi.ToolProvider; public class CLTest { public static void main(String... args) throws Exception { try { - new CLTest().run(); + var test = new CLTest(); + test.loadToolProviderByName(); // run first to create Tool.class + test.getGetResources(); } catch (Throwable t) { t.printStackTrace(); System.exit(1); } } - void run() throws Exception { + void loadToolProviderByName() { + ServiceLoader.load(ToolProvider.class).stream() + .map(ServiceLoader.Provider::get) + .filter(toolProvider -> toolProvider.name().equals("Tool")) + .findFirst() + .orElseThrow(); + } + + void getGetResources() throws Exception { String[] names = { + // scheme -> file: + "Tool.java", + "p/q/CLTest.java", + "META-INF/services/java.util.spi.ToolProvider", + // scheme -> sourcelauncher-memoryclassloaderNNN: + "Tool.class", "p/q/CLTest.class", "p/q/CLTest$Inner.class", "p/q/CLTest2.class", + // scheme -> jrt: "java/lang/Object.class", + // no scheme applicable "UNKNOWN.class", "UNKNOWN" }; @@ -102,6 +121,14 @@ void testGetResources(String name) { list.add(e.nextElement()); } + if (name.contains("META-INF")) { + if (list.size() == 0) { + error("resource not found: " + name); + } + // one or more resources found, as expected + return; + } + switch (list.size()) { case 0: if (!name.contains("UNKNOWN")) { @@ -150,6 +177,9 @@ void checkClass(String name, URL u) throws Exception { } void checkClass(String name, InputStream in) throws Exception { + if (!name.endsWith(".class")) { + return; // ignore non-class resources + } ClassModel cf = ClassFile.of().parse(in.readAllBytes()); System.err.println(" class " + cf.thisClass().asInternalName()); if (!name.equals(cf.thisClass().asInternalName() + ".class")) { diff --git a/test/langtools/tools/javac/lexer/JavaLexerTest.java b/test/langtools/tools/javac/lexer/JavaLexerTest.java index 6b9c789087c..b2362801f84 100644 --- a/test/langtools/tools/javac/lexer/JavaLexerTest.java +++ b/test/langtools/tools/javac/lexer/JavaLexerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,8 +30,11 @@ */ import java.net.URI; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; +import javax.tools.DiagnosticListener; import javax.tools.SimpleJavaFileObject; import com.sun.tools.javac.parser.JavaTokenizer; @@ -101,17 +104,29 @@ public class JavaLexerTest { new TestTuple(ERROR, "\'\'"), new TestTuple(ERROR, "\'\\q\'", "\'\\q\'"), new TestTuple(ERROR, "\'\\{1+2}\'", "\'\\{1+2}\'"), + new TestTuple(ERROR, "'\uD83D\uDE0A'", + List.of("compiler.err.illegal.char.literal.multiple.surrogates")), }; static class TestTuple { String input; TokenKind kind; String expected; + List expectedErrors; - TestTuple(TokenKind kind, String input, String expected) { + TestTuple(TokenKind kind, String input, String expected, List expectedErrors) { this.input = input; this.kind = kind; this.expected = expected; + this.expectedErrors = expectedErrors; + } + + TestTuple(TokenKind kind, String input, List expectedErrors) { + this(kind, input, input, expectedErrors); + } + + TestTuple(TokenKind kind, String input, String expected) { + this(kind, input, expected, null); } TestTuple(TokenKind kind, String input) { @@ -121,6 +136,12 @@ static class TestTuple { void test(TestTuple test, boolean willFail) throws Exception { Context ctx = new Context(); + List errors = new ArrayList(); + + if (test.expectedErrors != null) { + ctx.put(DiagnosticListener.class, (DiagnosticListener) d -> errors.add(d.getCode())); + } + Log log = Log.instance(ctx); log.useSource(SimpleJavaFileObject.forSource(URI.create("mem://Test.java"), @@ -149,6 +170,10 @@ void test(TestTuple test, boolean willFail) throws Exception { System.err.println("input: " + test.input); throw new AssertionError("Unexpected token content: " + actual); } + + if (test.expectedErrors != null && !test.expectedErrors.equals(errors)) { + throw new AssertionError("Unexpected errors: " + errors); + } } void run() throws Exception { diff --git a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java index 081a156d6a0..e181ef8bf63 100644 --- a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java +++ b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -113,7 +113,7 @@ protected void addExports(String moduleName, String... packageNames) { * corresponding platform visitor type. */ - @SupportedSourceVersion(RELEASE_25) + @SupportedSourceVersion(RELEASE_26) @SuppressWarnings("preview") public static abstract class AbstractAnnotationValueVisitor extends AbstractAnnotationValueVisitorPreview { @@ -125,7 +125,7 @@ protected AbstractAnnotationValueVisitor() { } } - @SupportedSourceVersion(RELEASE_25) + @SupportedSourceVersion(RELEASE_26) @SuppressWarnings("preview") public static abstract class AbstractElementVisitor extends AbstractElementVisitorPreview { /** @@ -136,7 +136,7 @@ protected AbstractElementVisitor(){ } } - @SupportedSourceVersion(RELEASE_25) + @SupportedSourceVersion(RELEASE_26) @SuppressWarnings("preview") public static abstract class AbstractTypeVisitor extends AbstractTypeVisitorPreview { /** @@ -147,7 +147,7 @@ protected AbstractTypeVisitor() { } } - @SupportedSourceVersion(RELEASE_25) + @SupportedSourceVersion(RELEASE_26) @SuppressWarnings("preview") public static class ElementKindVisitor extends ElementKindVisitorPreview { /** @@ -169,7 +169,7 @@ protected ElementKindVisitor(R defaultValue) { } } - @SupportedSourceVersion(RELEASE_25) + @SupportedSourceVersion(RELEASE_26) @SuppressWarnings("preview") public static class ElementScanner extends ElementScannerPreview { /** @@ -189,7 +189,7 @@ protected ElementScanner(R defaultValue){ } } - @SupportedSourceVersion(RELEASE_25) + @SupportedSourceVersion(RELEASE_26) @SuppressWarnings("preview") public static class SimpleAnnotationValueVisitor extends SimpleAnnotationValueVisitorPreview { /** @@ -211,7 +211,7 @@ protected SimpleAnnotationValueVisitor(R defaultValue) { } } - @SupportedSourceVersion(RELEASE_25) + @SupportedSourceVersion(RELEASE_26) @SuppressWarnings("preview") public static class SimpleElementVisitor extends SimpleElementVisitorPreview { /** @@ -233,7 +233,7 @@ protected SimpleElementVisitor(R defaultValue){ } } - @SupportedSourceVersion(RELEASE_25) + @SupportedSourceVersion(RELEASE_26) @SuppressWarnings("preview") public static class SimpleTypeVisitor extends SimpleTypeVisitorPreview { /** @@ -255,7 +255,7 @@ protected SimpleTypeVisitor(R defaultValue){ } } - @SupportedSourceVersion(RELEASE_25) + @SupportedSourceVersion(RELEASE_26) @SuppressWarnings("preview") public static class TypeKindVisitor extends TypeKindVisitorPreview { /** diff --git a/test/langtools/tools/javac/lint/ExternalAbuseOfVbc.java b/test/langtools/tools/javac/lint/ExternalAbuseOfVbc.java index 53de855fb01..d68932774a2 100644 --- a/test/langtools/tools/javac/lint/ExternalAbuseOfVbc.java +++ b/test/langtools/tools/javac/lint/ExternalAbuseOfVbc.java @@ -5,8 +5,10 @@ * @compile/fail/ref=ExternalAbuseOfVbc.out -XDrawDiagnostics -Werror -Xlint ExternalAbuseOfVbc.java * @compile/fail/ref=ExternalAbuseOfVbc.out -XDrawDiagnostics -Werror -Xlint:all ExternalAbuseOfVbc.java * @compile/fail/ref=ExternalAbuseOfVbc.out -XDrawDiagnostics -Werror -Xlint:synchronization ExternalAbuseOfVbc.java + * @compile/fail/ref=ExternalAbuseOfVbc.out -XDrawDiagnostics -Werror -Xlint:identity ExternalAbuseOfVbc.java * @compile/fail/ref=ExternalAbuseOfVbc.out --release 16 -XDrawDiagnostics -Werror -Xlint:synchronization ExternalAbuseOfVbc.java - * @compile/ref=LintModeOffAbuseOfVbc.out -XDrawDiagnostics -Werror -Xlint:-synchronization ExternalAbuseOfVbc.java + * @compile/fail/ref=ExternalAbuseOfVbc.out --release 16 -XDrawDiagnostics -Werror -Xlint:identity ExternalAbuseOfVbc.java + * @compile/ref=LintModeOffAbuseOfVbc.out -XDrawDiagnostics -Werror -Xlint:-synchronization,-identity ExternalAbuseOfVbc.java */ public final class ExternalAbuseOfVbc { diff --git a/test/langtools/tools/javac/lint/ExternalAbuseOfVbc.out b/test/langtools/tools/javac/lint/ExternalAbuseOfVbc.out index b042a2c2139..d03e33e06d5 100644 --- a/test/langtools/tools/javac/lint/ExternalAbuseOfVbc.out +++ b/test/langtools/tools/javac/lint/ExternalAbuseOfVbc.out @@ -1,4 +1,4 @@ -ExternalAbuseOfVbc.java:19:13: compiler.warn.attempt.to.synchronize.on.instance.of.value.based.class +ExternalAbuseOfVbc.java:21:13: compiler.warn.attempt.to.synchronize.on.instance.of.value.based.class - compiler.err.warnings.and.werror 1 error 1 warning diff --git a/test/langtools/tools/javac/lint/NoWarn.java b/test/langtools/tools/javac/lint/NoWarn.java index 7d6153807f2..4a1b99a7bed 100644 --- a/test/langtools/tools/javac/lint/NoWarn.java +++ b/test/langtools/tools/javac/lint/NoWarn.java @@ -1,15 +1,20 @@ /** - * @test /nodynamiccopyright/ - * @bug 6183484 - * @summary verify -nowarn is the same as -Xlint:none - * @compile/ref=NoWarn1.out -XDrawDiagnostics NoWarn.java - * @compile/ref=NoWarn2.out -XDrawDiagnostics -nowarn NoWarn.java - * @compile/ref=NoWarn2.out -XDrawDiagnostics -Xlint:none NoWarn.java + * @test /nodynamiccopyright/ + * @bug 6183484 8352612 + * @summary Restrict -Xlint:none to affect only lint categories, while -nowarn disables all warnings + * @compile/ref=NoWarn1.out -XDfind=diamond -XDrawDiagnostics -Xlint:none NoWarn.java + * @compile/ref=NoWarn2.out -XDfind=diamond -XDrawDiagnostics -Xlint:divzero,unchecked NoWarn.java + * @compile/ref=NoWarn2.out -XDfind=diamond -XDrawDiagnostics -Xlint:none,divzero,unchecked NoWarn.java + * @compile/ref=NoWarn3.out -XDfind=diamond -XDrawDiagnostics -Xlint:none -nowarn NoWarn.java + * @compile/ref=NoWarn4.out -XDfind=diamond -XDrawDiagnostics -Xlint:divzero,unchecked -nowarn NoWarn.java + * @compile/ref=NoWarn4.out -XDfind=diamond -XDrawDiagnostics -Xlint:none,divzero,unchecked -nowarn NoWarn.java */ - +import java.util.*; class NoWarn { - void m(Object... args) { } - void foo() { - m(null); - } + Set z = null; // Mandatory Lint Lint Category How can it be suppressed? + // --------- ---- ------------- ------------------------- + sun.misc.Unsafe b; // Yes No N/A Not possible + Set a = new HashSet(); // No No N/A "-nowarn" only (requires -XDfind=diamond) + Set d = (Set)z; // Yes Yes "unchecked" "-Xlint:-unchecked" only + int c = 1/0; // No Yes "divzero" "-Xlint:-divzero" or "-nowarn" } diff --git a/test/langtools/tools/javac/lint/NoWarn1.out b/test/langtools/tools/javac/lint/NoWarn1.out index c4a8456889f..5fea0f7b51a 100644 --- a/test/langtools/tools/javac/lint/NoWarn1.out +++ b/test/langtools/tools/javac/lint/NoWarn1.out @@ -1,2 +1,5 @@ -NoWarn.java:13:11: compiler.warn.inexact.non-varargs.call: java.lang.Object, java.lang.Object[] -1 warning +NoWarn.java:16:13: compiler.warn.sun.proprietary: sun.misc.Unsafe +NoWarn.java:17:32: compiler.warn.diamond.redundant.args +- compiler.note.unchecked.filename: NoWarn.java +- compiler.note.unchecked.recompile +2 warnings diff --git a/test/langtools/tools/javac/lint/NoWarn2.out b/test/langtools/tools/javac/lint/NoWarn2.out index e69de29bb2d..d33c2404e1e 100644 --- a/test/langtools/tools/javac/lint/NoWarn2.out +++ b/test/langtools/tools/javac/lint/NoWarn2.out @@ -0,0 +1,5 @@ +NoWarn.java:16:13: compiler.warn.sun.proprietary: sun.misc.Unsafe +NoWarn.java:18:34: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), java.util.Set, java.util.Set +NoWarn.java:19:15: compiler.warn.div.zero +NoWarn.java:17:32: compiler.warn.diamond.redundant.args +4 warnings diff --git a/test/langtools/tools/javac/lint/NoWarn3.out b/test/langtools/tools/javac/lint/NoWarn3.out new file mode 100644 index 00000000000..9491fe8b9ee --- /dev/null +++ b/test/langtools/tools/javac/lint/NoWarn3.out @@ -0,0 +1,4 @@ +NoWarn.java:16:13: compiler.warn.sun.proprietary: sun.misc.Unsafe +- compiler.note.unchecked.filename: NoWarn.java +- compiler.note.unchecked.recompile +1 warning diff --git a/test/langtools/tools/javac/lint/NoWarn4.out b/test/langtools/tools/javac/lint/NoWarn4.out new file mode 100644 index 00000000000..6586ff995bf --- /dev/null +++ b/test/langtools/tools/javac/lint/NoWarn4.out @@ -0,0 +1,3 @@ +NoWarn.java:16:13: compiler.warn.sun.proprietary: sun.misc.Unsafe +NoWarn.java:18:34: compiler.warn.prob.found.req: (compiler.misc.unchecked.cast.to.type), java.util.Set, java.util.Set +2 warnings diff --git a/test/langtools/tools/javac/lint/RequiresIdentityHelper.java b/test/langtools/tools/javac/lint/RequiresIdentityHelper.java new file mode 100644 index 00000000000..abc50d6d446 --- /dev/null +++ b/test/langtools/tools/javac/lint/RequiresIdentityHelper.java @@ -0,0 +1,21 @@ +/* /nodynamiccopyright/ */ + +package java.lang; + +public class RequiresIdentityHelper<@jdk.internal.RequiresIdentity T> { + public RequiresIdentityHelper() {} + public <@jdk.internal.RequiresIdentity TT> RequiresIdentityHelper(@jdk.internal.RequiresIdentity Object o) {} + + class RequiresIdentity2 { + public RequiresIdentity2() {} + public void foo(@jdk.internal.RequiresIdentity Object o) {} + public void bar(@jdk.internal.RequiresIdentity Object... o) {} + public void gg(@jdk.internal.RequiresIdentity TT ri) {} + } + + interface RequiresIdentityInt<@jdk.internal.RequiresIdentity T> {} + + interface MyIntFunction<@jdk.internal.RequiresIdentity R> { + R apply(int value); + } +} diff --git a/test/langtools/tools/javac/lint/RequiresIdentityTest.java b/test/langtools/tools/javac/lint/RequiresIdentityTest.java new file mode 100644 index 00000000000..ddc25c8d311 --- /dev/null +++ b/test/langtools/tools/javac/lint/RequiresIdentityTest.java @@ -0,0 +1,90 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8354556 + * @summary Expand value-based class warnings to java.lang.ref API + * @compile --patch-module java.base=${test.src} RequiresIdentityHelper.java + * @compile/fail/ref=RequiresIdentityTest.out --patch-module java.base=${test.src} -Werror -XDrawDiagnostics -Xlint:identity RequiresIdentityTest.java + * @compile/fail/ref=RequiresIdentityTest.out --patch-module java.base=${test.src} -Werror -XDrawDiagnostics -Xlint:synchronization RequiresIdentityTest.java + * @compile/ref=RequiresIdentityTest2.out --patch-module java.base=${test.src} -Werror -XDrawDiagnostics -Xlint:-identity RequiresIdentityTest.java + * @compile/ref=RequiresIdentityTest2.out --patch-module java.base=${test.src} -Werror -XDrawDiagnostics -Xlint:-synchronization RequiresIdentityTest.java + * @compile/fail/ref=RequiresIdentityTest.out --patch-module java.base=${test.src} -Werror -XDrawDiagnostics -Xlint:identity RequiresIdentityHelper.java RequiresIdentityTest.java + * @compile/fail/ref=RequiresIdentityTest.out --patch-module java.base=${test.src} -Werror -XDrawDiagnostics -Xlint:synchronization RequiresIdentityHelper.java RequiresIdentityTest.java + * @compile/ref=RequiresIdentityTest2.out --patch-module java.base=${test.src} -Werror -XDrawDiagnostics -Xlint:-identity RequiresIdentityHelper.java RequiresIdentityTest.java + * @compile/ref=RequiresIdentityTest2.out --patch-module java.base=${test.src} -Werror -XDrawDiagnostics -Xlint:-synchronization RequiresIdentityHelper.java RequiresIdentityTest.java + */ + +package java.lang; + +@SuppressWarnings("deprecation") +public class RequiresIdentityTest extends RequiresIdentityHelper // should warn + implements RequiresIdentityHelper.RequiresIdentityInt { // should warn + class Box {} + + RequiresIdentityHelper field; // should warn + RequiresIdentityHelper[] field2; // should warn + Box> field3; // should warn + Box> field4; // should warn + RequiresIdentityHelper field5 = new RequiresIdentityHelper(); // two warnings here + + public RequiresIdentityTest() {} + public RequiresIdentityTest(Integer i) { + super(i); // should warn + } + + void test(RequiresIdentity2 ri, Integer i) { // warn on the first argument due to its enclosing type: RequiresIdentityHelper + RequiresIdentityHelper localVar; // should warn + RequiresIdentityHelper[] localVar2; // should warn + // there should be warnings for the invocations below + ri.foo(i); + ri.bar(i, // warn here + i); // and here too + ri.gg(i); + } + + interface I extends RequiresIdentityHelper.RequiresIdentityInt {} // should warn + + void m(Object o) { + RequiresIdentityHelper ri = (RequiresIdentityHelper) o; // should warn + } + + RequiresIdentityHelper test() { // warn + return null; + } + + // two warns here one for the type parameter and one for the result type + > T test2() { return null; } + + class SomeClass> {} // warn + + record R(RequiresIdentityHelper c) {} // warn + record RR(R r) {} + + void m1(RequiresIdentityInt ri) { // warn here + if (ri instanceof RequiresIdentityInt rii) {} // and here + } + + void m2(RR rr) { + if (rr instanceof RR(R(RequiresIdentityHelper rii))) {} + } + + void m3() {} + void m4() { + this.>m3(); + } + + MyIntFunction field6 = Integer::new; // two warnings here + + class Run { + public <@jdk.internal.RequiresIdentity K> void run() {} + } + void m5(Runnable r) {} + void m6() { + m5(new Run()::run); + } + + void m7(Integer i, Object o) { + RequiresIdentityHelper var1 = new RequiresIdentityHelper(i); + RequiresIdentityHelper var2 = new RequiresIdentityHelper(o); + RequiresIdentityHelper var3 = new RequiresIdentityHelper(o); + } +} diff --git a/test/langtools/tools/javac/lint/RequiresIdentityTest.out b/test/langtools/tools/javac/lint/RequiresIdentityTest.out new file mode 100644 index 00000000000..ddcd4c91354 --- /dev/null +++ b/test/langtools/tools/javac/lint/RequiresIdentityTest.out @@ -0,0 +1,39 @@ +RequiresIdentityTest.java:19:65: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:20:88: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:23:27: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:24:36: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:25:8: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:26:8: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:27:72: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:27:27: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:31:15: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:34:32: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:35:31: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:36:40: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:38:16: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:39:16: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:40:16: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:41:15: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:44:67: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:47:63: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:50:27: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:55:6: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:55:49: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:57:21: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:59:36: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:62:32: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:63:46: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:67:54: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:72:37: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:75:37: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:75:18: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:82:32: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:86:90: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:87:52: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:88:82: compiler.warn.attempt.to.use.value.based.where.identity.expected +RequiresIdentityTest.java:88:31: compiler.warn.attempt.to.use.value.based.where.identity.expected +- compiler.err.warnings.and.werror +- compiler.note.unchecked.filename: RequiresIdentityTest.java +- compiler.note.unchecked.recompile +1 error +34 warnings diff --git a/test/langtools/tools/javac/lint/RequiresIdentityTest2.out b/test/langtools/tools/javac/lint/RequiresIdentityTest2.out new file mode 100644 index 00000000000..55a7ccdeb84 --- /dev/null +++ b/test/langtools/tools/javac/lint/RequiresIdentityTest2.out @@ -0,0 +1,2 @@ +- compiler.note.unchecked.filename: RequiresIdentityTest.java +- compiler.note.unchecked.recompile diff --git a/test/langtools/tools/javac/modules/AnnotationsOnModules.java b/test/langtools/tools/javac/modules/AnnotationsOnModules.java index 291633b4fb2..6d9bfaad406 100644 --- a/test/langtools/tools/javac/modules/AnnotationsOnModules.java +++ b/test/langtools/tools/javac/modules/AnnotationsOnModules.java @@ -755,7 +755,7 @@ public void testBrokenModuleInfoClassWithAnnotation(Path base) throws Exception for (ModuleRequireInfo mri : attr.requires()) { if (mri.requires().name().equalsString("java.base")) { requires.add(ModuleRequireInfo.of(mri.requires(), - List.of(AccessFlag.TRANSITIVE), + List.of(AccessFlag.STATIC_PHASE), mri.requiresVersion() .orElse(null))); } else { @@ -804,7 +804,7 @@ public class C {} .writeAll() .getOutputLines(OutputKind.DIRECT); List expectedErrors = List.of( - "- compiler.err.cant.access: m.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.bad.requires.flag: ACC_TRANSITIVE (0x0020)))", + "- compiler.err.cant.access: m.module-info, (compiler.misc.bad.class.file.header: module-info.class, (compiler.misc.bad.requires.flag: ACC_STATIC_PHASE (0x0040)))", "1 error" ); diff --git a/test/langtools/tools/javac/modules/ConvenientAccessErrorsTest.java b/test/langtools/tools/javac/modules/ConvenientAccessErrorsTest.java index 2958384ae94..d02f7816814 100644 --- a/test/langtools/tools/javac/modules/ConvenientAccessErrorsTest.java +++ b/test/langtools/tools/javac/modules/ConvenientAccessErrorsTest.java @@ -448,7 +448,6 @@ public void testInModuleImport(Path base) throws Exception { List log = new JavacTask(tb) .options("-XDrawDiagnostics", - "--enable-preview", "--source", System.getProperty("java.specification.version"), "--module-source-path", src.toString()) .outdir(classes) .files(findJavaFiles(src)) @@ -458,8 +457,6 @@ public void testInModuleImport(Path base) throws Exception { List expected = Arrays.asList( "Test.java:1:54: compiler.err.cant.resolve.location: kindname.class, Api, , , (compiler.misc.location: kindname.class, test.Test, null)", - "- compiler.note.preview.filename: Test.java, DEFAULT", - "- compiler.note.preview.recompile", "1 error"); if (!expected.equals(log)) diff --git a/test/langtools/tools/javac/modules/EdgeCases.java b/test/langtools/tools/javac/modules/EdgeCases.java index a3825d9e3a6..39b72dda03a 100644 --- a/test/langtools/tools/javac/modules/EdgeCases.java +++ b/test/langtools/tools/javac/modules/EdgeCases.java @@ -1178,7 +1178,8 @@ public class Test { log = new JavacTask(tb) .outdir(classes) - .options("-XDrawDiagnostics", "-XDshould-stop.at=FLOW") + .options("-XDrawDiagnostics", "-XDshould-stop.at=FLOW", + "--release", "24") .callback(verifyJavaSEDependency(true, seenJavaSEDependency)) .files(findJavaFiles(src)) .run(Task.Expect.FAIL) @@ -1186,7 +1187,7 @@ public class Test { .getOutputLines(Task.OutputKind.DIRECT); List expected = List.of( - "Test.java:2:8: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.module.imports)", + "Test.java:2:8: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.module.imports), 24, 25", "1 error"); if (!expected.equals(log)) diff --git a/test/langtools/tools/javac/modules/JavaBaseTest.java b/test/langtools/tools/javac/modules/JavaBaseTest.java index a888c430f53..9c089982c00 100644 --- a/test/langtools/tools/javac/modules/JavaBaseTest.java +++ b/test/langtools/tools/javac/modules/JavaBaseTest.java @@ -129,7 +129,7 @@ void testSource(Path base, List mods, String target) throws Exception { case "current": options.add("--release"); options.add(CURRENT_VERSION); - expectOK = false; + expectOK = true; break; case "current-preview": options.add("--enable-preview"); @@ -166,7 +166,7 @@ void testSource(Path base, List mods, String target) throws Exception { for (String mod : mods) { String key = mod.equals("static") ? "compiler.err.mod.not.allowed.here: " + mod - : "compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.java.base.transitive)"; + : "compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.java.base.transitive), $(VERSION), 25".replace("$(VERSION)", target); String message = "module-info.java:1:12: " + key; if (log.contains(message)) { foundErrorMessage = true; @@ -179,30 +179,26 @@ void testSource(Path base, List mods, String target) throws Exception { } void testClass(Path base, List mods, String target) throws Exception { - boolean expectOK; + boolean expectOK = true; List options = new ArrayList<>(); switch (target) { case "current": options.add("--release"); options.add(CURRENT_VERSION); - expectOK = false; break; case "current-preview": options.add("--enable-preview"); options.add("--release"); options.add(CURRENT_VERSION); - expectOK = true; break; case "9": options.add("--release"); options.add(target); - expectOK = true; break; default: options.add("--release"); options.add(target); - expectOK = false; break; } diff --git a/test/langtools/tools/javac/nametable/TestUtfNumChars.java b/test/langtools/tools/javac/nametable/TestUtfNumChars.java new file mode 100644 index 00000000000..de9530ec4c4 --- /dev/null +++ b/test/langtools/tools/javac/nametable/TestUtfNumChars.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8358066 + * @summary Test for bug in Convert.utfNumChars() + * @modules jdk.compiler/com.sun.tools.javac.util + * @run main TestUtfNumChars + */ + +import com.sun.tools.javac.util.Convert; + +import java.util.function.IntPredicate; +import java.util.stream.IntStream; + +public class TestUtfNumChars { + + public static void main(String[] args) { + + // This is the string "ab«cd≤ef🟢gh" + String s = "ab\u00ABcd\u2264ef\ud83d\udd34gh"; + + // This is its modified UTF-8 encoding + byte[] utf8 = Convert.string2utf(s); // UTF-8: 61 62 c2 ab 63 64 e2 89 a4 65 66 ed a0 bd ed b4 b4 67 68 + // Bytes: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 + // Chars: 00 01 02 .. 03 04 05 .. .. 06 07 08 .. .. 09 .. .. 10 11 + + // These are the offsets in "utf8" marking the boundaries of encoded Java charcters + int[] offsets = new int[] { + 0, 1, 2, 4, 5, 6, 9, 10, 11, 14, 17, 18 + }; + IntPredicate boundary = off -> off == utf8.length || IntStream.of(offsets).anyMatch(off2 -> off2 == off); + + // Check Convert.utfNumChars() on every subsequence + for (int i = 0; i < offsets.length; i++) { + int i_off = offsets[i]; + if (!boundary.test(i_off)) + continue; + for (int j = i; j < offsets.length; j++) { + int j_off = offsets[j]; + if (!boundary.test(j_off)) + continue; + int nchars = Convert.utfNumChars(utf8, i_off, j_off - i_off); + if (nchars != j - i) + throw new AssertionError(String.format("nchars %d != %d for [%d, %d)", nchars, j - i, i_off, j_off)); + } + } + } +} diff --git a/test/langtools/tools/javac/nested/5009484/Y.java b/test/langtools/tools/javac/nested/5009484/Y.java index d56309737ae..98c4b20edec 100644 --- a/test/langtools/tools/javac/nested/5009484/Y.java +++ b/test/langtools/tools/javac/nested/5009484/Y.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 5009484 * @summary Compiler fails to resolve appropriate type for outer member - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=Y.out -XDrawDiagnostics Y.java */ diff --git a/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java b/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java index ecc8218b5f5..4cef7e1916b 100644 --- a/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java +++ b/test/langtools/tools/javac/options/HelpOutputColumnWidthTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ public class HelpOutputColumnWidthTest extends TestRunner { - public static final int MAX_COLUMNS = 80; + public static final int MAX_COLUMNS = 84; protected ToolBox tb; diff --git a/test/langtools/tools/javac/overload/T4494762.java b/test/langtools/tools/javac/overload/T4494762.java index 5ca31ecb4f4..bc4c7c7ab62 100644 --- a/test/langtools/tools/javac/overload/T4494762.java +++ b/test/langtools/tools/javac/overload/T4494762.java @@ -25,7 +25,7 @@ * @test * @bug 4494762 6491939 * @summary Request for Clarification of JLS 15.12.2.2 - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T4494762.java */ diff --git a/test/langtools/tools/javac/parser/DeclarationEndPositions.java b/test/langtools/tools/javac/parser/DeclarationEndPositions.java new file mode 100644 index 00000000000..473d6bc2712 --- /dev/null +++ b/test/langtools/tools/javac/parser/DeclarationEndPositions.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8350212 + * @summary Verify ending source positions are calculated for declarations supporting SuppressWarnings + * @modules jdk.compiler/com.sun.tools.javac.tree + * @run main DeclarationEndPositions + */ + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.Tree; +import com.sun.source.tree.Tree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreeScanner; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.tree.TreeInfo; + +import java.io.IOException; +import java.net.URI; +import java.util.List; + +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +public class DeclarationEndPositions { + + public static void checkEndPosition(Class nodeType, String input, String marker) throws IOException { + + // Create source + var source = new SimpleJavaFileObject(URI.create("file://T.java"), JavaFileObject.Kind.SOURCE) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return input; + } + }; + + // Parse source + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + JavaCompiler.CompilationTask task = compiler.getTask(null, null, null, List.of(), List.of(), List.of(source)); + Iterable units = ((JavacTask)task).parse(); + + // Find node and check end position + JCTree.JCCompilationUnit unit = (JCTree.JCCompilationUnit)units.iterator().next(); + unit.accept(new TreeScanner() { + @Override + public Void scan(Tree node, Void aVoid) { + if (nodeType.isInstance(node)) { + JCTree tree = (JCTree)node; + int actual = TreeInfo.getEndPos(tree, unit.endPositions); + int expected = marker.indexOf('^') + 1; + if (actual != expected) { + throw new AssertionError(String.format( + "wrong end pos %d != %d for \"%s\" @ %d", actual, expected, input, tree.pos)); + } + } + return super.scan(node, aVoid); + } + }, null); + } + + public static void main(String... args) throws Exception { + + // JCModuleDecl + checkEndPosition(JCModuleDecl.class, + "/* comment */ module fred { /* comment */ } /* comment */", + " ^ "); + + // JCPackageDecl + checkEndPosition(JCPackageDecl.class, + "/* comment */ package fred; /* comment */", + " ^ "); + + // JCClassDecl + checkEndPosition(JCClassDecl.class, + "/* comment */ class Fred { /* comment */ } /* comment */", + " ^ "); + + // JCMethodDecl + checkEndPosition(JCMethodDecl.class, + "/* comment */ class Fred { void m() { /* comment */ } } /* comment */", + " ^ "); + + // JCVariableDecl + checkEndPosition(JCVariableDecl.class, + "/* comment */ class Fred { int x; } /* comment */", + " ^ "); + checkEndPosition(JCVariableDecl.class, + "/* comment */ class Fred { int x = 123; } /* comment */", + " ^ "); + checkEndPosition(JCVariableDecl.class, + "/* comment */ class A { try {} catch (Error err) {} } /* comment */", + " ^ "); + } +} diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index 40ab577a5d1..9c6ad617132 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 8324859 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 8324859 8344706 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -1010,7 +1010,7 @@ void testVoidLambdaParameter() throws IOException { @Test //JDK-8065753 void testWrongFirstToken() throws IOException { String code = "<"; - String expectedErrors = "Test.java:1:1: compiler.err.expected4: class, interface, enum, record\n" + + String expectedErrors = "Test.java:1:1: compiler.err.class.method.or.field.expected\n" + "1 error\n"; StringWriter out = new StringWriter(); JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null, @@ -2298,13 +2298,12 @@ public Void visitCase(CaseTree node, Void p) { @Test //JDK-8310326 void testUnnamedClassPositions() throws IOException { - String code = """ - void main() { - } - """; + // 0 1 2 + // 012345678901234567890 + String code = "void main() { }"; DiagnosticCollector coll = new DiagnosticCollector<>(); - JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, List.of("--enable-preview", "--source", System.getProperty("java.specification.version")), + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, null, null, Arrays.asList(new MyFileObject(code))); Trees trees = Trees.instance(ct); SourcePositions sp = trees.getSourcePositions(); @@ -2313,7 +2312,7 @@ void main() { @Override public Void visitClass(ClassTree node, Void p) { assertEquals("Wrong start position", 0, sp.getStartPosition(cut, node)); - assertEquals("Wrong end position", -1, sp.getEndPosition(cut, node)); + assertEquals("Wrong end position", 15, sp.getEndPosition(cut, node)); assertEquals("Wrong modifiers start position", -1, sp.getStartPosition(cut, node.getModifiers())); assertEquals("Wrong modifiers end position", -1, sp.getEndPosition(cut, node.getModifiers())); return super.visitClass(node, p); diff --git a/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out b/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out index 05d27bc67df..15ea81a7f16 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.annotation.missing.element.value -SingleCommaAnnotationValueFail.java:11:14: compiler.err.expected4: class, interface, enum, record +SingleCommaAnnotationValueFail.java:11:14: compiler.err.class.method.or.field.expected 2 errors diff --git a/test/langtools/tools/javac/parser/extend/TrialParser.java b/test/langtools/tools/javac/parser/extend/TrialParser.java index 539676a90fb..c9a858fbc47 100644 --- a/test/langtools/tools/javac/parser/extend/TrialParser.java +++ b/test/langtools/tools/javac/parser/extend/TrialParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -139,7 +139,6 @@ public TrialUnit(List defs) { storeEnd(toplevel, S.prevToken().endPos); } toplevel.lineMap = S.getLineMap(); - this.endPosTable.setParser(null); // remove reference to parser toplevel.endPositions = this.endPosTable; return toplevel; } diff --git a/test/langtools/tools/javac/patterns/InstanceOfModelTest.java b/test/langtools/tools/javac/patterns/InstanceOfModelTest.java new file mode 100644 index 00000000000..b756c9263bd --- /dev/null +++ b/test/langtools/tools/javac/patterns/InstanceOfModelTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8348906 + * @summary Verify the InstanceOfTree model + */ + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.tree.InstanceOfTree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.TreeScanner; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +public class InstanceOfModelTest { + private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + + public static void main(String... args) throws Exception { + new InstanceOfModelTest().run(); + } + + private void run() throws Exception { + JavaFileObject input = + SimpleJavaFileObject.forSource(URI.create("mem://Test.java"), + """ + public class Test { + void test(Object o) { + boolean _ = o instanceof R; + boolean _ = o instanceof R r; + boolean _ = o instanceof R(var v); + } + record R(int i) {} + } + """); + JavacTask task = + (JavacTask) compiler.getTask(null, null, null, null, null, List.of(input)); + CompilationUnitTree cut = task.parse().iterator().next(); + + task.analyze(); + + List instanceOf = new ArrayList<>(); + + new TreeScanner() { + @Override + public Void visitInstanceOf(InstanceOfTree node, Void p) { + instanceOf.add(node.getPattern() + ":" + node.getType()); + return super.visitInstanceOf(node, p); + } + }.scan(cut, null); + + List expectedInstanceOf = List.of( + "null:R", + "R r:R", + "R(int v):null" + ); + + if (!Objects.equals(expectedInstanceOf, instanceOf)) { + throw new AssertionError("Expected: " + expectedInstanceOf + ",\n" + + "got: " + instanceOf); + } + } +} diff --git a/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchRequirePreview.java b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchRequirePreview.java new file mode 100644 index 00000000000..a69df09912a --- /dev/null +++ b/test/langtools/tools/javac/patterns/PrimitivePatternsSwitchRequirePreview.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8348410 + * @summary Ensure --enable-preview is required for primitive switch on a boxed expression + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run main PrimitivePatternsSwitchRequirePreview + */ + +import java.nio.file.Path; +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 PrimitivePatternsSwitchRequirePreview extends TestRunner { + + ToolBox tb; + + public PrimitivePatternsSwitchRequirePreview() { + super(System.err); + tb = new ToolBox(); + } + + public static void main(String[] args) throws Exception { + PrimitivePatternsSwitchRequirePreview t = new PrimitivePatternsSwitchRequirePreview(); + t.runTests(); + } + + @Test + public void testBoolean() throws Exception { + String code = """ + class C { + public static void testBoolean(Boolean value) { + switch (value) { + case true -> System.out.println("true"); + default -> System.out.println("false"); + } + } + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev", "-XDshould-stop.at=FLOW") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "C.java:4:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.primitive.patterns)", + "1 error" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + + @Test + public void testLong() throws Exception { + String code = """ + class C { + public static void testLong(Long value) { + switch (value) { + case 0L -> System.out.println("zero"); + default -> System.out.println("non-zero"); + } + } + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev", "-XDshould-stop.at=FLOW") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "C.java:4:17: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.primitive.patterns)", + "1 error" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + + @Test + public void testFloat() throws Exception { + String code = """ + class C { + public static void testFloat(Float value) { + switch (value) { + case 0f -> System.out.println("zero"); + default -> System.out.println("non-zero"); + } + } + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev", "-XDshould-stop.at=FLOW") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "C.java:4:15: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.primitive.patterns)", + "1 error" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + + @Test + public void testDouble() throws Exception { + String code = """ + class C { + public static void testDouble(Long value) { + switch (value) { + case 0L -> System.out.println("zero"); + default -> System.out.println("non-zero"); + } + } + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev", "-XDshould-stop.at=FLOW") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "C.java:4:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.primitive.patterns)", + "1 error" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } +} \ No newline at end of file diff --git a/test/langtools/tools/javac/patterns/SwitchErrors.java b/test/langtools/tools/javac/patterns/SwitchErrors.java index 6f93dbb192a..607052be583 100644 --- a/test/langtools/tools/javac/patterns/SwitchErrors.java +++ b/test/langtools/tools/javac/patterns/SwitchErrors.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8262891 8269146 8269113 + * @bug 8262891 8269146 8269113 8348928 * @summary Verify errors related to pattern switches. * @compile/fail/ref=SwitchErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW SwitchErrors.java */ @@ -307,4 +307,22 @@ void test8269301bb(Integer i) { break; } } + + void testPatternWithoutBindingCantOverridePatternWithBinding8348928a(Object o) { + record R(int i, String s) {} + switch (o) { + case Integer _, R(int x, String _) -> {} + default -> {} + } + } + + void testPatternWithoutBindingCantOverridePatternWithBinding8348928b(Object o) { + record R(int i, String s) {} + switch (o) { + case Integer _: + case R(int x, String _): + break; + default: + } + } } diff --git a/test/langtools/tools/javac/patterns/SwitchErrors.out b/test/langtools/tools/javac/patterns/SwitchErrors.out index 9eea96ee272..fa2038b29b6 100644 --- a/test/langtools/tools/javac/patterns/SwitchErrors.out +++ b/test/langtools/tools/javac/patterns/SwitchErrors.out @@ -57,6 +57,8 @@ SwitchErrors.java:276:49: compiler.err.cant.resolve.location.args: kindname.meth SwitchErrors.java:278:55: compiler.err.cant.resolve.location.args: kindname.method, length, , , (compiler.misc.location: kindname.class, java.lang.Object, null) SwitchErrors.java:284:26: compiler.err.pattern.type.cannot.infer SwitchErrors.java:299:21: compiler.err.invalid.case.label.combination +SwitchErrors.java:314:29: compiler.err.flows.through.from.pattern +SwitchErrors.java:323:18: compiler.err.flows.through.to.pattern SwitchErrors.java:10:9: compiler.err.not.exhaustive.statement SwitchErrors.java:16:9: compiler.err.not.exhaustive.statement SwitchErrors.java:22:9: compiler.err.not.exhaustive.statement @@ -69,4 +71,4 @@ SwitchErrors.java:98:9: compiler.err.not.exhaustive.statement SwitchErrors.java:105:9: compiler.err.not.exhaustive.statement SwitchErrors.java:153:9: compiler.err.not.exhaustive.statement SwitchErrors.java:226:9: compiler.err.not.exhaustive.statement -71 errors +73 errors diff --git a/test/langtools/tools/javac/platform/RequiresIdentityTest.java b/test/langtools/tools/javac/platform/RequiresIdentityTest.java new file mode 100644 index 00000000000..f10d6e8054c --- /dev/null +++ b/test/langtools/tools/javac/platform/RequiresIdentityTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8356894 + * @summary Verify source level checks are performed properly + * @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 RequiresIdentityTest +*/ + +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 RequiresIdentityTest extends TestRunner { + + ToolBox tb; + + public static void main(String... args) throws Exception { + new RequiresIdentityTest().runTests(); + } + + RequiresIdentityTest() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testReleaseWorksAsCurrentVersion(Path base) throws Exception { + Path src = base.resolve("src"); + Path classes = base.resolve("classes"); + tb.writeJavaFiles(src, + """ + import java.util.WeakHashMap; + import java.util.Optional; + + public class Test { + void test() { + WeakHashMap, Object> m = null; + m.put(Optional.empty(), 1); + } + } + """); + + Files.createDirectories(classes); + + var expectedErrors = List.of( + "Test.java:6:20: compiler.warn.attempt.to.use.value.based.where.identity.expected", + "Test.java:7:29: compiler.warn.attempt.to.use.value.based.where.identity.expected", + "2 warnings" + ); + + { + var actualErrors = + new JavacTask(tb) + .options("-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + if (!expectedErrors.equals(actualErrors)) { + throw new AssertionError("Incorrect errors, expected: " + List.of(expectedErrors) + + ", actual: " + actualErrors); + } + } + + { + var actualErrors = + new JavacTask(tb) + .options("--release", System.getProperty("java.specification.version"), + "-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + if (!expectedErrors.equals(actualErrors)) { + throw new AssertionError("Incorrect errors, expected: " + List.of(expectedErrors) + + ", actual: " + actualErrors); + } + } + } + + @Test + public void testModel(Path base) throws Exception { + { + List printed = + new JavacTask(tb) + .options("-Xprint") + .classes("java.util.WeakHashMap") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + printed.removeIf(l -> !l.contains("put(") && !l.contains("class WeakHashMap<")); + + List expected = List.of( + "public class WeakHashMap<@jdk.internal.RequiresIdentity K, V> extends java.util.AbstractMap implements java.util.Map {", + " public V put(@jdk.internal.RequiresIdentity sealed K key," + ); + if (!expected.equals(printed)) { + throw new AssertionError("Expected: " + expected + + ", but got: " + printed); + } + } + + { + List printed = + new JavacTask(tb) + .options("--release", System.getProperty("java.specification.version"), + "-Xprint") + .classes("java.util.WeakHashMap") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + printed.removeIf(l -> !l.contains("put(") && !l.contains("class WeakHashMap<")); + + List expected = List.of( + "public class WeakHashMap extends java.util.AbstractMap implements java.util.Map {", + " public V put(sealed K arg0," + ); + if (!expected.equals(printed)) { + throw new AssertionError("Expected: " + expected + + ", but got: " + printed); + } + } + } + +} diff --git a/test/langtools/tools/javac/platform/RequiresIdentityTest.out b/test/langtools/tools/javac/platform/RequiresIdentityTest.out new file mode 100644 index 00000000000..7b93ce830b7 --- /dev/null +++ b/test/langtools/tools/javac/platform/RequiresIdentityTest.out @@ -0,0 +1,4 @@ +RequiresIdentityTest.java:16:18: compiler.warn.attempt.to.use.value.based.where.identity.expected +- compiler.err.warnings.and.werror +1 error +1 warning diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java new file mode 100644 index 00000000000..a6298bfa8ce --- /dev/null +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsReproducibleTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import javax.lang.model.SourceVersion; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/* + * @test + * @bug 8327466 + * @summary verifies that the ct.sym file created by build.tools.symbolgenerator.CreateSymbols + * is reproducible + * @library /test/lib + * @modules java.compiler + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.jvm + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * + * @compile ${test.root}/../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java + * + * @run junit CreateSymbolsReproducibleTest + */ +public class CreateSymbolsReproducibleTest { + + // the fully qualified class name of the tool that we launch to generate the ct.sym file + private static final String CREATE_SYMBOLS_CLASS_FQN = "build.tools.symbolgenerator.CreateSymbols"; + // a reproducible timestamp (in seconds) that we pass to "CreateSymbols build-ctsym" as input + // when generating the ct.sym file + private static final long SOURCE_EPOCH_DATE = Instant.now().getEpochSecond(); + // arbitrary set of packages that will be included in a include list file + // that will be given as input to "CreateSymbols build-description-incremental" command + // for generating the symbol text file + private static final String INCLUDE_PKGS = """ + +java/io/ + +java/lang/ + +java/lang/annotation/ + +java/lang/instrument/ + +java/lang/invoke/ + """; + + private static Path symTxtFile; + + @BeforeAll + static void beforeAll() throws Exception { + symTxtFile = createSymTxtFile(); + System.out.println("created sym.txt file at " + symTxtFile); + } + + /* + * Launches the "CreateSymbols build-ctsym" tool multiple times to generate ct.sym files. + * Each time with the same inputs and the same timestamp. For each of these attempts, we use + * a different timezone when launching the tool. The test verifies that irrespective of + * what timezone gets used, the generated ct.sym files don't differ. + */ + @Test + void testDifferentTimezone() throws Exception { + final Path destDir = Files.createTempDirectory(Path.of("."), "").toAbsolutePath(); + final List ctSymFiles = new ArrayList<>(); + final List> timezones = List.of( + Optional.empty(), // no explicit timezone + Optional.of("UTC"), + Optional.of("America/Los_Angeles"), + Optional.of("Asia/Tokyo") + ); + int num = 0; + // create several ct.sym files by launching the tool with different timezones + // but the same timestamp value as input + for (final Optional timezone : timezones) { + num++; + final String destCtSymFileName = "ct-" + num + ".sym"; + final Path destCtSym = destDir.resolve(destCtSymFileName); + System.out.println("using timezone " + timezone + " to create ct.sym file at " + + destCtSym); + createCtSym(destCtSym, symTxtFile, timezone); + ctSymFiles.add(destCtSym); + } + // verify that each of these generated ct.sym files are exactly the same in content + for (int i = 0; i < ctSymFiles.size() - 1; i++) { + final Path ctSym1 = ctSymFiles.get(i); + final Path ctSym2 = ctSymFiles.get(i + 1); + final long mismatchOffset = Files.mismatch(ctSym1, ctSym2); + if (mismatchOffset != -1) { + throw new AssertionError("contents of files " + ctSym1 + " and " + ctSym2 + + " unexpectedly differ" + " (at " + mismatchOffset + " offset)"); + } + } + } + + private static Path createSymTxtFile() throws Exception { + final Path tmpDir = Files.createTempDirectory(Path.of("."), "").toAbsolutePath(); + final Path destSymTxtFile = tmpDir.resolve("sym.txt"); + Files.writeString(destSymTxtFile, ""); + final Path includeList = tmpDir.resolve("include.list"); + Files.writeString(includeList, INCLUDE_PKGS); + final String[] cmd = new String[]{ + "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + CREATE_SYMBOLS_CLASS_FQN, + "build-description-incremental", + destSymTxtFile.toString(), + includeList.toString() + }; + final OutputAnalyzer oa = ProcessTools.executeTestJava(cmd); + oa.shouldHaveExitValue(0); + // verify the file was created + if (Files.notExists(destSymTxtFile)) { + oa.reportDiagnosticSummary(); + throw new AssertionError(CREATE_SYMBOLS_CLASS_FQN + + " build-description-incremental failed to create " + destSymTxtFile); + } + return destSymTxtFile; + } + + private static void createCtSym(final Path destCtSymFile, final Path symTxtFile, + final Optional timezone) throws Exception { + final Path modulesDir = Path.of(".").resolve("modules"); + Files.createDirectories(modulesDir); + final Path modulesList = Path.of(".").resolve("modules-list"); + // an empty file + Files.writeString(modulesList, ""); + + final List cmd = new ArrayList<>(); + timezone.ifPresent((tz) -> { + // launch the tool with a specific timezone (if any) + cmd.add("-Duser.timezone=" + tz); + }); + cmd.add(CREATE_SYMBOLS_CLASS_FQN); + cmd.add("build-ctsym"); // command to CreateSymbols tool + cmd.add("non-existent-ct-desc-file"); + cmd.add(symTxtFile.toString()); // a previously generated a sym.txt file + cmd.add(destCtSymFile.toString()); // target ct.sym file to generate + cmd.add(Long.toString(SOURCE_EPOCH_DATE)); // reproducible timestamp (in seconds) + cmd.add(Integer.toString(SourceVersion.latest().ordinal())); + cmd.add("does-not-matter-pre-release-tag"); + cmd.add(modulesDir.toString()); + cmd.add(modulesList.toString()); + final OutputAnalyzer oa = ProcessTools.executeTestJava(cmd); + oa.shouldHaveExitValue(0); + // verify the ct.sym file was generated + if (Files.notExists(destCtSymFile)) { + oa.reportDiagnosticSummary(); + throw new AssertionError("ct.sym file missing at " + destCtSymFile); + } + } +} diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java index 76c13582b73..ac42c26488a 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTest.java @@ -21,19 +21,6 @@ * questions. */ -/** - * @test - * @bug 8072480 8277106 8331027 - * @summary Unit test for CreateSymbols - * @modules java.compiler - * jdk.compiler/com.sun.tools.javac.api - * jdk.compiler/com.sun.tools.javac.jvm - * jdk.compiler/com.sun.tools.javac.main - * jdk.compiler/com.sun.tools.javac.util - * @clean * - * @run main/othervm CreateSymbolsTest - */ - import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; diff --git a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java index c66cd08852a..2680ca6488f 100644 --- a/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java +++ b/test/langtools/tools/javac/platform/createsymbols/CreateSymbolsTestImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,19 @@ * questions. */ +/** + * @test + * @bug 8072480 8277106 8331027 + * @summary Unit test for CreateSymbols + * @modules java.compiler + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.jvm + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @clean * + * @run main/othervm CreateSymbolsTest + */ + import java.io.File; import java.io.InputStream; import java.io.Writer; @@ -908,6 +921,109 @@ public static class OtherNested {} """); } + @Test + void testTypeAnnotations() throws Exception { + doPrintElementTest(""" + package t; + public class T { + } + """, + """ + package t; + import java.lang.annotation.*; + import java.util.*; + public class T<@AnnInvisible @AnnVisible E extends @AnnInvisible @AnnVisible ArrayList<@AnnInvisible @AnnVisible ArrayList>> extends @AnnInvisible @AnnVisible ArrayList { + public @AnnInvisible @AnnVisible List<@AnnInvisible @AnnVisible E> field; + public <@AnnInvisible @AnnVisible M extends @AnnInvisible @AnnVisible ArrayList<@AnnInvisible @AnnVisible ArrayList>> @AnnInvisible @AnnVisible List<@AnnInvisible @AnnVisible M> convert(@AnnInvisible @AnnVisible T this, @AnnInvisible @AnnVisible M e1, @AnnInvisible @AnnVisible List<@AnnInvisible @AnnVisible E> e2) throws @AnnInvisible @AnnVisible IllegalStateException, @AnnInvisible @AnnVisible IllegalArgumentException { + return null; + } + } + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE_USE) + @interface AnnVisible { + } + @Retention(RetentionPolicy.CLASS) + @Target(ElementType.TYPE_USE) + @interface AnnInvisible { + } + """, + "t.T", + """ + package t; + + public class T { + + public T(); + } + """, + "t.T", + """ + package t; + + public class T<@t.AnnInvisible @t.AnnVisible E extends java.util.@t.AnnInvisible @t.AnnVisible ArrayList> extends java.util.@t.AnnInvisible @t.AnnVisible ArrayList { + public java.util.@t.AnnInvisible @t.AnnVisible List<@t.AnnInvisible @t.AnnVisible E> field; + + public T(); + + public <@t.AnnInvisible @t.AnnVisible M extends java.util.@t.AnnInvisible @t.AnnVisible ArrayList> java.util.@t.AnnInvisible @t.AnnVisible List<@t.AnnInvisible @t.AnnVisible M> convert(@t.AnnInvisible @t.AnnVisible M arg0, + java.util.@t.AnnInvisible @t.AnnVisible List<@t.AnnInvisible @t.AnnVisible E> arg1) throws java.lang.@t.AnnInvisible @t.AnnVisible IllegalStateException,\s + java.lang.@t.AnnInvisible @t.AnnVisible IllegalArgumentException; + } + """); + } + + @Test + void testParameterAnnotations() throws Exception { + doPrintElementTest(""" + package t; + public class T { + public void test(int p1, int p2) { + } + } + """, + """ + package t; + import java.lang.annotation.*; + import java.util.*; + public class T { + public void test(@AnnVisible int p1, @AnnInvisible int p2) { + } + } + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.PARAMETER) + @interface AnnVisible { + } + @Retention(RetentionPolicy.CLASS) + @Target(ElementType.PARAMETER) + @interface AnnInvisible { + } + """, + "t.T", + """ + package t; + + public class T { + + public T(); + + public void test(int arg0, + int arg1); + } + """, + "t.T", + """ + package t; + + public class T { + + public T(); + + public void test(@t.AnnVisible int arg0, + @t.AnnInvisible int arg1); + } + """); + } + void doTestData(String data, String... code) throws Exception { String testClasses = System.getProperty("test.classes"); diff --git a/test/langtools/tools/javac/positions/T6402077.java b/test/langtools/tools/javac/positions/T6402077.java index 0fb3f89ee81..66caa9c282e 100644 --- a/test/langtools/tools/javac/positions/T6402077.java +++ b/test/langtools/tools/javac/positions/T6402077.java @@ -25,7 +25,7 @@ * @test * @bug 6402077 * @summary Start position is wrong for package private constructors - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler */ diff --git a/test/langtools/tools/javac/positions/T6404194.java b/test/langtools/tools/javac/positions/T6404194.java index 6b187f58198..18b07ad8af1 100644 --- a/test/langtools/tools/javac/positions/T6404194.java +++ b/test/langtools/tools/javac/positions/T6404194.java @@ -25,7 +25,7 @@ * @test * @bug 6404194 * @summary javac parser generates incorrect end position for annotations with parentheses. - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler */ diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out b/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out index 46c55fa62f3..8c455009ae5 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, 25 +- compiler.err.preview.feature.disabled.classfile: Bar.class, 26 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 539b128efd2..26ff05b085a 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, 25 +- compiler.warn.preview.feature.use.classfile: Bar.class, 26 - compiler.err.warnings.and.werror 1 error 1 warning diff --git a/test/langtools/tools/javac/processing/6359313/T6359313.java b/test/langtools/tools/javac/processing/6359313/T6359313.java index 3d06d3ecfcb..b3854099075 100644 --- a/test/langtools/tools/javac/processing/6359313/T6359313.java +++ b/test/langtools/tools/javac/processing/6359313/T6359313.java @@ -25,7 +25,7 @@ * @test * @bug 6359313 * @summary error compiling annotated package - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library /tools/javac/lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/processing/6413690/T6413690.java b/test/langtools/tools/javac/processing/6413690/T6413690.java index f0a01d599ef..b0945991bd2 100644 --- a/test/langtools/tools/javac/processing/6413690/T6413690.java +++ b/test/langtools/tools/javac/processing/6413690/T6413690.java @@ -25,7 +25,7 @@ * @test * @bug 6413690 6380018 * @summary JavacProcessingEnvironment does not enter trees from preceding rounds - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library /tools/javac/lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/processing/model/6194785/T6194785.java b/test/langtools/tools/javac/processing/model/6194785/T6194785.java index d053b9353dd..c8f09ba8c95 100644 --- a/test/langtools/tools/javac/processing/model/6194785/T6194785.java +++ b/test/langtools/tools/javac/processing/model/6194785/T6194785.java @@ -25,7 +25,7 @@ * @test * @bug 6194785 * @summary ParameterDeclaration.getSimpleName does not return actual name from class files - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library /tools/javac/lib * @modules java.compiler * jdk.compiler diff --git a/test/langtools/tools/javac/processing/model/testgetallmembers/Main.java b/test/langtools/tools/javac/processing/model/testgetallmembers/Main.java index 8310a403b14..4d35b9ae747 100644 --- a/test/langtools/tools/javac/processing/model/testgetallmembers/Main.java +++ b/test/langtools/tools/javac/processing/model/testgetallmembers/Main.java @@ -25,7 +25,7 @@ * @test * @bug 6374357 6308351 6707027 * @summary PackageElement.getEnclosedElements() throws ClassReader$BadClassFileException - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler/com.sun.tools.javac.model * @run main/othervm -Xmx512m Main */ diff --git a/test/langtools/tools/javac/processing/model/util/elements/overrides/S.java b/test/langtools/tools/javac/processing/model/util/elements/overrides/S.java new file mode 100644 index 00000000000..f6da3324acb --- /dev/null +++ b/test/langtools/tools/javac/processing/model/util/elements/overrides/S.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 models a few cases where Elements.overrides produces a false + * positive which warrants @apiNote. + */ + +// S.java does not compile because it violates the JLS rules for overrides +class S { + + public void m() { } +} + +// `protected` is a weaker modifier than `public` +class T1 extends S { + + protected void m() { } +} + +// `package-private` is a weaker modifier than `public` +class T2 extends S { + + void m() { } +} + +// `private` methods cannot override public method +class T3 extends S { + + private void m() { } +} + +// return type int is not compatible with void +class T4 extends S { + + public int m() { return 0; } +} + +// adding a checked exception violates the override rule +class T5 extends S { + + public void m() throws Exception { } +} diff --git a/test/langtools/tools/javac/processing/model/util/elements/overrides/TestOverrides.java b/test/langtools/tools/javac/processing/model/util/elements/overrides/TestOverrides.java new file mode 100644 index 00000000000..724dda1d482 --- /dev/null +++ b/test/langtools/tools/javac/processing/model/util/elements/overrides/TestOverrides.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8174840 + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor TestOverrides + * @compile -processor TestOverrides -proc:only S.java + */ + +import java.util.Set; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; + +import static javax.lang.model.element.ElementKind.METHOD; + +public class TestOverrides extends JavacTestingAbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment round) { + if (!round.processingOver()) { + var sm = mIn(elements.getTypeElement("S")); + for (var subtypeName : new String[]{"T1", "T2", "T3", "T4", "T5"}) { + var t = elements.getTypeElement(subtypeName); + var tm = mIn(t); + if (!elements.overrides(tm, sm, t)) + messager.printError(String.format( + "%s does not override from %s method %s", tm, t.getQualifiedName(), sm)); + } + } + return true; + } + + private ExecutableElement mIn(TypeElement t) { + return t.getEnclosedElements().stream() + .filter(e -> e.getKind() == METHOD) + .filter(e -> e.getSimpleName().toString().equals("m")) + .map(e -> (ExecutableElement) e) + .findAny() + .get(); + } +} diff --git a/test/langtools/tools/javac/processing/options/Xprint.java b/test/langtools/tools/javac/processing/options/Xprint.java index adf6c20e1ed..51df77afef9 100644 --- a/test/langtools/tools/javac/processing/options/Xprint.java +++ b/test/langtools/tools/javac/processing/options/Xprint.java @@ -25,7 +25,7 @@ * @test * @bug 6266828 * @summary JSR 269: Java Language Model API - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/processing/options/XprintTypeAnnotationsAndTypeVarBounds.java b/test/langtools/tools/javac/processing/options/XprintTypeAnnotationsAndTypeVarBounds.java new file mode 100644 index 00000000000..d81724763db --- /dev/null +++ b/test/langtools/tools/javac/processing/options/XprintTypeAnnotationsAndTypeVarBounds.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8356057 + * @summary Verify annotated supertypes and type variable bounds are printed properly + * @compile/ref=XprintTypeAnnotationsAndTypeVarBounds.out -Xprint XprintTypeAnnotationsAndTypeVarBounds.java + */ + +import java.lang.annotation.*; + +class AnnotatedObjectSuperType extends @TA Object { +} + +class UnannotatedObjectSuperType extends Object { +} + +class TypeVariableWithAnnotation1<@TA T> { +} + +class TypeVariableWithAnnotation2<@TA T extends Object> { +} + +class TypeVariableWithBound1 { +} + +class TypeVariableWithBound2 { +} + +class TypeVariableWithBound3 { +} + +class TypeVariableWithBound4 { +} + +class TypeVariableWithBound5 { +} + +class TypeVariableWithBound6 { +} + +class TypeVariableWithBoundRecursive> { +} + +class TypeVariableBoundsOnMethods { + public <@TA T> void test1() {} + public <@TA T extends Object> void test2() {} + public void test3() {} + public void test4() {} + public void test5() {} + public void test6() {} + public void test7() {} + public void test8() {} +} + +class TypeVariableBoundsOnConstructors { + public <@TA T> TypeVariableBoundsOnConstructors(boolean b) {} + public <@TA T extends Object> TypeVariableBoundsOnConstructors(byte b) {} + public TypeVariableBoundsOnConstructors(char c) {} + public TypeVariableBoundsOnConstructors(short s) {} + public TypeVariableBoundsOnConstructors(int i) {} + public TypeVariableBoundsOnConstructors(long l) {} + public TypeVariableBoundsOnConstructors(float f) {} + public TypeVariableBoundsOnConstructors(double d) {} +} + +@Target(ElementType.TYPE_USE) +@interface TA { +} diff --git a/test/langtools/tools/javac/processing/options/XprintTypeAnnotationsAndTypeVarBounds.out b/test/langtools/tools/javac/processing/options/XprintTypeAnnotationsAndTypeVarBounds.out new file mode 100644 index 00000000000..89c5c8747d0 --- /dev/null +++ b/test/langtools/tools/javac/processing/options/XprintTypeAnnotationsAndTypeVarBounds.out @@ -0,0 +1,99 @@ + +class AnnotatedObjectSuperType extends java.lang.@TA Object { + + AnnotatedObjectSuperType(); +} + +class UnannotatedObjectSuperType { + + UnannotatedObjectSuperType(); +} + +class TypeVariableWithAnnotation1<@TA T> { + + TypeVariableWithAnnotation1(); +} + +class TypeVariableWithAnnotation2<@TA T> { + + TypeVariableWithAnnotation2(); +} + +class TypeVariableWithBound1 { + + TypeVariableWithBound1(); +} + +class TypeVariableWithBound2 { + + TypeVariableWithBound2(); +} + +class TypeVariableWithBound3 { + + TypeVariableWithBound3(); +} + +class TypeVariableWithBound4 { + + TypeVariableWithBound4(); +} + +class TypeVariableWithBound5 { + + TypeVariableWithBound5(); +} + +class TypeVariableWithBound6 { + + TypeVariableWithBound6(); +} + +class TypeVariableWithBoundRecursive> { + + TypeVariableWithBoundRecursive(); +} + +class TypeVariableBoundsOnMethods { + + TypeVariableBoundsOnMethods(); + + public <@TA T> void test1(); + + public <@TA T> void test2(); + + public void test3(); + + public void test4(); + + public void test5(); + + public void test6(); + + public void test7(); + + public void test8(); +} + +class TypeVariableBoundsOnConstructors { + + public <@TA T> TypeVariableBoundsOnConstructors(boolean b); + + public <@TA T> TypeVariableBoundsOnConstructors(byte b); + + public TypeVariableBoundsOnConstructors(char c); + + public TypeVariableBoundsOnConstructors(short s); + + public TypeVariableBoundsOnConstructors(int i); + + public TypeVariableBoundsOnConstructors(long l); + + public TypeVariableBoundsOnConstructors(float f); + + public TypeVariableBoundsOnConstructors(double d); +} + +@java.lang.annotation.Target({TYPE_USE}) +@interface TA { +} \ No newline at end of file diff --git a/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out b/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out index 1840ca9205e..536ccc17754 100644 --- a/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out +++ b/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_1.out @@ -2,7 +2,7 @@ round: 1 round: 2 @java.lang.Deprecated -public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { public GeneratedSource(); @@ -12,7 +12,7 @@ public class GeneratedSource extends java.util.ArrayList im } @java.lang.Deprecated -public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { public GeneratedClass(); @@ -23,7 +23,7 @@ public class GeneratedClass extends java.util.ArrayList imp round: 3 @java.lang.Deprecated -public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { public GeneratedSource(); @@ -33,7 +33,7 @@ public class GeneratedSource extends java.util.ArrayList im } @java.lang.Deprecated -public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { public GeneratedClass(); diff --git a/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out b/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out index d1bf374bb74..826e2b4bcb0 100644 --- a/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out +++ b/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_2.out @@ -1,7 +1,7 @@ round: 1 @java.lang.Deprecated -public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { public GeneratedSource(); @@ -11,7 +11,7 @@ public class GeneratedSource extends java.util.ArrayList im } @java.lang.Deprecated -public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { public GeneratedClass(); @@ -22,7 +22,7 @@ public class GeneratedClass extends java.util.ArrayList imp round: 2 @javax.annotation.processing.SupportedAnnotationTypes({"*"}) -public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { +public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { public GeneratedSource(); @@ -30,7 +30,7 @@ public abstract class GeneratedSource extends java.util.LinkedList extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { +public abstract class GeneratedClass extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { public GeneratedClass(); @@ -39,7 +39,7 @@ public abstract class GeneratedClass extends java.util.LinkedList extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { +public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { public GeneratedSource(); @@ -47,7 +47,7 @@ public abstract class GeneratedSource extends java.util.LinkedList extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { +public abstract class GeneratedClass extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { public GeneratedClass(); diff --git a/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out b/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out index 39b044ec78a..1831303304a 100644 --- a/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out +++ b/test/langtools/tools/javac/processing/rounds/OverwriteBetweenCompilations_3.out @@ -1,7 +1,7 @@ round: 1 @javax.annotation.processing.SupportedAnnotationTypes({"*"}) -public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { +public abstract class GeneratedSource extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { public GeneratedSource(); @@ -9,7 +9,7 @@ public abstract class GeneratedSource extends java.util.LinkedList extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { +public abstract class GeneratedClass extends java.util.LinkedList implements java.lang.Runnable, java.lang.CharSequence { public GeneratedClass(); @@ -18,7 +18,7 @@ public abstract class GeneratedClass extends java.util.LinkedList extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { public GeneratedSource(); @@ -28,7 +28,7 @@ public class GeneratedSource extends java.util.ArrayList im } @java.lang.Deprecated -public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { public GeneratedClass(); @@ -39,7 +39,7 @@ public class GeneratedClass extends java.util.ArrayList imp round: 3 @java.lang.Deprecated -public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedSource extends java.util.ArrayList implements java.lang.Runnable { public GeneratedSource(); @@ -49,7 +49,7 @@ public class GeneratedSource extends java.util.ArrayList im } @java.lang.Deprecated -public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { +public class GeneratedClass extends java.util.ArrayList implements java.lang.Runnable { public GeneratedClass(); diff --git a/test/langtools/tools/javac/scope/6225935/T6214959.java b/test/langtools/tools/javac/scope/6225935/T6214959.java index 96a9478f33c..6130a04cc96 100644 --- a/test/langtools/tools/javac/scope/6225935/T6214959.java +++ b/test/langtools/tools/javac/scope/6225935/T6214959.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 6214959 * @summary Compiler fails to produce error message with ODD number of import static - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile/fail/ref=T6214959.out -XDrawDiagnostics T6214959.java */ diff --git a/test/langtools/tools/javac/scope/6225935/T6225935.java b/test/langtools/tools/javac/scope/6225935/T6225935.java index 4e6e5272c53..555293ca030 100644 --- a/test/langtools/tools/javac/scope/6225935/T6225935.java +++ b/test/langtools/tools/javac/scope/6225935/T6225935.java @@ -25,7 +25,7 @@ * @test * @bug 6225935 * @summary "import static" accessibility rules for symbols different for no reason - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile a/Private.java a/Named.java a/Star.java T6225935.java * @run main/othervm T6225935 */ diff --git a/test/langtools/tools/javac/scope/6225935/T6381787.java b/test/langtools/tools/javac/scope/6225935/T6381787.java index 1e989950d75..7a658b9e5f8 100644 --- a/test/langtools/tools/javac/scope/6225935/T6381787.java +++ b/test/langtools/tools/javac/scope/6225935/T6381787.java @@ -25,7 +25,7 @@ * @test * @bug 6381787 * @summary Failing Japanese Calendar regression tests - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6381787.java */ diff --git a/test/langtools/tools/javac/scope/6225935/Test.java b/test/langtools/tools/javac/scope/6225935/Test.java index a77c8eebd0c..1efc260c1fc 100644 --- a/test/langtools/tools/javac/scope/6225935/Test.java +++ b/test/langtools/tools/javac/scope/6225935/Test.java @@ -25,7 +25,7 @@ * @test * @bug 6381787 * @summary Failing Japanese Calendar regression tests - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile Test.java Bar.java Baz.java */ diff --git a/test/langtools/tools/javac/scope/6392998/T6392998.java b/test/langtools/tools/javac/scope/6392998/T6392998.java index 82f188d6391..353d9d56233 100644 --- a/test/langtools/tools/javac/scope/6392998/T6392998.java +++ b/test/langtools/tools/javac/scope/6392998/T6392998.java @@ -25,7 +25,7 @@ * @test * @bug 6392998 * @summary Mustang compiler throws AssertionError (beta2-b71 and higher) - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile T6392998.java */ diff --git a/test/langtools/tools/javac/sealed/SealedCompilationTests.java b/test/langtools/tools/javac/sealed/SealedCompilationTests.java index 7cf63f5b2d5..17141ee3c67 100644 --- a/test/langtools/tools/javac/sealed/SealedCompilationTests.java +++ b/test/langtools/tools/javac/sealed/SealedCompilationTests.java @@ -25,7 +25,7 @@ * SealedCompilationTests * * @test - * @bug 8246353 8273257 8294550 8347562 + * @bug 8246353 8273257 8294550 8347562 8344706 * @summary Negative compilation tests, and positive compilation (smoke) tests for sealed classes * @library /lib/combo /tools/lib * @modules @@ -781,7 +781,7 @@ sealed class C permits Sub {} non/**/sealed class Sub extends C {} """ )) { - assertFail("compiler.err.expected4", s); + assertFail("compiler.err.class.method.or.field.expected", s); } } @@ -985,7 +985,7 @@ void testDoNotAllowSealedAnnotation() { non-sealed interface I extends A {} """ )) { - assertFail("compiler.err.expected4", s); + assertFail("compiler.err.class.method.or.field.expected", s); } } diff --git a/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java b/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java index 30fc23922bb..ddadec7d862 100644 --- a/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java +++ b/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java @@ -556,7 +556,7 @@ public void testSameModuleSamePkgNeg2(Path base) throws Exception { .getOutputLines(OutputKind.DIRECT); List expected = List.of( - "Sealed.java:1:66: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.extend.sealed: pkg.Sub2)", + "Sealed.java:1:66: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.implement.sealed: kindname.class, pkg.Sub2)", "1 error"); if (!error.containsAll(expected)) { throw new AssertionError("Expected output not found. Found: " + error); diff --git a/test/langtools/tools/javac/sealed/erroneous_hierarchy/CyclicHierarchyTest.out b/test/langtools/tools/javac/sealed/erroneous_hierarchy/CyclicHierarchyTest.out index c9420a0dc09..b919e8cce3a 100644 --- a/test/langtools/tools/javac/sealed/erroneous_hierarchy/CyclicHierarchyTest.out +++ b/test/langtools/tools/javac/sealed/erroneous_hierarchy/CyclicHierarchyTest.out @@ -1,3 +1,3 @@ -CyclicHierarchyTest.java:9:37: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.extend.sealed: CyclicHierarchyTest.Add) +CyclicHierarchyTest.java:9:37: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.implement.sealed: kindname.class, CyclicHierarchyTest.Add) CyclicHierarchyTest.java:11:55: compiler.err.invalid.permits.clause: (compiler.misc.must.not.be.same.class) 2 errors diff --git a/test/langtools/tools/javac/BranchToFewerDefines.java b/test/langtools/tools/javac/stackmap/BranchToFewerDefines.java similarity index 97% rename from test/langtools/tools/javac/BranchToFewerDefines.java rename to test/langtools/tools/javac/stackmap/BranchToFewerDefines.java index dabdff64d32..7a0c69e4ae5 100644 --- a/test/langtools/tools/javac/BranchToFewerDefines.java +++ b/test/langtools/tools/javac/stackmap/BranchToFewerDefines.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8067429 + * @bug 8067429 8332934 * @summary java.lang.VerifyError: Inconsistent stackmap frames at branch target * @author srikanth * diff --git a/test/langtools/tools/javac/stackmap/DoLoopLocalEscapeThroughContinueTest.java b/test/langtools/tools/javac/stackmap/DoLoopLocalEscapeThroughContinueTest.java new file mode 100644 index 00000000000..dbc73ca73c0 --- /dev/null +++ b/test/langtools/tools/javac/stackmap/DoLoopLocalEscapeThroughContinueTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8332934 + * @summary Incorrect defined locals escaped from continue in do loop + * @library /tools/lib /test/lib + * @run main DoLoopLocalEscapeThroughContinueTest + */ + +import jdk.test.lib.ByteCodeLoader; +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +import java.lang.classfile.ClassFile; +import java.lang.invoke.MethodHandles; + +public class DoLoopLocalEscapeThroughContinueTest { + public static void main(String... args) throws Throwable { + String source = """ + static void main(String[] k) { + do { + int b = 1; + continue; + } while (Math.random() > 0.5D) ; + switch (2) { + case 3: + double d; + case 4: + k.toString(); + } + } + """; + var bytes = InMemoryJavaCompiler.compile("Test", source, "-XDdebug.code"); + System.out.println(ClassFile.of().parse(bytes).toDebugString()); + var clz = ByteCodeLoader.load("Test", bytes); + MethodHandles.privateLookupIn(clz, MethodHandles.lookup()).ensureInitialized(clz); // force verification + } +} diff --git a/test/langtools/tools/javac/SwitchExitStateTest.java b/test/langtools/tools/javac/stackmap/SwitchExitStateTest.java similarity index 93% rename from test/langtools/tools/javac/SwitchExitStateTest.java rename to test/langtools/tools/javac/stackmap/SwitchExitStateTest.java index 4b9e0d61e07..74b443a5803 100644 --- a/test/langtools/tools/javac/SwitchExitStateTest.java +++ b/test/langtools/tools/javac/stackmap/SwitchExitStateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8160699 + * @bug 8160699 8332934 * @summary Verify that having finished executing a switch statement live locals are exactly the same as it was upon entry of the switch. * @run main SwitchExitStateTest */ diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugsInGen.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugsInGen.java index c0ec0511ecc..28e8518a5a0 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugsInGen.java +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugsInGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,12 +23,14 @@ /* * @test - * @bug 8214031 + * @bug 8214031 8357361 * @summary Verify various corner cases with nested switch expressions. * @compile ExpressionSwitchBugsInGen.java * @run main ExpressionSwitchBugsInGen */ +import java.util.Objects; + public class ExpressionSwitchBugsInGen { public static void main(String... args) { new ExpressionSwitchBugsInGen().test(0, 0, 0, false); @@ -43,6 +45,8 @@ public static void main(String... args) { new ExpressionSwitchBugsInGen().testSwitchExpressionInConditional(1, 1, 1); new ExpressionSwitchBugsInGen().testIntBoxing(0, 10, 10); new ExpressionSwitchBugsInGen().testIntBoxing(1, 10, -1); + new ExpressionSwitchBugsInGen().testSwitchExpressionTypeErased(0); + new ExpressionSwitchBugsInGen().testSwitchExpressionTypeErased(1); } private void test(int a, int b, int c, boolean expected) { @@ -91,4 +95,21 @@ private void testIntBoxing(int a, Integer res, int expected) { } } + //JDK-8357361: + private void testSwitchExpressionTypeErased(int i) { + interface Readable { + R getReader(); + } + Readable readable = () -> ""; + var v = switch (i) { + case 0 -> readable.getReader(); + default -> null; + }; + var expected = i == 0 ? "" : null; + if (!Objects.equals(v, expected)) { + throw new IllegalStateException("Expected: " + expected + + ", got: " + v); + } + } + } diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitchEmbedding.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitchEmbedding.java index 7f8a9c06e17..1e652eb2119 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchEmbedding.java +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchEmbedding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8214031 8214114 8236546 + * @bug 8214031 8214114 8236546 8353565 * @summary Verify switch expressions embedded in various statements work properly. * @compile ExpressionSwitchEmbedding.java * @run main ExpressionSwitchEmbedding @@ -32,6 +32,7 @@ public class ExpressionSwitchEmbedding { public static void main(String... args) { new ExpressionSwitchEmbedding().run(); + new ExpressionSwitchEmbedding().runStackMapMergingTest(); } private void run() { @@ -330,6 +331,110 @@ yield switch (i) { } } + private void runStackMapMergingTest() { + //JDK-8353565: verify that two types neither of which is a subtype of the other + //can be merged while computing StackMaps. + if (!(computeTypeAtMergePoint1(E.A, E.A) instanceof Impl1a)) { + throw new AssertionError("Unexpected result"); + } + if (runMethodForInterfaceTypeAtMergePoint1(E.A, E.A) != 1) { + throw new AssertionError("Unexpected result"); + } + if (runMethodForInterfaceTypeAtMergePoint2(E.A, E.A) != 2) { + throw new AssertionError("Unexpected result"); + } + } + + private Root computeTypeAtMergePoint1(E e1, E e2) { + return (Root) switch (e1) { + case A -> switch (e2) { + case A -> new Impl1a(); + case B -> new Impl1b(); + case C -> new Impl1c(); + }; + case B -> switch (e2) { + case A -> new Impl2a(); + case B -> new Impl2b(); + case C -> new Impl2c(); + }; + case C -> switch (e2) { + case A -> new Impl3a(); + case B -> new Impl3b(); + case C -> new Impl3c(); + }; + }; + } + + private int runMethodForInterfaceTypeAtMergePoint1(E e1, E e2) { + return (switch (e1) { + case A -> switch (e2) { + case A -> new C1(); + case B -> new C1(); + case C -> new C1(); + }; + case B -> switch (e2) { + case A -> new C2(); + case B -> new C2(); + case C -> new C2(); + }; + case C -> switch (e2) { + case A -> new C3(); + case B -> new C3(); + case C -> new C3(); + }; + }).test1(); + } + + private int runMethodForInterfaceTypeAtMergePoint2(E e1, E e2) { + return (switch (e1) { + case A -> switch (e2) { + case A -> new C1(); + case B -> new C1(); + case C -> new C1(); + }; + case B -> switch (e2) { + case A -> new C2(); + case B -> new C2(); + case C -> new C2(); + }; + case C -> switch (e2) { + case A -> new C3(); + case B -> new C3(); + case C -> new C3(); + }; + }).test2(); + } + + private static class Root {} + private static class Base1 extends Root {} + private static class Impl1a extends Base1 {} + private static class Impl1b extends Base1 {} + private static class Impl1c extends Base1 {} + private static class Base2 extends Root {} + private static class Impl2a extends Base2 {} + private static class Impl2b extends Base2 {} + private static class Impl2c extends Base2 {} + private static class Base3 extends Root {} + private static class Impl3a extends Base3 {} + private static class Impl3b extends Base3 {} + private static class Impl3c extends Base3 {} + + private static interface RootInterface1 { + public default int test1() { + return 1; + } + } + private static interface RootInterface2 { + public default int test2() { + return 2; + } + } + private static class C1 implements RootInterface1, RootInterface2 {} + private static class C2 implements RootInterface1, RootInterface2 {} + private static class C3 implements RootInterface1, RootInterface2 {} + + enum E {A, B, C;} + private void throwException() { throw new RuntimeException(); } diff --git a/test/langtools/tools/javac/tree/TreePosTest.java b/test/langtools/tools/javac/tree/TreePosTest.java index add1db72e29..0ae62ca940d 100644 --- a/test/langtools/tools/javac/tree/TreePosTest.java +++ b/test/langtools/tools/javac/tree/TreePosTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,7 +78,10 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCAnnotatedType; import com.sun.tools.javac.tree.JCTree.JCCase; +import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCImport; +import com.sun.tools.javac.tree.JCTree.JCImportBase; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCNewClass; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -87,6 +90,7 @@ import static com.sun.tools.javac.tree.JCTree.Tag.*; import static com.sun.tools.javac.util.Position.NOPOS; +import java.util.stream.Stream; /** * Utility and test program to check validity of tree positions for tree nodes. @@ -102,7 +106,7 @@ /* * @test - * @bug 6919889 + * @bug 6919889 8344706 * @summary assorted position errors in compiler syntax trees * OLD: -q -r -ef ./tools/javac/typeAnnotations -ef ./tools/javap/typeAnnotations -et ANNOTATED_TYPE . * @modules java.desktop @@ -342,10 +346,18 @@ private static String getTagName(JCTree.Tag tag) { * Main class for testing assertions concerning tree positions for tree nodes. */ private class PosTester extends TreeScanner { + private boolean compactSourceFile; void test(JCCompilationUnit tree) { sourcefile = tree.sourcefile; endPosTable = tree.endPositions; encl = new Info(); + List nonImports = tree.defs + .stream() + .filter(t -> !(t instanceof JCImportBase)) + .toList(); + compactSourceFile = nonImports.size() == 1 && + nonImports.get(0) instanceof JCClassDecl classDecl && + tree.endPositions.getEndPos(classDecl) == NOPOS; tree.accept(this); } @@ -369,7 +381,12 @@ public void scan(JCTree tree) { // For this node, start , pos, and endpos should be all defined check("start != NOPOS", encl, self, self.start != NOPOS); check("pos != NOPOS", encl, self, self.pos != NOPOS); - check("end != NOPOS", encl, self, self.end != NOPOS); + boolean topLevelCompactClass = compactSourceFile && + encl.tree == null && + self.tag == CLASSDEF; + if (!topLevelCompactClass) { + check("end != NOPOS", encl, self, self.end != NOPOS); + } // The following should normally be ordered // encl.start <= start <= pos <= end <= encl.end // In addition, the position of the enclosing node should be @@ -398,12 +415,14 @@ public void scan(JCTree tree) { check("encl.pos <= start || end <= encl.pos", encl, self, encl.pos <= self.start || self.end <= encl.pos); } - check("pos <= end", encl, self, self.pos <= self.end); + if (!topLevelCompactClass) { + check("pos <= end", encl, self, self.pos <= self.end); + } if (!( (self.tag == TYPEARRAY || isAnnotatedArray(self.tree)) && (encl.tag == TYPEARRAY || isAnnotatedArray(encl.tree)) || encl.tag == MODIFIERS && self.tag == ANNOTATION - ) ) { + ) && !compactSourceFile) { check("end <= encl.end", encl, self, self.end <= encl.end); } } diff --git a/test/langtools/tools/javac/tree/VarWarnPosition.java b/test/langtools/tools/javac/tree/VarWarnPosition.java new file mode 100644 index 00000000000..7dae84f3542 --- /dev/null +++ b/test/langtools/tools/javac/tree/VarWarnPosition.java @@ -0,0 +1,29 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8329951 + * @summary Check that "var" variable synthetic types have a source position + * @compile/process/ref=VarWarnPosition.out -Xlint:deprecation -XDrawDiagnostics VarWarnPosition.java + */ + +import java.util.*; +import java.util.function.*; + +public class VarWarnPosition { + + VarWarnPosition() { + + // Test 1 + @SuppressWarnings("deprecation") + List deprecatedList = null; + for (var deprValue : deprecatedList) { } + + // Test 2 + Consumer c = d -> { }; + + // Test 3 + Consumer c2 = (var d) -> { }; + } +} + +@Deprecated +class Depr {} diff --git a/test/langtools/tools/javac/tree/VarWarnPosition.out b/test/langtools/tools/javac/tree/VarWarnPosition.out new file mode 100644 index 00000000000..2200c8b4ae0 --- /dev/null +++ b/test/langtools/tools/javac/tree/VarWarnPosition.out @@ -0,0 +1,6 @@ +VarWarnPosition.java:18:14: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package +VarWarnPosition.java:21:18: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package +VarWarnPosition.java:21:28: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package +VarWarnPosition.java:24:18: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package +VarWarnPosition.java:24:30: compiler.warn.has.been.deprecated: Depr, compiler.misc.unnamed.package +5 warnings diff --git a/test/langtools/tools/javac/unicode/FirstChar.java b/test/langtools/tools/javac/unicode/FirstChar.java index 9e7bf473907..261538ab91b 100644 --- a/test/langtools/tools/javac/unicode/FirstChar.java +++ b/test/langtools/tools/javac/unicode/FirstChar.java @@ -25,7 +25,7 @@ * @test * @bug 5099360 * @summary allow unicode escape at start of program - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @compile FirstChar2.java * @run main FirstChar2 */ diff --git a/test/langtools/tools/javac/unit/T6198196.java b/test/langtools/tools/javac/unit/T6198196.java index 6c67c513584..3c75cc34477 100644 --- a/test/langtools/tools/javac/unit/T6198196.java +++ b/test/langtools/tools/javac/unit/T6198196.java @@ -25,7 +25,7 @@ * @test * @bug 6198196 6278523 * @summary package-info.java: Weird compiler error - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules java.compiler * jdk.compiler */ diff --git a/test/langtools/tools/javac/unit/util/convert/EnclosingCandidates.java b/test/langtools/tools/javac/unit/util/convert/EnclosingCandidates.java index 02f7161da03..7a96872f663 100644 --- a/test/langtools/tools/javac/unit/util/convert/EnclosingCandidates.java +++ b/test/langtools/tools/javac/unit/util/convert/EnclosingCandidates.java @@ -25,7 +25,7 @@ * @test * @bug 6397652 * @summary javac compilation failure when imported class with $ sign in the name - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler/com.sun.tools.javac.util */ diff --git a/test/langtools/tools/javac/unit/util/list/AbstractList.java b/test/langtools/tools/javac/unit/util/list/AbstractList.java index daf80486853..38cdd7c5e78 100644 --- a/test/langtools/tools/javac/unit/util/list/AbstractList.java +++ b/test/langtools/tools/javac/unit/util/list/AbstractList.java @@ -25,7 +25,7 @@ * @test * @bug 6320536 * @summary com.sun.tools.javac.util.List.from(A[]) shouldn't be deprecated - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../.. * @modules jdk.compiler/com.sun.tools.javac.util * @compile ../../util/list/AbstractList.java diff --git a/test/langtools/tools/javac/unit/util/list/FromArray.java b/test/langtools/tools/javac/unit/util/list/FromArray.java index 5a4b05fce93..eabdb71e148 100644 --- a/test/langtools/tools/javac/unit/util/list/FromArray.java +++ b/test/langtools/tools/javac/unit/util/list/FromArray.java @@ -25,7 +25,7 @@ * @test * @bug 6289436 * @summary com.sun.tools.javac.util.List.from(A[]) shouldn't be deprecated - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @library ../.. * @modules jdk.compiler/com.sun.tools.javac.util * @compile ../../util/list/FromArray.java diff --git a/test/langtools/tools/javac/util/filemanager/TestName.java b/test/langtools/tools/javac/util/filemanager/TestName.java index cb8c77dda93..23bb2b9c781 100644 --- a/test/langtools/tools/javac/util/filemanager/TestName.java +++ b/test/langtools/tools/javac/util/filemanager/TestName.java @@ -26,7 +26,7 @@ * @bug 6409829 * @summary JSR 199: enforce the use of valid package and class names * in get{Java,}FileFor{Input,Output} - * @author Peter von der Ah\u00e9 + * @author Peter von der Ahé * @modules jdk.compiler/com.sun.tools.javac.file */ diff --git a/test/langtools/tools/javac/varargs/Warn1.java b/test/langtools/tools/javac/varargs/Warn1.java index eb5758d9a23..f65c2f9bc73 100644 --- a/test/langtools/tools/javac/varargs/Warn1.java +++ b/test/langtools/tools/javac/varargs/Warn1.java @@ -6,7 +6,7 @@ * * @compile Warn1.java * @compile/ref=Warn1.out -XDrawDiagnostics Warn1.java - * @compile -Werror -Xlint:none Warn1.java + * @compile -Werror -nowarn Warn1.java */ package varargs.warn1; diff --git a/test/langtools/tools/javac/varargs/Warn2.java b/test/langtools/tools/javac/varargs/Warn2.java index 9ba8b8f8832..6d411f31f57 100644 --- a/test/langtools/tools/javac/varargs/Warn2.java +++ b/test/langtools/tools/javac/varargs/Warn2.java @@ -6,7 +6,7 @@ * * @compile Warn2.java * @compile/fail/ref=Warn2.out -XDrawDiagnostics -Werror Warn2.java - * @compile -Werror -Xlint:none Warn2.java + * @compile -Werror -nowarn Warn2.java */ package varargs.warn2; diff --git a/test/langtools/tools/javac/versions/Versions.java b/test/langtools/tools/javac/versions/Versions.java index 6d885a55972..43fcb0353d0 100644 --- a/test/langtools/tools/javac/versions/Versions.java +++ b/test/langtools/tools/javac/versions/Versions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @bug 4981566 5028634 5094412 6304984 7025786 7025789 8001112 8028545 * 8000961 8030610 8028546 8188870 8173382 8173382 8193290 8205619 8028563 * 8245147 8245586 8257453 8286035 8306586 8320806 8306586 8319414 8330183 - * 8342982 + * 8342982 8355748 8356108 * @summary Check interpretation of -target and -source options * @modules java.compiler * jdk.compiler @@ -73,9 +73,9 @@ public static void main(String... args) throws IOException { public static final Set VALID_SOURCES = Set.of("1.8", "1.9", "1.10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", - "23", "24", "25"); + "23", "24", "25", "26"); - public static final String LATEST_MAJOR_VERSION = "69.0"; + public static final String LATEST_MAJOR_VERSION = "70.0"; static enum SourceTarget { EIGHT(true, "52.0", "8"), @@ -96,6 +96,7 @@ static enum SourceTarget { TWENTY_THREE(false,"67.0", "23"), TWENTY_FOUR(false,"68.0", "24"), TWENTY_FIVE(false,"69.0", "25"), + TWENTY_SIX(false, "70.0", "26"), ; // Reduce code churn when appending new constants private final boolean dotOne; @@ -403,6 +404,14 @@ public static void main(String... args) { } } """), + + SOURCE_25(25, "New25.java", + // New feature in 25: module import declarations + """ + import module java.base; + public class New25 { + } + """), ; // Reduce code churn when appending new constants private int sourceLevel; @@ -558,4 +567,3 @@ protected void genSourceFiles() throws IOException{ return false; } } - diff --git a/test/langtools/tools/javac/warnings/ThisEscape.java b/test/langtools/tools/javac/warnings/ThisEscape.java index 93ccb6e0830..f9280b5b1ae 100644 --- a/test/langtools/tools/javac/warnings/ThisEscape.java +++ b/test/langtools/tools/javac/warnings/ThisEscape.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8015831 + * @bug 8015831 8355753 * @compile/ref=ThisEscape.out -Xlint:this-escape -XDrawDiagnostics ThisEscape.java * @summary Verify 'this' escape detection */ @@ -765,4 +765,53 @@ private Object getObject() { return this.obj; } } + + // JDK-8355753 - @SuppressWarnings("this-escape") not respected for indirect leak via field + public static class SuppressedIndirectLeakViaField { + + private final int x = this.mightLeak(); // this leak should be suppressed + private int y; + + { + y = this.mightLeak(); // this leak should be suppressed + } + + public SuppressedIndirectLeakViaField() { + this(""); + } + + @SuppressWarnings("this-escape") + private SuppressedIndirectLeakViaField(String s) { + } + + public int mightLeak() { + return 0; + } + } + + public static class UnsuppressedIndirectLeakViaField { + + private final int x = this.mightLeak(); // this leak should not be suppressed + + public UnsuppressedIndirectLeakViaField() { + this(""); // this constructor does not trigger the warning + } + + @SuppressWarnings("this-escape") + private UnsuppressedIndirectLeakViaField(String s) { + // this constructor does not trigger the warning (obviously; it's directly suppressed) + } + + public UnsuppressedIndirectLeakViaField(int z) { + // this constructor triggers the warning + } + + public UnsuppressedIndirectLeakViaField(float z) { + // this constructor also triggers the warning, but should not create a duplicate + } + + public int mightLeak() { + return 0; + } + } } diff --git a/test/langtools/tools/javac/warnings/ThisEscape.out b/test/langtools/tools/javac/warnings/ThisEscape.out index a444c2828b7..b866c4a7731 100644 --- a/test/langtools/tools/javac/warnings/ThisEscape.out +++ b/test/langtools/tools/javac/warnings/ThisEscape.out @@ -35,4 +35,5 @@ ThisEscape.java:652:55: compiler.warn.possible.this.escape ThisEscape.java:672:18: compiler.warn.possible.this.escape ThisEscape.java:669:48: compiler.warn.possible.this.escape.location ThisEscape.java:726:32: compiler.warn.possible.this.escape -37 warnings +ThisEscape.java:794:45: compiler.warn.possible.this.escape +38 warnings diff --git a/test/langtools/tools/javap/ClassFileVersionTest.java b/test/langtools/tools/javap/ClassFileVersionTest.java new file mode 100644 index 00000000000..c5968dfd84e --- /dev/null +++ b/test/langtools/tools/javap/ClassFileVersionTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8358078 + * @summary javap should not crash due to class file versions + * @library /tools/lib + * @modules jdk.jdeps/com.sun.tools.javap + * @run junit ClassFileVersionTest + */ + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import toolbox.JavapTask; +import toolbox.Task; +import toolbox.ToolBox; + +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.reflect.AccessFlag; +import java.lang.reflect.ClassFileFormatVersion; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.params.provider.Arguments.of; + +public class ClassFileVersionTest { + + final ToolBox toolBox = new ToolBox(); + + public static Stream classFiles() { + int major17 = ClassFileFormatVersion.RELEASE_17.major(); + int preview = Character.MAX_VALUE; + int majorLatest = ClassFileFormatVersion.latest().major(); + AccessFlag[] noFlags = {}; + return Stream.of( + of(false, major17, 0, noFlags), + of(false, major17, preview, noFlags), + of(false, 0, 0, noFlags), + of(false, major17, 0, new AccessFlag[]{AccessFlag.PUBLIC}), + of(false, major17, preview, new AccessFlag[]{AccessFlag.PUBLIC}), + of(false, majorLatest, preview, new AccessFlag[]{AccessFlag.PUBLIC}), + of(true, majorLatest, 0, new AccessFlag[]{AccessFlag.BRIDGE}), // misplaced access flag + of(true, majorLatest, preview, new AccessFlag[]{AccessFlag.BRIDGE}) // misplaced access flag + ); + } + + private static byte[] createClassFile(int major, int minor, AccessFlag[] classFlags) { + return ClassFile.of().build(ClassDesc.of("Test"), (builder) -> { + // manually assemble flag bits to avoid exception in ClassFile api + int flags = 0; + for (AccessFlag classFlag : classFlags) { + flags |= classFlag.mask(); + } + builder.withVersion(major, minor).withFlags(flags); + }); + } + + @ParameterizedTest + @MethodSource("classFiles") + void test(boolean shouldError, int major, int minor, AccessFlag[] classFlags) throws Throwable { + + Files.write(Path.of("cf.class"), createClassFile(major, minor, classFlags)); + + var lines = new JavapTask(toolBox) + .classes("cf.class") + .options("-c", "-p", "-v") + .run(shouldError ? Task.Expect.FAIL : Task.Expect.SUCCESS) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + assertEquals(shouldError, lines.stream().anyMatch(l -> l.startsWith("Error: Access Flags:")), "printed error"); + } +} diff --git a/test/langtools/tools/javap/UndefinedAccessFlagTest.java b/test/langtools/tools/javap/UndefinedAccessFlagTest.java index ab63dbddce8..682483223ae 100644 --- a/test/langtools/tools/javap/UndefinedAccessFlagTest.java +++ b/test/langtools/tools/javap/UndefinedAccessFlagTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,8 @@ */ /* - * @test 8333748 + * @test + * @bug 8333748 8349536 * @summary javap should not fail if reserved access flag bits are set to 1 * @library /tools/lib * @modules jdk.jdeps/com.sun.tools.javap @@ -91,7 +92,7 @@ void test(TestLocation location) throws Throwable { }); case InnerClassesAttribute attr when location == TestLocation.INNER_CLASS -> cb .with(InnerClassesAttribute.of(attr.classes().stream() - .map(ic -> InnerClassInfo.of(ic.innerClass(), ic.outerClass(), ic.innerName(), ic.flagsMask() | 0x0020)) + .map(ic -> InnerClassInfo.of(ic.innerClass(), ic.outerClass(), ic.innerName(), ic.flagsMask() | ACC_SUPER)) .toList())); default -> cb.with(ce); } diff --git a/test/langtools/tools/jdeps/MalformedClassesTest.java b/test/langtools/tools/jdeps/MalformedClassesTest.java new file mode 100644 index 00000000000..baa94ad78e2 --- /dev/null +++ b/test/langtools/tools/jdeps/MalformedClassesTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8341608 + * @summary Tests for jdeps tool with jar files with malformed classes + * @library lib /test/lib + * @build jdk.jdeps/com.sun.tools.jdeps.* + * @run junit MalformedClassesTest + */ + +import java.io.IOException; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassTransform; +import java.lang.classfile.attribute.SignatureAttribute; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import com.sun.tools.jdeps.JdepsAccess; +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class MalformedClassesTest { + + static Stream invalidArchives() throws Exception { + var jarPath = Path.of("malformed-signature.jar"); + var compiledClasses = InMemoryJavaCompiler.compile(Map.ofEntries( + Map.entry("one.One", """ + package one; + + import java.util.Optional; + + class One { + Optional st = Optional.empty(); + } + """), + Map.entry("two.Two", """ + package two; + + import java.lang.invoke.*; + + class Two { + int i; + static final VarHandle I; + + static { + try { + I = MethodHandles.lookup().findVarHandle(Two.class, "i", int.class); + } catch (ReflectiveOperationException ex) { + throw new ExceptionInInitializerError(ex); + } + } + } + """) + )); + var updated = ClassFile.of().transformClass(ClassFile.of().parse(compiledClasses.get("one.One")), + ClassTransform.transformingFields((fb, fe) -> { + if (fe instanceof SignatureAttribute) { + fb.with(SignatureAttribute.of(fb.constantPool().utf8Entry("Invalid string"))); + } else { + fb.with(fe); + } + })); + var classes = new HashMap<>(compiledClasses); + classes.put("one.One", updated); + JarUtils.createJarFromClasses(jarPath, classes); + + Path flatDir = Path.of("flatDir"); + Files.createDirectories(flatDir); + for (var entry : classes.entrySet()) { + ClassFileInstaller.writeClassToDisk(entry.getKey(), entry.getValue(), flatDir.toString()); + } + + return Stream.of( + Arguments.of("directory", flatDir, "One.class"), + Arguments.of("jar", jarPath, "one/One.class (malformed-signature.jar)") + ); + } + + @ParameterizedTest + @MethodSource("invalidArchives") + public void testMalformedSignature(String kind, Path path, String entryName) throws IOException { + try (var jdeps = JdepsUtil.newCommand("jdeps")) { + jdeps.addRoot(path); + var analyzer = jdeps.getDepsAnalyzer(); + analyzer.run(); + var archives = JdepsAccess.depsAnalyzerArchives(analyzer); + assertEquals(1, archives.size(), archives::toString); + var archive = archives.iterator().next(); + var skippedEntries = archive.reader().skippedEntries(); + assertEquals(1, skippedEntries.size(), skippedEntries::toString); + var message = skippedEntries.getFirst(); + assertTrue(message.contains("ClassFileError"), message); + assertTrue(message.contains("Invalid string"), message); + assertTrue(message.contains(entryName), "\"" + message + "\" does not contain \"" + entryName + "\""); + } + } +} diff --git a/test/langtools/tools/jdeps/TEST.properties b/test/langtools/tools/jdeps/TEST.properties new file mode 100644 index 00000000000..56b5043d3c1 --- /dev/null +++ b/test/langtools/tools/jdeps/TEST.properties @@ -0,0 +1,2 @@ +modules = \ + jdk.jdeps/com.sun.tools.jdeps diff --git a/test/langtools/tools/jdeps/jdk.jdeps/com/sun/tools/jdeps/JdepsAccess.java b/test/langtools/tools/jdeps/jdk.jdeps/com/sun/tools/jdeps/JdepsAccess.java new file mode 100644 index 00000000000..16229153e13 --- /dev/null +++ b/test/langtools/tools/jdeps/jdk.jdeps/com/sun/tools/jdeps/JdepsAccess.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact 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.tools.jdeps; + +import java.util.Set; + +public final class JdepsAccess { + public static Set depsAnalyzerArchives(DepsAnalyzer analyzer) { + return analyzer.archives; + } + + private JdepsAccess() {} +} diff --git a/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java b/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java index b3f81ca1e1e..52db62dd41a 100644 --- a/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java +++ b/test/langtools/tools/jdeps/listdeps/ListModuleDeps.java @@ -92,7 +92,6 @@ public void compileAll() throws Exception { public Object[][] jdkModules() { return new Object[][]{ {"jdk.compiler", new String[]{ - "java.base/jdk.internal.javac", "java.base/jdk.internal.jmod", "java.base/jdk.internal.misc", "java.base/jdk.internal.module", diff --git a/test/lib-test/ProblemList-StaticJdk.txt b/test/lib-test/ProblemList-StaticJdk.txt new file mode 100644 index 00000000000..3d151e07d41 --- /dev/null +++ b/test/lib-test/ProblemList-StaticJdk.txt @@ -0,0 +1,2 @@ +# Requires jcmd +jdk/test/lib/hprof/HprofTest.java 8346719 generic-all diff --git a/test/lib-test/TEST.ROOT b/test/lib-test/TEST.ROOT index 5908b50cb17..162e6e15ec2 100644 --- a/test/lib-test/TEST.ROOT +++ b/test/lib-test/TEST.ROOT @@ -29,7 +29,24 @@ keys=randomness # Minimum jtreg version -requiredVersion=7.5.1+1 +requiredVersion=7.5.2+1 + +# Allow querying of various System properties in @requires clauses +requires.extraPropDefns = ../jtreg-ext/requires/VMProps.java +requires.extraPropDefns.bootlibs = ../lib/jdk/test/whitebox +requires.extraPropDefns.libs = \ + ../lib/jdk/test/lib/Platform.java \ + ../lib/jdk/test/lib/Container.java +requires.extraPropDefns.javacOpts = \ + --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED +requires.extraPropDefns.vmOpts = \ + -XX:+UnlockDiagnosticVMOptions \ + -XX:+WhiteBoxAPI \ + --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED +requires.properties= \ + jdk.static # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../ notation to reach them diff --git a/test/lib-test/jdk/test/lib/process/TestNativeProcessBuilder.java b/test/lib-test/jdk/test/lib/process/TestNativeProcessBuilder.java index 6c2f53d31eb..926a5200936 100644 --- a/test/lib-test/jdk/test/lib/process/TestNativeProcessBuilder.java +++ b/test/lib-test/jdk/test/lib/process/TestNativeProcessBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @test * @summary Test the native process builder API. * @library /test/lib + * @requires !jdk.static * @run main/native TestNativeProcessBuilder */ diff --git a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java index 54a9ef872f5..8f0ef108885 100644 --- a/test/lib-test/jdk/test/whitebox/CPUInfoTest.java +++ b/test/lib-test/jdk/test/whitebox/CPUInfoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,7 @@ public class CPUInfoTest { "hv", "fsrm", "avx512_bitalg", "gfni", "f16c", "pku", "ospke", "cet_ibt", "cet_ss", "avx512_ifma", "serialize", "avx_ifma", - "apx_f" + "apx_f", "avx10_1", "avx10_2" ); // @formatter:on // Checkstyle: resume diff --git a/test/lib-test/jdk/test/whitebox/WaitForRefProcTest.java b/test/lib-test/jdk/test/whitebox/WaitForRefProcTest.java new file mode 100644 index 00000000000..1a254775f77 --- /dev/null +++ b/test/lib-test/jdk/test/whitebox/WaitForRefProcTest.java @@ -0,0 +1,30 @@ +/* + * @test + * @summary Test WhiteBox.waitForReferenceProcessing + * @bug 8305186 8355632 + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @modules java.base/java.lang.ref:open + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -ea -esa + * -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI + * WaitForRefProcTest + */ + +import jdk.test.whitebox.WhiteBox; + +public class WaitForRefProcTest { + + public static void main(String[] args) { + WhiteBox.getWhiteBox().fullGC(); + try { + boolean ret = WhiteBox.getWhiteBox().waitForReferenceProcessing(); + System.out.println("wFRP returned " + ret); + } catch (InterruptedException e) { + e.printStackTrace(); + throw new RuntimeException("test caught InterruptedException"); + } + } +} diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java index f08cbf0e7e2..7e98b57cb83 100644 --- a/test/lib/jdk/test/lib/cds/CDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.java @@ -35,7 +35,12 @@ * This is a base class used for testing CDS functionalities with complex applications. * You can define the application by overridding the vmArgs(), classpath() and appCommandLine() * methods. Application-specific validation checks can be implemented with checkExecution(). -*/ + * + * The AOT workflow runs with one-step training by default. For debugging purposes, run + * jtreg with -vmoption:-DCDSAppTester.two.step.training=true. This will run -XX:AOTMode=record + * and -XX:AOTMode=record in two separate processes that you can rerun easily inside a debugger. + * Also, the log files are easier to read. + */ abstract public class CDSAppTester { private final String name; private final String classListFile; @@ -51,7 +56,15 @@ abstract public class CDSAppTester { private final String tempBaseArchiveFile; private int numProductionRuns = 0; private String whiteBoxJar = null; - + private boolean inOneStepTraining = false; + + /** + * All files created in the CDS/AOT workflow will be name + extension. E.g. + * - name.aot + * - name.aotconfig + * - name.classlist + * - name.jsa + */ public CDSAppTester(String name) { if (CDSTestUtils.DYNAMIC_DUMP) { throw new SkippedException("Tests based on CDSAppTester should be excluded when -Dtest.dynamic.cds.archive is specified"); @@ -59,26 +72,32 @@ public CDSAppTester(String name) { this.name = name; classListFile = name() + ".classlist"; - classListFileLog = classListFile + ".log"; + classListFileLog = logFileName(classListFile); aotConfigurationFile = name() + ".aotconfig"; - aotConfigurationFileLog = aotConfigurationFile + ".log"; + aotConfigurationFileLog = logFileName(aotConfigurationFile); staticArchiveFile = name() + ".static.jsa"; - staticArchiveFileLog = staticArchiveFile + ".log"; + staticArchiveFileLog = logFileName(staticArchiveFile); aotCacheFile = name() + ".aot"; - aotCacheFileLog = aotCacheFile + ".log"; + aotCacheFileLog = logFileName(aotCacheFile);; dynamicArchiveFile = name() + ".dynamic.jsa"; - dynamicArchiveFileLog = dynamicArchiveFile + ".log"; + dynamicArchiveFileLog = logFileName(dynamicArchiveFile); tempBaseArchiveFile = name() + ".temp-base.jsa"; } private String productionRunLog() { if (numProductionRuns == 0) { - return name() + ".production.log"; + return logFileName(name() + ".production"); } else { - return name() + ".production." + numProductionRuns + ".log"; + return logFileName(name() + ".production." + numProductionRuns); } } + private static String logFileName(String file) { + file = file.replace("\"", "%22"); + file = file.replace("'", "%27"); + return file + ".log"; + } + private enum Workflow { STATIC, // classic -Xshare:dump workflow DYNAMIC, // classic -XX:ArchiveClassesAtExit @@ -86,7 +105,7 @@ private enum Workflow { } public enum RunMode { - TRAINING, // -XX:DumpLoadedClassList OR {-XX:AOTMode=create -XX:AOTConfiguration} + TRAINING, // -XX:DumpLoadedClassList OR {-XX:AOTMode=record -XX:AOTConfiguration} DUMP_STATIC, // -Xshare:dump DUMP_DYNAMIC, // -XX:ArchiveClassesArExit ASSEMBLY, // JEP 483 (assembly phase, app logic not executed) @@ -168,12 +187,11 @@ public final boolean isAOTWorkflow() { } private String logToFile(String logFile, String... logTags) { - StringBuilder sb = new StringBuilder("-Xlog:"); - String prefix = ""; + StringBuilder sb = new StringBuilder("-Xlog:arguments"); + String prefix = ","; for (String tag : logTags) { sb.append(prefix); sb.append(tag); - prefix = ","; } sb.append(":file=" + logFile + "::filesize=0"); return sb.toString(); @@ -242,6 +260,7 @@ private OutputAnalyzer recordAOTConfiguration() throws Exception { "-XX:AOTConfiguration=" + aotConfigurationFile, logToFile(aotConfigurationFileLog, "class+load=debug", + "aot=debug", "cds=debug", "cds+class=debug")); cmdLine = addCommonVMArgs(runMode, cmdLine); @@ -249,6 +268,22 @@ private OutputAnalyzer recordAOTConfiguration() throws Exception { return executeAndCheck(cmdLine, runMode, aotConfigurationFile, aotConfigurationFileLog); } + private OutputAnalyzer createAOTCacheOneStep() throws Exception { + RunMode runMode = RunMode.TRAINING; + String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-XX:AOTMode=record", + "-XX:AOTCacheOutput=" + aotCacheFile, + logToFile(aotCacheFileLog, + "class+load=debug", + "cds=debug", + "cds+class=debug")); + cmdLine = addCommonVMArgs(runMode, cmdLine); + cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); + OutputAnalyzer out = executeAndCheck(cmdLine, runMode, aotCacheFile, aotCacheFileLog); + listOutputFile(aotCacheFileLog + ".0"); // the log file for the training run + return out; + } + private OutputAnalyzer createClassList() throws Exception { RunMode runMode = RunMode.TRAINING; String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), @@ -264,15 +299,17 @@ private OutputAnalyzer createClassList() throws Exception { private OutputAnalyzer dumpStaticArchive() throws Exception { RunMode runMode = RunMode.DUMP_STATIC; String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xlog:aot", + "-Xlog:aot+heap=error", "-Xlog:cds", - "-Xlog:cds+heap=error", "-Xshare:dump", "-XX:SharedArchiveFile=" + staticArchiveFile, "-XX:SharedClassListFile=" + classListFile, logToFile(staticArchiveFileLog, + "aot=debug", "cds=debug", "cds+class=debug", - "cds+heap=warning", + "aot+heap=warning", "cds+resolve=debug")); cmdLine = addCommonVMArgs(runMode, cmdLine); cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); @@ -282,15 +319,17 @@ private OutputAnalyzer dumpStaticArchive() throws Exception { private OutputAnalyzer createAOTCache() throws Exception { RunMode runMode = RunMode.ASSEMBLY; String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xlog:aot", + "-Xlog:aot+heap=error", "-Xlog:cds", - "-Xlog:cds+heap=error", "-XX:AOTMode=create", "-XX:AOTConfiguration=" + aotConfigurationFile, "-XX:AOTCache=" + aotCacheFile, logToFile(aotCacheFileLog, + "aot=debug", "cds=debug", "cds+class=debug", - "cds+heap=warning", + "aot+heap=warning", "cds+resolve=debug")); cmdLine = addCommonVMArgs(runMode, cmdLine); cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); @@ -331,9 +370,11 @@ private OutputAnalyzer dumpDynamicArchive() throws Exception { if (isDynamicWorkflow()) { // "classic" dynamic archive cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xlog:aot", "-Xlog:cds", "-XX:ArchiveClassesAtExit=" + dynamicArchiveFile, logToFile(dynamicArchiveFileLog, + "aot=debug", "cds=debug", "cds+class=debug", "cds+resolve=debug", @@ -347,7 +388,7 @@ private OutputAnalyzer dumpDynamicArchive() throws Exception { return executeAndCheck(cmdLine, runMode, dynamicArchiveFile, dynamicArchiveFileLog); } - private OutputAnalyzer productionRun() throws Exception { + public OutputAnalyzer productionRun() throws Exception { return productionRun(null, null); } @@ -362,7 +403,7 @@ public OutputAnalyzer productionRun(String[] extraVmArgs, String[] extraAppArgs) String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), "-XX:+UnlockDiagnosticVMOptions", "-XX:VerifyArchivedFields=2", // make sure archived heap objects are good. - logToFile(productionRunLog(), "cds")); + logToFile(productionRunLog(), "aot", "cds")); cmdLine = addCommonVMArgs(runMode, cmdLine); if (isStaticWorkflow()) { @@ -389,14 +430,14 @@ public OutputAnalyzer productionRun(String[] extraVmArgs, String[] extraAppArgs) } public void run(String... args) throws Exception { - String err = "Must have exactly one command line argument of the following: "; + String err = "Must have at least one command line argument of the following: "; String prefix = ""; for (Workflow wf : Workflow.values()) { err += prefix; err += wf; prefix = ", "; } - if (args.length != 1) { + if (args.length < 1) { throw new RuntimeException(err); } else { if (args[0].equals("STATIC")) { @@ -404,7 +445,7 @@ public void run(String... args) throws Exception { } else if (args[0].equals("DYNAMIC")) { runDynamicWorkflow(); } else if (args[0].equals("AOT")) { - runAOTWorkflow(); + runAOTWorkflow(args); } else { throw new RuntimeException(err); } @@ -425,10 +466,44 @@ public void runDynamicWorkflow() throws Exception { } // See JEP 483 - public void runAOTWorkflow() throws Exception { + public void runAOTWorkflow(String... args) throws Exception { + this.workflow = Workflow.AOT; + boolean oneStepTraining = true; // by default use onestep trainning + + if (System.getProperty("CDSAppTester.two.step.training") != null) { + oneStepTraining = false; + } + + if (args.length > 1) { + // Tests such as test/hotspot/jtreg/runtime/cds/appcds/aotCache/SpecialCacheNames.java + // use --one-step-training or --two-step-training to force a certain training workflow. + if (args[1].equals("--one-step-training")) { + oneStepTraining = true; + } else if (args[1].equals("--two-step-training")) { + oneStepTraining = false; + } else { + throw new RuntimeException("Unknown option: " + args[1]); + } + } + + if (oneStepTraining) { + try { + inOneStepTraining = true; + createAOTCacheOneStep(); + } finally { + inOneStepTraining = false; + } + } else { + recordAOTConfiguration(); + createAOTCache(); + } + productionRun(); + } + + // See JEP 483; stop at the assembly run; do not execute production run + public void runAOTAssemblyWorkflow() throws Exception { this.workflow = Workflow.AOT; recordAOTConfiguration(); createAOTCache(); - productionRun(); } } diff --git a/test/lib/jdk/test/lib/cds/CDSTestUtils.java b/test/lib/jdk/test/lib/cds/CDSTestUtils.java index a913f2f9fa2..be6fddc17aa 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -255,7 +255,7 @@ public static OutputAnalyzer createArchive(CDSOptions opts) for (String p : opts.prefix) cmd.add(p); cmd.add("-Xshare:dump"); - cmd.add("-Xlog:cds,cds+hashtables"); + cmd.add("-Xlog:cds,aot+hashtables"); if (opts.archiveName == null) opts.archiveName = getDefaultArchiveName(); cmd.add("-XX:SharedArchiveFile=" + opts.archiveName); @@ -778,8 +778,10 @@ private static boolean isAsciiPrintable(char ch) { // 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"}; + // The jvm.cfg file must be copied because the cds/NonJVMVariantLocation.java + // test is testing a CDS archive can be loaded from a non-JVM variant directory. + // Set a list of {jvm, "java", "jvm.cfg"} which will be physically copied. If a file needs copied physically, add it to the list. + private static String[] phCopied = {System.mapLibraryName("jvm"), "java", "jvm.cfg"}; public static void clone(File src, File dst) throws Exception { if (dst.exists()) { if (!dst.isDirectory()) { diff --git a/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java b/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java index 33d984ed505..c869cfa366b 100644 --- a/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java @@ -24,11 +24,13 @@ package jdk.test.lib.cds; import java.io.File; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + +import jdk.test.lib.cds.CDSAppTester.RunMode; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.StringArrayUtils; -import java.util.function.Consumer; - /* * A simpler way to use CDSAppTester. Example: * @@ -49,8 +51,9 @@ */ public class SimpleCDSAppTester { private String name; - private Consumer assemblyChecker; - private Consumer productionChecker; + private BiConsumer trainingChecker; + private BiConsumer assemblyChecker; + private BiConsumer productionChecker; private String classpath; private String modulepath; private String[] appCommandLine; @@ -98,16 +101,42 @@ public SimpleCDSAppTester appCommandLine(String... args) { return this; } - public SimpleCDSAppTester setAssemblyChecker(Consumer checker) { + public SimpleCDSAppTester setTrainingChecker(BiConsumer checker) { + this.trainingChecker = checker; + return this; + } + + public SimpleCDSAppTester setAssemblyChecker(BiConsumer checker) { this.assemblyChecker = checker; return this; } - public SimpleCDSAppTester setProductionChecker(Consumer checker) { + public SimpleCDSAppTester setProductionChecker(BiConsumer checker) { this.productionChecker = checker; return this; } + public SimpleCDSAppTester setTrainingChecker(Consumer checker) { + this.trainingChecker = (OutputAnalyzer out, RunMode runMode) -> { + checker.accept(out); + }; + return this; + } + + public SimpleCDSAppTester setAssemblyChecker(Consumer checker) { + this.assemblyChecker = (OutputAnalyzer out, RunMode runMode) -> { + checker.accept(out); + }; + return this; + } + + public SimpleCDSAppTester setProductionChecker(Consumer checker) { + this.productionChecker = (OutputAnalyzer out, RunMode runMode) -> { + checker.accept(out); + }; + return this; + } + class Tester extends CDSAppTester { public Tester(String name) { super(name); @@ -135,13 +164,17 @@ public String[] appCommandLine(RunMode runMode) { @Override public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { - if (isDumping(runMode) && runMode != RunMode.TRAINING) { + if (runMode == RunMode.TRAINING) { + if (trainingChecker != null) { + trainingChecker.accept(out, runMode); + } + } else if (isDumping(runMode)) { if (assemblyChecker != null) { - assemblyChecker.accept(out); + assemblyChecker.accept(out, runMode); } } else if (runMode.isProductionRun()) { if (productionChecker != null) { - productionChecker.accept(out); + productionChecker.accept(out, runMode); } } } @@ -156,4 +189,9 @@ public SimpleCDSAppTester runAOTWorkflow() throws Exception { (new Tester(name)).runAOTWorkflow(); return this; } + + public SimpleCDSAppTester run(String args[]) throws Exception { + (new Tester(name)).run(args); + return this; + } } diff --git a/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java b/test/lib/jdk/test/lib/compiler/InMemoryJavaCompiler.java index 4722ef3b67a..7a289bbcce5 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,8 +208,10 @@ public String getClassName() { } /** - * Compiles the list of classes with the given map of name and source code. - * This overloaded version of compile is useful for batch compile use cases. + * Compiles the list of classes with the given map of binary name and source code. + * This overloaded version of compile is useful for batch compile use cases, or + * if a compilation unit produces multiple class files. Returns a map from + * class binary names to class file content. * * @param inputMap The map containing the name of the class and corresponding source code * @throws RuntimeException if the compilation did not succeed diff --git a/test/lib/jdk/test/lib/containers/docker/ContainerRuntimeVersionTestUtils.java b/test/lib/jdk/test/lib/containers/docker/ContainerRuntimeVersionTestUtils.java new file mode 100644 index 00000000000..88538e7e780 --- /dev/null +++ b/test/lib/jdk/test/lib/containers/docker/ContainerRuntimeVersionTestUtils.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Methods and definitions related to container runtime version to test container in this directory + */ + +package jdk.test.lib.containers.docker; + +import jdk.test.lib.Container; +import jdk.test.lib.process.OutputAnalyzer; +import jtreg.SkippedException; + +public class ContainerRuntimeVersionTestUtils implements Comparable { + private final int major; + private final int minor; + private final int micro; + private static final boolean IS_DOCKER = Container.ENGINE_COMMAND.contains("docker"); + private static final boolean IS_PODMAN = Container.ENGINE_COMMAND.contains("podman"); + public static final ContainerRuntimeVersionTestUtils DOCKER_MINIMAL_SUPPORTED_VERSION_CGROUPNS = new ContainerRuntimeVersionTestUtils(20, 10, 0); + public static final ContainerRuntimeVersionTestUtils PODMAN_MINIMAL_SUPPORTED_VERSION_CGROUPNS = new ContainerRuntimeVersionTestUtils(1, 5, 0); + + private ContainerRuntimeVersionTestUtils(int major, int minor, int micro) { + this.major = major; + this.minor = minor; + this.micro = micro; + } + + public static void checkContainerVersionSupported() { + if (IS_DOCKER && ContainerRuntimeVersionTestUtils.DOCKER_MINIMAL_SUPPORTED_VERSION_CGROUPNS.compareTo(ContainerRuntimeVersionTestUtils.getContainerRuntimeVersion()) > 0) { + throw new SkippedException("Docker version too old for this test. Expected >= 20.10.0"); + } + if (IS_PODMAN && ContainerRuntimeVersionTestUtils.PODMAN_MINIMAL_SUPPORTED_VERSION_CGROUPNS.compareTo(ContainerRuntimeVersionTestUtils.getContainerRuntimeVersion()) > 0) { + throw new SkippedException("Podman version too old for this test. Expected >= 1.5.0"); + } + } + + @Override + public int compareTo(ContainerRuntimeVersionTestUtils other) { + if (this.major > other.major) { + return 1; + } else if (this.major < other.major) { + return -1; + } else if (this.minor > other.minor) { + return 1; + } else if (this.minor < other.minor) { + return -1; + } else if (this.micro > other.micro) { + return 1; + } else if (this.micro < other.micro) { + return -1; + } else { + // equal majors, minors, micro + return 0; + } + } + + public static ContainerRuntimeVersionTestUtils fromVersionString(String version) { + try { + // Example 'docker version 20.10.0 or podman version 4.9.4-rhel' + String versNums = version.split("\\s+", 3)[2]; + String[] numbers = versNums.split("-")[0].split("\\.", 3); + return new ContainerRuntimeVersionTestUtils(Integer.parseInt(numbers[0]), + Integer.parseInt(numbers[1]), + Integer.parseInt(numbers[2])); + } catch (Exception e) { + throw new RuntimeException("Failed to parse container runtime version: " + version); + } + } + + public static String getContainerRuntimeVersionStr() { + try { + ProcessBuilder pb = new ProcessBuilder(Container.ENGINE_COMMAND, "--version"); + OutputAnalyzer out = new OutputAnalyzer(pb.start()) + .shouldHaveExitValue(0); + String result = out.asLines().get(0); + System.out.println(Container.ENGINE_COMMAND + " --version returning: " + result); + return result; + } catch (Exception e) { + throw new RuntimeException(Container.ENGINE_COMMAND + " --version command failed."); + } + } + + public static ContainerRuntimeVersionTestUtils getContainerRuntimeVersion() { + return ContainerRuntimeVersionTestUtils.fromVersionString(getContainerRuntimeVersionStr()); + } +} \ No newline at end of file diff --git a/test/lib/jdk/test/lib/dcmd/JcmdExecutor.java b/test/lib/jdk/test/lib/dcmd/JcmdExecutor.java index 6bf940cda6e..52b64c5a0cb 100644 --- a/test/lib/jdk/test/lib/dcmd/JcmdExecutor.java +++ b/test/lib/jdk/test/lib/dcmd/JcmdExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,8 @@ */ public abstract class JcmdExecutor extends CommandExecutor { protected String jcmdBinary; + // VM option to disable streaming output + protected String jcmdDisableStreamingOption = "-J-Djdk.attach.allowStreamingOutput=false"; protected abstract List createCommandLine(String cmd) throws CommandExecutorException; @@ -41,6 +43,10 @@ protected JcmdExecutor() { jcmdBinary = JDKToolFinder.getJDKTool("jcmd"); } + public List getCommandLine(String... cmds) { + return createCommandLine(String.join(" ", cmds)); + } + protected OutputAnalyzer executeImpl(String cmd) throws CommandExecutorException { List commandLine = createCommandLine(cmd); diff --git a/test/lib/jdk/test/lib/dcmd/PidJcmdExecutor.java b/test/lib/jdk/test/lib/dcmd/PidJcmdExecutor.java index 25b3f532fc6..2b132c39b09 100644 --- a/test/lib/jdk/test/lib/dcmd/PidJcmdExecutor.java +++ b/test/lib/jdk/test/lib/dcmd/PidJcmdExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ import jdk.test.lib.process.ProcessTools; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -33,17 +34,15 @@ */ public class PidJcmdExecutor extends JcmdExecutor { protected final long pid; + // jcmd output for many commands may be lengthy when command is executed against main test process + protected boolean disableStreamingOutput = true; /** * Instantiates a new PidJcmdExecutor targeting the current VM */ public PidJcmdExecutor() { super(); - try { - pid = ProcessTools.getProcessId(); - } catch (Exception e) { - throw new CommandExecutorException("Could not determine own pid", e); - } + pid = getCurrentPid(); } /** @@ -54,10 +53,27 @@ public PidJcmdExecutor() { public PidJcmdExecutor(String target) { super(); pid = Long.valueOf(target); + disableStreamingOutput = (pid == getCurrentPid()); + } + + private static long getCurrentPid() { + try { + return ProcessTools.getProcessId(); + } catch (Exception e) { + throw new CommandExecutorException("Could not determine own pid", e); + } } protected List createCommandLine(String cmd) throws CommandExecutorException { - return Arrays.asList(jcmdBinary, Long.toString(pid), cmd); + List commandLine = new ArrayList<>(); + commandLine.add(jcmdBinary); + if (disableStreamingOutput) { + commandLine.add(jcmdDisableStreamingOption); + } + commandLine.add(Long.toString(pid)); + commandLine.add(cmd); + return commandLine; + //return Arrays.asList(jcmdBinary, Long.toString(pid), cmd); } } diff --git a/test/lib/jdk/test/lib/jfr/EventNames.java b/test/lib/jdk/test/lib/jfr/EventNames.java index 8137f33df44..a00898358a8 100644 --- a/test/lib/jdk/test/lib/jfr/EventNames.java +++ b/test/lib/jdk/test/lib/jfr/EventNames.java @@ -77,6 +77,8 @@ public class EventNames { public static final String ThreadAllocationStatistics = PREFIX + "ThreadAllocationStatistics"; public static final String ExecutionSample = PREFIX + "ExecutionSample"; public static final String NativeMethodSample = PREFIX + "NativeMethodSample"; + public static final String CPUTimeSample = PREFIX + "CPUTimeSample"; + public static final String CPUTimeSamplesLost = PREFIX + "CPUTimeSamplesLost"; public static final String ThreadDump = PREFIX + "ThreadDump"; public static final String OldObjectSample = PREFIX + "OldObjectSample"; public static final String SymbolTableStatistics = PREFIX + "SymbolTableStatistics"; @@ -90,6 +92,9 @@ public class EventNames { public static final String JavaAgent = PREFIX + "JavaAgent"; public static final String NativeAgent = PREFIX + "NativeAgent"; public static final String DeprecatedInvocation = PREFIX + "DeprecatedInvocation"; + public static final String SafepointLatency = PREFIX + "SafepointLatency"; + public static final String MethodTiming = PREFIX + "MethodTiming"; + public static final String MethodTrace = PREFIX + "MethodTrace"; // This event is hard to test public static final String ReservedStackActivation = PREFIX + "ReservedStackActivation"; diff --git a/test/lib/jdk/test/lib/jfr/Events.java b/test/lib/jdk/test/lib/jfr/Events.java index 5676b7021d6..8bbf22ca63a 100644 --- a/test/lib/jdk/test/lib/jfr/Events.java +++ b/test/lib/jdk/test/lib/jfr/Events.java @@ -361,6 +361,16 @@ public static void hasNotEvent(List events, String name) throws I } } + public static RecordedEvent getFirst(List events, String name) throws Exception { + for (RecordedEvent event : events) { + if (event.getEventType().getName().equals(name)) { + return event; + } + } + Asserts.fail("Missing event " + name + " in recording " + events.toString()); + return null; + } + private static boolean containsEvent(List events, String name) { for (RecordedEvent event : events) { if (event.getEventType().getName().equals(name)) { @@ -370,6 +380,12 @@ private static boolean containsEvent(List events, String name) { return false; } + public static void assertEventCount(List events, int count) throws Exception { + if (events.size() != count) { + throw new Exception("Expected " + count + " events, found " + events.size()); + } + } + public static void assertTopFrame(RecordedEvent event, Class expectedClass, String expectedMethodName) { assertTopFrame(event, expectedClass.getName(), expectedMethodName); } diff --git a/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp b/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp index 5efd58e7773..e77abb400e0 100644 --- a/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp +++ b/test/lib/jdk/test/lib/jvmti/jvmti_common.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -447,7 +447,27 @@ static jthread get_current_thread(jvmtiEnv *jvmti, JNIEnv* jni) { return thread; } +/* Used in a couple of nsk/jvmti/scenarios tests to convert jbyteArray to a JVMTI allocated */ +static unsigned char* jni_array_to_jvmti_allocated(jvmtiEnv *jvmti, JNIEnv *jni, jbyteArray arr, jint* len_ptr) { + unsigned char* new_arr = nullptr; + jint len = jni->GetArrayLength(arr); + if (len <= 0) { + fatal(jni, "JNI GetArrayLength returned a non-positive value"); + } + jbyte* jni_arr = jni->GetByteArrayElements(arr, nullptr); + if (jni_arr == nullptr) { + fatal(jni, "JNI GetByteArrayElements returned nullptr"); + } + jvmtiError err = jvmti->Allocate(len, &new_arr); + check_jvmti_status(jni, err, "JVMTI Allocate returned an error code"); + + memcpy(new_arr, jni_arr, (size_t)len); + jni->ReleaseByteArrayElements(arr, jni_arr, JNI_ABORT); + + *len_ptr = len; + return new_arr; +} /* Commonly used helper functions */ const char* diff --git a/test/lib/jdk/test/lib/security/SecurityUtils.java b/test/lib/jdk/test/lib/security/SecurityUtils.java index 7509488225e..be6ff1cc0e3 100644 --- a/test/lib/jdk/test/lib/security/SecurityUtils.java +++ b/test/lib/jdk/test/lib/security/SecurityUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,8 @@ public final class SecurityUtils { private enum KeySize{ RSA(2048), DSA(2048), + Ed25519(256), + EC(256), DH(2048); private final int keySize; @@ -145,6 +147,8 @@ public static int getTestKeySize(String algo) { return switch (algo) { case "RSA" -> KeySize.RSA.keySize; case "DSA" -> KeySize.DSA.keySize; + case "Ed25519" -> KeySize.Ed25519.keySize; + case "EC" -> KeySize.EC.keySize; case "DH", "DiffieHellman" -> KeySize.DH.keySize; default -> throw new RuntimeException("Test key size not defined for " + algo); }; diff --git a/test/lib/jdk/test/lib/threaddump/ThreadDump.java b/test/lib/jdk/test/lib/threaddump/ThreadDump.java index 5e4f6ebc10f..f4964a9521f 100644 --- a/test/lib/jdk/test/lib/threaddump/ThreadDump.java +++ b/test/lib/jdk/test/lib/threaddump/ThreadDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -62,6 +63,7 @@ * { * "tid": "8", * "name": "Reference Handler", + * "state": "RUNNABLE", * "stack": [ * "java.base\/java.lang.ref.Reference.waitForReferencePendingList(Native Method)", * "java.base\/java.lang.ref.Reference.processPendingReferences(Reference.java:245)", @@ -113,23 +115,46 @@ * } */ public final class ThreadDump { - private final long processId; - private final String time; - private final String runtimeVersion; - private ThreadContainer rootThreadContainer; + private final ThreadContainer rootThreadContainer; + private final Map nameToThreadContainer; + private final JSONValue threadDumpObj; + + private ThreadDump(ThreadContainer rootThreadContainer, + Map nameToThreadContainer, + JSONValue threadDumpObj) { + this.rootThreadContainer = rootThreadContainer; + this.nameToThreadContainer = nameToThreadContainer; + this.threadDumpObj = threadDumpObj; + } /** * Represents an element in the threadDump/threadContainers array. */ public static class ThreadContainer { private final String name; - private long owner; - private ThreadContainer parent; - private Set threads; + private final ThreadContainer parent; private final Set children = new HashSet<>(); + private final JSONValue containerObj; - ThreadContainer(String name) { + ThreadContainer(String name, ThreadContainer parent, JSONValue containerObj) { this.name = name; + this.parent = parent; + this.containerObj = containerObj; + } + + /** + * Add a child thread container. + */ + void addChild(ThreadContainer container) { + children.add(container); + } + + /** + * Returns the value of a property of this thread container, as a string. + */ + private String getStringProperty(String propertyName) { + JSONValue value = containerObj.get(propertyName); + return (value != null) ? value.asString() : null; } /** @@ -143,7 +168,10 @@ public String name() { * Return the thread identifier of the owner or empty OptionalLong if not owned. */ public OptionalLong owner() { - return (owner != 0) ? OptionalLong.of(owner) : OptionalLong.empty(); + String owner = getStringProperty("owner"); + return (owner != null) + ? OptionalLong.of(Long.parseLong(owner)) + : OptionalLong.empty(); } /** @@ -164,7 +192,12 @@ public Stream children() { * Returns a stream of {@code ThreadInfo} objects for the threads in this container. */ public Stream threads() { - return threads.stream(); + JSONValue.JSONArray threadsObj = containerObj.get("threads").asArray(); + Set threadInfos = new HashSet<>(); + for (JSONValue threadObj : threadsObj) { + threadInfos.add(new ThreadInfo(threadObj)); + } + return threadInfos.stream(); } /** @@ -176,21 +209,6 @@ public Optional findThread(long tid) { .findAny(); } - /** - * Helper method to recursively find a container with the given name. - */ - ThreadContainer findThreadContainer(String name) { - if (name().equals(name)) - return this; - if (name().startsWith(name + "/")) - return this; - return children() - .map(c -> c.findThreadContainer(name)) - .filter(c -> c != null) - .findAny() - .orElse(null); - } - @Override public int hashCode() { return name.hashCode(); @@ -216,13 +234,30 @@ public String toString() { */ public static final class ThreadInfo { private final long tid; - private final String name; - private final List stack; + private final JSONValue threadObj; - ThreadInfo(long tid, String name, List stack) { - this.tid = tid; - this.name = name; - this.stack = stack; + ThreadInfo(JSONValue threadObj) { + this.tid = Long.parseLong(threadObj.get("tid").asString()); + this.threadObj = threadObj; + } + + /** + * Returns the value of a property of this thread object, as a string. + */ + private String getStringProperty(String propertyName) { + JSONValue value = threadObj.get(propertyName); + return (value != null) ? value.asString() : null; + } + + /** + * Returns the value of a property of an object in this thread object, as a string. + */ + private String getStringProperty(String objectName, String propertyName) { + if (threadObj.get(objectName) instanceof JSONValue.JSONObject obj + && obj.get(propertyName) instanceof JSONValue value) { + return value.asString(); + } + return null; } /** @@ -236,16 +271,86 @@ public long tid() { * Returns the thread name. */ public String name() { - return name; + return getStringProperty("name"); + } + + /** + * Returns the thread state. + */ + public String state() { + return getStringProperty("state"); + } + + /** + * Returns true if virtual thread. + */ + public boolean isVirtual() { + String s = getStringProperty("virtual"); + return (s != null) ? Boolean.parseBoolean(s) : false; + } + + /** + * Returns the thread's parkBlocker. + */ + public String parkBlocker() { + return getStringProperty("parkBlocker", "object"); + } + + /** + * Returns the object that the thread is blocked entering its monitor. + */ + public String blockedOn() { + return getStringProperty("blockedOn"); + } + + /** + * Return the object that is the therad is waiting on with Object.wait. + */ + public String waitingOn() { + return getStringProperty("waitingOn"); } /** * Returns the thread stack. */ public Stream stack() { + JSONValue.JSONArray stackObj = threadObj.get("stack").asArray(); + List stack = new ArrayList<>(); + for (JSONValue steObject : stackObj) { + stack.add(steObject.asString()); + } return stack.stream(); } + /** + * Return a map of monitors owned. + */ + public Map> ownedMonitors() { + Map> ownedMonitors = new HashMap<>(); + JSONValue monitorsOwnedObj = threadObj.get("monitorsOwned"); + if (monitorsOwnedObj != null) { + for (JSONValue obj : monitorsOwnedObj.asArray()) { + int depth = Integer.parseInt(obj.get("depth").asString()); + for (JSONValue lock : obj.get("locks").asArray()) { + ownedMonitors.computeIfAbsent(depth, _ -> new ArrayList<>()) + .add(lock.asString()); + } + } + } + return ownedMonitors; + } + + /** + * If the thread is a mounted virtual thread, return the thread identifier of + * its carrier. + */ + public OptionalLong carrier() { + String s = getStringProperty("carrier"); + return (s != null) + ? OptionalLong.of(Long.parseLong(s)) + : OptionalLong.empty(); + } + @Override public int hashCode() { return Long.hashCode(tid); @@ -264,84 +369,42 @@ public boolean equals(Object obj) { public String toString() { StringBuilder sb = new StringBuilder("#"); sb.append(tid); + String name = name(); if (name.length() > 0) { - sb.append(","); - sb.append(name); + sb.append(",") + .append(name); } return sb.toString(); } } /** - * Parses the given JSON text as a thread dump. + * Returns the value of a property of this thread dump, as a string. */ - private ThreadDump(String json) { - JSONValue threadDumpObj = JSONValue.parse(json).get("threadDump"); - - // maps container name to ThreadContainer - Map map = new HashMap<>(); - - // threadContainers array - JSONValue threadContainersObj = threadDumpObj.get("threadContainers"); - for (JSONValue containerObj : threadContainersObj.asArray()) { - String name = containerObj.get("container").asString(); - String parentName = containerObj.get("parent").asString(); - String owner = containerObj.get("owner").asString(); - JSONValue.JSONArray threadsObj = containerObj.get("threads").asArray(); - - // threads array - Set threadInfos = new HashSet<>(); - for (JSONValue threadObj : threadsObj) { - long tid = Long.parseLong(threadObj.get("tid").asString()); - String threadName = threadObj.get("name").asString(); - JSONValue.JSONArray stackObj = threadObj.get("stack").asArray(); - List stack = new ArrayList<>(); - for (JSONValue steObject : stackObj) { - stack.add(steObject.asString()); - } - threadInfos.add(new ThreadInfo(tid, threadName, stack)); - } - - // add to map if not already encountered - var container = map.computeIfAbsent(name, k -> new ThreadContainer(name)); - if (owner != null) - container.owner = Long.parseLong(owner); - container.threads = threadInfos; - - if (parentName == null) { - rootThreadContainer = container; - } else { - // add parent to map if not already encountered and add to its set of children - var parent = map.computeIfAbsent(parentName, k -> new ThreadContainer(parentName)); - container.parent = parent; - parent.children.add(container); - } - } - - this.processId = Long.parseLong(threadDumpObj.get("processId").asString()); - this.time = threadDumpObj.get("time").asString(); - this.runtimeVersion = threadDumpObj.get("runtimeVersion").asString(); + private String getStringProperty(String propertyName) { + JSONValue value = threadDumpObj.get(propertyName); + return (value != null) ? value.asString() : null; } /** * Returns the value of threadDump/processId. */ public long processId() { - return processId; + return Long.parseLong(getStringProperty("processId")); } /** * Returns the value of threadDump/time. */ public String time() { - return time; + return getStringProperty("time"); } /** * Returns the value of threadDump/runtimeVersion. */ public String runtimeVersion() { - return runtimeVersion; + return getStringProperty("runtimeVersion"); } /** @@ -355,8 +418,17 @@ public ThreadContainer rootThreadContainer() { * Finds a container in the threadDump/threadContainers array with the given name. */ public Optional findThreadContainer(String name) { - ThreadContainer container = rootThreadContainer.findThreadContainer(name); - return Optional.ofNullable(container); + ThreadContainer container = nameToThreadContainer.get(name); + if (container == null) { + // may be name/identity format + container = nameToThreadContainer.entrySet() + .stream() + .filter(e -> e.getKey().startsWith(name + "/")) + .map(e -> e.getValue()) + .findAny() + .orElse(null); + } + return Optional.of(container); } /** @@ -364,6 +436,36 @@ public Optional findThreadContainer(String name) { * @throws RuntimeException if an error occurs */ public static ThreadDump parse(String json) { - return new ThreadDump(json); + JSONValue threadDumpObj = JSONValue.parse(json).get("threadDump"); + + // threadContainers array, preserve insertion order (parents are added before children) + Map containerObjs = new LinkedHashMap<>(); + JSONValue threadContainersObj = threadDumpObj.get("threadContainers"); + for (JSONValue containerObj : threadContainersObj.asArray()) { + String name = containerObj.get("container").asString(); + containerObjs.put(name, containerObj); + } + + // find root and create tree of thread containers + ThreadContainer root = null; + Map map = new HashMap<>(); + for (String name : containerObjs.keySet()) { + JSONValue containerObj = containerObjs.get(name); + String parentName = containerObj.get("parent").asString(); + if (parentName == null) { + root = new ThreadContainer(name, null, containerObj); + map.put(name, root); + } else { + var parent = map.get(parentName); + if (parent == null) { + throw new RuntimeException("Thread container " + name + " found before " + parentName); + } + var container = new ThreadContainer(name, parent, containerObj); + parent.addChild(container); + map.put(name, container); + } + } + + return new ThreadDump(root, map, threadDumpObj); } -} +} \ No newline at end of file diff --git a/test/lib/jdk/test/lib/util/JarUtils.java b/test/lib/jdk/test/lib/util/JarUtils.java index 3aa4ada5197..9a3d73ee410 100644 --- a/test/lib/jdk/test/lib/util/JarUtils.java +++ b/test/lib/jdk/test/lib/util/JarUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,6 +131,24 @@ public static void createJarFile(Path jarfile, Path dir, String... input) createJarFile(jarfile, dir, paths); } + + /** + * Creates a JAR file from a map of class binary name to class bytes. + * + * @see jdk.test.lib.compiler.InMemoryJavaCompiler#compile(Map) + */ + public static void createJarFromClasses(Path jarfile, Map classes) throws IOException { + try (OutputStream out = Files.newOutputStream(jarfile); + JarOutputStream jos = new JarOutputStream(out)) { + for (var entry : classes.entrySet()) { + String name = entry.getKey().replace('.', '/') + ".class"; + jos.putNextEntry(new JarEntry(name)); + jos.write(entry.getValue()); + jos.closeEntry(); + } + } + } + /** * Updates a JAR file. * diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index f0e164d94b5..10fad866ca3 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -24,7 +24,11 @@ package jdk.test.whitebox; import java.lang.management.MemoryUsage; +import java.lang.ref.Reference; import java.lang.reflect.Executable; +import java.lang.reflect.InaccessibleObjectException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.function.BiFunction; @@ -556,6 +560,53 @@ public void clearInlineCaches(boolean preserve_static_stubs) { // Force Full GC public native void fullGC(); + // Infrastructure for waitForReferenceProcessing() + private static volatile Method waitForReferenceProcessingMethod = null; + + private static Method getWaitForReferenceProcessingMethod() { + Method wfrp = waitForReferenceProcessingMethod; + if (wfrp == null) { + try { + wfrp = Reference.class.getDeclaredMethod("waitForReferenceProcessing"); + wfrp.setAccessible(true); + assert wfrp.getReturnType().equals(boolean.class); + Class[] ev = wfrp.getExceptionTypes(); + assert ev.length == 1; + assert ev[0] == InterruptedException.class; + waitForReferenceProcessingMethod = wfrp; + } catch (InaccessibleObjectException e) { + throw new RuntimeException("Need to add @modules java.base/java.lang.ref:open to test?", e); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } + } + return wfrp; + } + + /** + * Wait for reference processing, via Reference.waitForReferenceProcessing(). + * Callers of this method will need the + * @modules java.base/java.lang.ref:open + * jtreg tag. + * + * This method should usually be called after a call to WhiteBox.fullGC(). + */ + public boolean waitForReferenceProcessing() throws InterruptedException { + try { + Method wfrp = getWaitForReferenceProcessingMethod(); + return (Boolean) wfrp.invoke(null); + } catch (IllegalAccessException e) { + throw new RuntimeException("Shouldn't happen, we call setAccessible()", e); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + if (cause instanceof InterruptedException) { + throw (InterruptedException) cause; + } else { + throw new RuntimeException(e); + } + } + } + // Returns true if the current GC supports concurrent collection control. public native boolean supportsConcurrentGCBreakpoints(); @@ -765,6 +816,7 @@ public native int validateCgroup(boolean cgroupsV2Enabled, String procSelfMountinfo); public native void printOsInfo(); public native long hostPhysicalMemory(); + public native long hostAvailableMemory(); public native long hostPhysicalSwap(); public native int hostCPUs(); diff --git a/test/micro/org/openjdk/bench/java/lang/CbrtPerf.java b/test/micro/org/openjdk/bench/java/lang/CbrtPerf.java new file mode 100644 index 00000000000..0143b76fe6c --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/CbrtPerf.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Random; + +public class CbrtPerf { + + @Warmup(iterations = 3, time = 5, timeUnit = TimeUnit.MILLISECONDS) + @Measurement(iterations = 4, time = 5, timeUnit = TimeUnit.MILLISECONDS) + @Fork(2) + @BenchmarkMode(Mode.Throughput) + @State(Scope.Thread) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public static class CbrtPerfRanges { + public static int cbrtInputCount = 2048; + + @Param({"0", "1"}) + public int cbrtRangeIndex; + + public double [] cbrtPosRandInputs; + public double [] cbrtNegRandInputs; + public int cbrtInputIndex = 0; + public double cbrtRangeInputs[][] = { {0.0, 0x1.0P-1022}, {0x1.0P-1022, 1.7976931348623157E308} }; + + @Setup + public void setupValues() { + Random random = new Random(1023); + + // Fill the positive and negative cbrt vectors with random values + cbrtPosRandInputs = new double[cbrtInputCount]; + cbrtNegRandInputs = new double[cbrtInputCount]; + + for (int i = 0; i < cbrtInputCount; i++) { + double cbrtLowerBound = cbrtRangeInputs[cbrtRangeIndex][0]; + double cbrtUpperBound = cbrtRangeInputs[cbrtRangeIndex][1]; + cbrtPosRandInputs[i] = random.nextDouble(cbrtLowerBound, cbrtUpperBound); + cbrtNegRandInputs[i] = random.nextDouble(-cbrtUpperBound, -cbrtLowerBound); + } + } + + @Benchmark + @OperationsPerInvocation(2048) + public double cbrtPosRangeDouble() { + double res = 0.0; + for (int i = 0; i < cbrtInputCount; i++) { + res += Math.cbrt(cbrtPosRandInputs[i]); + } + return res; + } + + @Benchmark + @OperationsPerInvocation(2048) + public double cbrtNegRangeDouble() { + double res = 0.0; + for (int i = 0; i < cbrtInputCount; i++) { + res += Math.cbrt(cbrtNegRandInputs[i]); + } + return res; + } + } + + @Warmup(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(2) + @BenchmarkMode(Mode.Throughput) + @State(Scope.Thread) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public static class CbrtPerfConstant { + public static final double constDouble0 = 0.0; + public static final double constDouble1 = 1.0; + public static final double constDouble27 = 27.0; + public static final double constDouble512 = 512.0; + + @Benchmark + public double cbrtConstDouble0() { + return Math.cbrt(constDouble0); + } + + @Benchmark + public double cbrtConstDouble1() { + return Math.cbrt(constDouble1); + } + + @Benchmark + public double cbrtConstDouble27() { + return Math.cbrt(constDouble27); + } + + @Benchmark + public double cbrtConstDouble512() { + return Math.cbrt(constDouble512); + } + } + + @Warmup(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(2) + @BenchmarkMode(Mode.Throughput) + @State(Scope.Thread) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public static class CbrtPerfSpecialValues { + public double double0 = 0.0; + public double doubleNegative0 = -0.0; + public double doubleInf = Double.POSITIVE_INFINITY; + public double doubleNegativeInf = Double.NEGATIVE_INFINITY; + public double doubleNaN = Double.NaN; + + @Benchmark + public double cbrtDouble0() { + return Math.cbrt(double0); + } + + @Benchmark + public double cbrtDoubleNegative0() { + return Math.cbrt(doubleNegative0); + } + + @Benchmark + public double cbrtDoubleInf() { + return Math.cbrt(doubleInf); + } + + @Benchmark + public double cbrtDoubleNegativeInf() { + return Math.cbrt(doubleNegativeInf); + } + + @Benchmark + public double cbrtDoubleNaN() { + return Math.cbrt(doubleNaN); + } + } + + public static void main(String[] args) throws RunnerException { + Options opt = new OptionsBuilder() + .include(CbrtPerfRanges.class.getSimpleName()) + .build(); + + new Runner(opt).run(); + + opt = new OptionsBuilder() + .include(CbrtPerfConstant.class.getSimpleName()) + .build(); + + new Runner(opt).run(); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/ClassComparison.java b/test/micro/org/openjdk/bench/java/lang/ClassComparison.java new file mode 100644 index 00000000000..2a768f243e2 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/ClassComparison.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.*; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class ClassComparison { + static final int INVOCATIONS = 1024; + + Class[] c1; + Class[] c2; + int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Object[] resClass; + Class rc1; + Class rc2; + + @Setup + public void setup() { + var random = RandomGenerator.getDefault(); + c1 = new Class[INVOCATIONS]; + c2 = new Class[INVOCATIONS]; + res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; + for (int i = 0; i < INVOCATIONS; i++) { + c1[i] = random.nextBoolean() ? Float.class : Double.class; + } + List list = Arrays.asList(c1); + Collections.shuffle(list); + list.toArray(c2); + } + + @Benchmark + public void equalClass() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (c1[i] == c2[i]) ? 1 : 2; + } + } + + @Benchmark + public void notEqualClass() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (c1[i] != c2[i]) ? 1 : 2; + } + } + + public void equalClassResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (c1[i] == c2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualClassResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (c1[i] != c2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/FPComparison.java b/test/micro/org/openjdk/bench/java/lang/FPComparison.java index 9fe88b934f8..8074ada3257 100644 --- a/test/micro/org/openjdk/bench/java/lang/FPComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/FPComparison.java @@ -23,6 +23,7 @@ package org.openjdk.bench.java.lang; import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; import java.util.concurrent.TimeUnit; import java.util.random.RandomGenerator; @@ -41,6 +42,13 @@ public class FPComparison { float[] f2; double[] d2; int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Class[] resClass; + Class rc1; + Class rc2; @Setup public void setup() { @@ -50,6 +58,13 @@ public void setup() { f2 = new float[INVOCATIONS]; d2 = new double[INVOCATIONS]; res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; for (int i = 0; i < INVOCATIONS; i++) { int type = random.nextInt(5); if (type == 1) { @@ -79,56 +94,184 @@ public void setup() { @Benchmark public void isNanFloat() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Float.isNaN(f1[i]) ? 1 : 0; + res[i] = Float.isNaN(f1[i]) ? 1 : 2; } } @Benchmark public void isNanDouble() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Double.isNaN(d1[i]) ? 1 : 0; + res[i] = Double.isNaN(d1[i]) ? 1 : 2; } } @Benchmark public void isInfiniteFloat() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Float.isInfinite(f1[i]) ? 1 : 0; + res[i] = Float.isInfinite(f1[i]) ? 1 : 2; } } @Benchmark public void isInfiniteDouble() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Double.isInfinite(d1[i]) ? 1 : 0; + res[i] = Double.isInfinite(d1[i]) ? 1 : 2; } } @Benchmark public void isFiniteFloat() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Float.isFinite(f1[i]) ? 1 : 0; + res[i] = Float.isFinite(f1[i]) ? 1 : 2; } } @Benchmark public void isFiniteDouble() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = Double.isFinite(d1[i]) ? 1 : 0; + res[i] = Double.isFinite(d1[i]) ? 1 : 2; } } @Benchmark public void equalFloat() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = (f1[i] == f2[i]) ? 1 : 0; + res[i] = (f1[i] == f2[i]) ? 1 : 2; } } @Benchmark public void equalDouble() { for (int i = 0; i < INVOCATIONS; i++) { - res[i] = (d1[i] == d2[i]) ? 1 : 0; + res[i] = (d1[i] == d2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (f1[i] < f2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (d1[i] < d2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessEqualFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (f1[i] <= f2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessEqualDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (d1[i] <= d2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (f1[i] > f2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (d1[i] > d2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (f1[i] >= f2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (d1[i] >= d2[i]) ? 1 : 2; + } + } + + // --------- result: long --------- + + @Benchmark + public void equalFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] == f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void equalDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] == d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] < f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] < d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] <= f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] <= d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] > f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] > d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualFloatResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (f1[i] >= f2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualDoubleResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (d1[i] >= d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } } diff --git a/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java b/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java new file mode 100644 index 00000000000..1853be8497d --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2025, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class IntegerComparison { + static final int INVOCATIONS = 1024; + + int[] i1; + int[] i2; + int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Object[] resClass; + Class rc1; + Class rc2; + + @Setup + public void setup() { + var random = RandomGenerator.getDefault(); + i1 = new int[INVOCATIONS]; + i2 = new int[INVOCATIONS]; + res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; + for (int i = 0; i < INVOCATIONS; i++) { + i1[i] = random.nextInt(INVOCATIONS); + i2[i] = random.nextInt(INVOCATIONS); + } + } + + @Benchmark + public void equalInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] == i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void notEqualInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] != i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] < i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessEqualInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] <= i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] > i2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualInteger() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (i1[i] >= i2[i]) ? 1 : 2; + } + } + + // --------- result: long --------- + + public void equalIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] == i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] != i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + public void lessIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] < i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] <= i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + public void greaterIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] > i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualIntegerResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (i1[i] >= i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/LongComparison.java b/test/micro/org/openjdk/bench/java/lang/LongComparison.java new file mode 100644 index 00000000000..bed5ee245b2 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/LongComparison.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2025, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.*; + +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class LongComparison { + static final int INVOCATIONS = 1024; + + long[] l1; + long[] l2; + int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Object[] resClass; + Class rc1; + Class rc2; + + @Setup + public void setup() { + var random = RandomGenerator.getDefault(); + l1 = new long[INVOCATIONS]; + l2 = new long[INVOCATIONS]; + res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; + for (int i = 0; i < INVOCATIONS; i++) { + l1[i] = random.nextLong(INVOCATIONS); + l2[i] = random.nextLong(INVOCATIONS); + } + } + + @Benchmark + public void equalLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] == l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void notEqualLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] != l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] < l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void lessEqualLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] <= l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] > l2[i]) ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualLong() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (l1[i] >= l2[i]) ? 1 : 2; + } + } + + // --------- result: long --------- + + public void equalLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] == l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] != l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + public void lessLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] < l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] <= l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + public void greaterLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] > l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualLongResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (l1[i] >= l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/PointerComparison.java b/test/micro/org/openjdk/bench/java/lang/PointerComparison.java new file mode 100644 index 00000000000..b6bcf008619 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/PointerComparison.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.*; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(3) +public class PointerComparison { + static final int INVOCATIONS = 1024; + + Object[] o1; + Object[] o2; + int[] res; + long[] resLong; + Object[] resObject; + Object ro1; + Object ro2; + Object[] resClass; + Class rc1; + Class rc2; + + @Setup + public void setup() { + var random = RandomGenerator.getDefault(); + o1 = new Object[INVOCATIONS]; + o2 = new Object[INVOCATIONS]; + res = new int[INVOCATIONS]; + resLong = new long[INVOCATIONS]; + resObject = new Object[INVOCATIONS]; + ro1 = new Object(); + ro2 = new Object(); + resClass = new Class[INVOCATIONS]; + rc1 = Float.class; + rc2 = Double.class; + for (int i = 0; i < INVOCATIONS; i++) { + o1[i] = new Object(); + } + List list = Arrays.asList(o1); + Collections.shuffle(list); + list.toArray(o2); + } + + @Benchmark + public void equalObject() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (o1[i] == o2[i]) ? 1 : 2; + } + } + + @Benchmark + public void notEqualObject() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = (o1[i] != o2[i]) ? 1 : 2; + } + } + + public void equalObjectResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (o1[i] == o2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualObjectResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = (o1[i] != o2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/StringHashCodeStatic.java b/test/micro/org/openjdk/bench/java/lang/StringHashCodeStatic.java new file mode 100644 index 00000000000..8f4d22a1d86 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/StringHashCodeStatic.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * Performance test of String.hashCode() function with constant folding. + * The tests are using a Map that holds a MethodHandle to better expose + * any potential lack of constant folding. + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 1) +@Fork(value = 3) +public class StringHashCodeStatic { + + private static final String HASHCODE = "abcdefghijkl"; + private static final String HASHCODE_0 = new String(new char[]{72, 90, 100, 89, 105, 2, 72, 90, 100, 89, 105, 2}); + private static final String EMPTY = new String(); + + private static final Map MAP = Map.of( + HASHCODE, mh(HASHCODE.hashCode()), + HASHCODE_0, mh(HASHCODE_0.hashCode()), + EMPTY, mh(EMPTY.hashCode())); + + /** + * Benchmark testing String.hashCode() with a regular 12 char string with + * the result possibly cached in String + */ + @Benchmark + public int nonZero() throws Throwable { + return (int)MAP.get(HASHCODE).invokeExact(); + } + + /** + * Benchmark testing String.hashCode() with a 12 char string with the + * hashcode = 0. + */ + @Benchmark + public int zero() throws Throwable { + return (int)MAP.get(HASHCODE_0).invokeExact(); + } + + /** + * Benchmark testing String.hashCode() with the empty string. an + * empty String has hashCode = 0. + */ + @Benchmark + public int empty() throws Throwable { + return (int)MAP.get(EMPTY).invokeExact(); + } + + static MethodHandle mh(int value) { + return MethodHandles.constant(int.class, value); + } + +} \ No newline at end of file diff --git a/test/micro/org/openjdk/bench/java/lang/TanhPerf.java b/test/micro/org/openjdk/bench/java/lang/TanhPerf.java new file mode 100644 index 00000000000..6747b6b2aa3 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/TanhPerf.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang; + +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Random; + +public class TanhPerf { + + @Warmup(iterations = 3, time = 5, timeUnit = TimeUnit.MILLISECONDS) + @Measurement(iterations = 4, time = 5, timeUnit = TimeUnit.MILLISECONDS) + @Fork(2) + @BenchmarkMode(Mode.Throughput) + @State(Scope.Thread) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public static class TanhPerfRanges { + public static int tanhInputCount = 2048; + + @Param({"0", "1", "2", "3"}) + public int tanhRangeIndex; + + public double [] tanhPosRandInputs; + public double [] tanhNegRandInputs; + public int tanhInputIndex = 0; + public double tanhRangeInputs[][] = {{0.0, 0x1.0P-55}, {0x1.0P-55, 1.0}, {1.0, 22.0}, {22.1, 1.7976931348623157E308} }; + + @Setup + public void setupValues() { + Random random = new Random(1023); + + // Fill the positive and negative tanh vectors with random values + tanhPosRandInputs = new double[tanhInputCount]; + tanhNegRandInputs = new double[tanhInputCount]; + + for (int i = 0; i < tanhInputCount; i++) { + double tanhLowerBound = tanhRangeInputs[tanhRangeIndex][0]; + double tanhUpperBound = tanhRangeInputs[tanhRangeIndex][1]; + tanhPosRandInputs[i] = random.nextDouble(tanhLowerBound, tanhUpperBound); + tanhNegRandInputs[i] = random.nextDouble(-tanhUpperBound, -tanhLowerBound); + } + } + + @Benchmark + @OperationsPerInvocation(2048) + public double tanhPosRangeDouble() { + double res = 0.0; + for (int i = 0; i < tanhInputCount; i++) { + res += Math.tanh(tanhPosRandInputs[i]); + } + return res; + } + + @Benchmark + @OperationsPerInvocation(2048) + public double tanhNegRangeDouble() { + double res = 0.0; + for (int i = 0; i < tanhInputCount; i++) { + res += Math.tanh(tanhNegRandInputs[i]); + } + return res; + } + } + + @Warmup(iterations = 3, time = 5, timeUnit = TimeUnit.SECONDS) + @Measurement(iterations = 4, time = 5, timeUnit = TimeUnit.SECONDS) + @Fork(2) + @BenchmarkMode(Mode.Throughput) + @State(Scope.Thread) + @OutputTimeUnit(TimeUnit.MILLISECONDS) + public static class TanhPerfConstant { + public static final double constDoubleTiny = 0x1.0P-57; + public static final double constDoubleSmall = 0x1.0P-54; + public static final double constDouble1 = 1.0; + public static final double constDouble21 = 21.0; + public static final double constDoubleLarge = 23.0; + + @Benchmark + public double tanhConstDoubleTiny() { + return Math.tanh(constDoubleTiny); + } + + @Benchmark + public double tanhConstDoubleSmall() { + return Math.tanh(constDoubleSmall); + } + + @Benchmark + public double tanhConstDouble1() { + return Math.tanh(constDouble1); + } + + @Benchmark + public double tanhConstDouble21() { + return Math.tanh(constDouble21); + } + + @Benchmark + public double tanhConstDoubleLarge() { + return Math.tanh(constDoubleLarge); + } + } + + public static void main(String[] args) throws RunnerException { + Options opt = new OptionsBuilder() + .include(TanhPerfRanges.class.getSimpleName()) + .build(); + + new Runner(opt).run(); + + opt = new OptionsBuilder() + .include(TanhPerfConstant.class.getSimpleName()) + .build(); + + new Runner(opt).run(); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/BufferStackBench.java b/test/micro/org/openjdk/bench/java/lang/foreign/BufferStackBench.java new file mode 100644 index 00000000000..06f5a352209 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/BufferStackBench.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package org.openjdk.bench.java.lang.foreign; + +import jdk.internal.foreign.BufferStack; +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 java.lang.foreign.Arena; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3, jvmArgs = {"--add-exports=java.base/jdk.internal.foreign=ALL-UNNAMED"}) +public class BufferStackBench { + + @Param({"8", "16", "32"}) + public int ELEM_SIZE; + + private BufferStack bufferStack; + + @Setup + public void setup() { + bufferStack = BufferStack.of(128); + } + + @Benchmark + public long confined() { + try (Arena arena = Arena.ofConfined()) { + return arena.allocate(ELEM_SIZE).address(); + } + } + + @Benchmark + public long buffer() { + try (Arena arena = bufferStack.pushFrame(64, 1)) { + return arena.allocate(ELEM_SIZE).address(); + } + } + + @Fork(value = 3, jvmArgsAppend = "-Djmh.executor=VIRTUAL") + public static class OfVirtual extends BufferStackBench {} + +} + diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadByValue.java b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadByValue.java new file mode 100644 index 00000000000..18ddcda495a --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CallOverheadByValue.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.foreign; + +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.TearDown; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentAllocator; +import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.util.concurrent.TimeUnit; + +import static org.openjdk.bench.java.lang.foreign.CLayouts.C_DOUBLE; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(org.openjdk.jmh.annotations.Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3, jvmArgs = { "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=micro/native" }) +public class CallOverheadByValue { + + public static final MemoryLayout POINT_LAYOUT = MemoryLayout.structLayout( + C_DOUBLE, C_DOUBLE + ); + private static final MethodHandle MH_UNIT_BY_VALUE; + private static final MethodHandle MH_UNIT_BY_PTR; + + static { + Linker abi = Linker.nativeLinker(); + System.loadLibrary("CallOverheadByValue"); + SymbolLookup loaderLibs = SymbolLookup.loaderLookup(); + MH_UNIT_BY_VALUE = abi.downcallHandle( + loaderLibs.findOrThrow("unit"), + FunctionDescriptor.of(POINT_LAYOUT) + ); + MH_UNIT_BY_PTR = abi.downcallHandle( + loaderLibs.findOrThrow("unit_ptr"), + FunctionDescriptor.ofVoid(ValueLayout.ADDRESS) + ); + } + + private static final Arena arena = Arena.ofConfined(); + private static final MemorySegment point = arena.allocate(POINT_LAYOUT); + private static final SegmentAllocator BY_VALUE_ALLOCATOR = (SegmentAllocator) (_, _) -> point; + + @TearDown + public void tearDown() { + arena.close(); + } + + @Benchmark + public void byValue() throws Throwable { + // point = unit(); + MemorySegment unused = (MemorySegment) MH_UNIT_BY_VALUE.invokeExact(BY_VALUE_ALLOCATOR); + } + + @Benchmark + public void byPtr() throws Throwable { + // unit_ptr(&point); + MH_UNIT_BY_PTR.invokeExact(point); + } + + @Fork(value = 3, jvmArgsAppend = "-Djmh.executor=VIRTUAL") + public static class OfVirtual extends CallOverheadByValue {} + +} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/CaptureStateUtilBench.java b/test/micro/org/openjdk/bench/java/lang/foreign/CaptureStateUtilBench.java new file mode 100644 index 00000000000..c833444d713 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/CaptureStateUtilBench.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang.foreign; + +import jdk.internal.foreign.CaptureStateUtil; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.foreign.Arena; +import java.lang.foreign.Linker; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3, jvmArgs = {"--add-exports=java.base/jdk.internal.foreign=ALL-UNNAMED", + "--enable-native-access=ALL-UNNAMED"}) +public class CaptureStateUtilBench { + + private static final String ERRNO_NAME = "errno"; + + private static final VarHandle ERRNO_HANDLE = Linker.Option.captureStateLayout() + .varHandle(MemoryLayout.PathElement.groupElement(ERRNO_NAME)); + + private static final long SIZE = Linker.Option.captureStateLayout().byteSize(); + + private static final MethodHandle DUMMY_EXPLICIT_ALLOC = dummyExplicitAlloc(); + private static final MethodHandle DUMMY_TL_ALLOC = dummyTlAlloc(); + + @Benchmark + public int explicitAllocationSuccess() throws Throwable { + try (var arena = Arena.ofConfined()) { + return (int) DUMMY_EXPLICIT_ALLOC.invokeExact(arena.allocate(SIZE), 0, 0); + } + } + + @Benchmark + public int explicitAllocationFail() throws Throwable { + try (var arena = Arena.ofConfined()) { + return (int) DUMMY_EXPLICIT_ALLOC.invokeExact(arena.allocate(SIZE), -1, 1); + } + } + + @Benchmark + public int adaptedSysCallSuccess() throws Throwable { + return (int) DUMMY_TL_ALLOC.invokeExact(0, 0); + } + + @Benchmark + public int adaptedSysCallFail() throws Throwable { + return (int) DUMMY_TL_ALLOC.invokeExact( -1, 1); + } + + private static MethodHandle dummyExplicitAlloc() { + try { + return MethodHandles.lookup().findStatic(CaptureStateUtilBench.class, + "dummy", MethodType.methodType(int.class, MemorySegment.class, int.class, int.class)); + } catch (ReflectiveOperationException roe) { + throw new RuntimeException(roe); + } + } + + private static MethodHandle dummyTlAlloc() { + final MethodHandle handle = dummyExplicitAlloc(); + return CaptureStateUtil.adaptSystemCall(handle, ERRNO_NAME); + } + + // Dummy method that is just returning the provided parameters + private static int dummy(MemorySegment segment, int result, int errno) { + if (errno != 0) { + // Assuming the capture state is only modified upon detecting an error. + ERRNO_HANDLE.set(segment, 0, errno); + } + return result; + } + + @Fork(value = 3, jvmArgsAppend = "-Djmh.executor=VIRTUAL") + public static class OfVirtual extends CaptureStateUtilBench {} + +} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentFillUnsafe.java b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentFillUnsafe.java new file mode 100644 index 00000000000..18857d4657e --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/MemorySegmentFillUnsafe.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + package org.openjdk.bench.java.lang.foreign; + +import jdk.internal.misc.Unsafe; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; + +import java.util.concurrent.TimeUnit; + +@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, jvmArgs = {"--enable-native-access=ALL-UNNAMED", "--add-opens=java.base/jdk.internal.misc=ALL-UNNAMED"}) +public class MemorySegmentFillUnsafe { + + static final Unsafe UNSAFE = Utils.unsafe; + long src; + + @Param({"1", "2", "3", "4", "5", "6", "7", "8", "15", "16", "63", "64", "255", "256"}) + public int size; + + @Param({"true", "false"}) + public boolean aligned; + + private MemorySegment segment; + private long address; + + @Setup + public void setup() throws Throwable { + Arena arena = Arena.global(); + long alignment = 1; + // this complex logic is to ensure that if in the future we decide to batch writes with different + // batches based on alignment, we would spot it here + if (size == 2 || size == 3) { + alignment = 2; + } else if (size >= 4 && size <= 7) { + alignment = 4; + } else { + alignment = 8; + } + if (aligned) { + segment = arena.allocate(size, alignment); + } else { + // forcibly misaligned in both address AND size, given that would be the worst case + segment = arena.allocate(size + 1, alignment).asSlice(1); + } + address = segment.address(); + } + + @Benchmark + public void panama() { + segment.fill((byte) 99); + } + + @Benchmark + public void unsafe() { + UNSAFE.setMemory(address, size, (byte) 99); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/libCallOverheadByValue.c b/test/micro/org/openjdk/bench/java/lang/foreign/libCallOverheadByValue.c new file mode 100644 index 00000000000..2eb80f537d8 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/libCallOverheadByValue.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "export.h" + +typedef struct { + double x; + double y; +} DoublePoint; + +EXPORT DoublePoint unit() { + DoublePoint result = { 1, 0 }; + return result; +} + +EXPORT void unit_ptr(DoublePoint* out) { + *out = unit(); +} diff --git a/test/micro/org/openjdk/bench/java/lang/stable/StableFunctionBenchmark.java b/test/micro/org/openjdk/bench/java/lang/stable/StableFunctionBenchmark.java new file mode 100644 index 00000000000..44fd3f2c18e --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/stable/StableFunctionBenchmark.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang.stable; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * Benchmark measuring StableValue performance + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) // Share the same state instance (for contention) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 2) +@Fork(value = 2, jvmArgsAppend = { + "--enable-preview" +}) +@Threads(Threads.MAX) // Benchmark under contention +@OperationsPerInvocation(100) +public class StableFunctionBenchmark { + + private static final int SIZE = 100; + private static final Set SET = IntStream.range(0, SIZE).boxed().collect(Collectors.toSet()); + + private static final Map MAP = StableValue.map(SET, Function.identity()); + private static final Function FUNCTION = StableValue.function(SET, Function.identity()); + + private final Map map = StableValue.map(SET, Function.identity()); + private final Function function = StableValue.function(SET, Function.identity()); + + @Benchmark + public int map() { + int sum = 0; + for (int i = 0; i < SIZE; i++) { + sum += map.get(i); + } + return sum; + } + + @Benchmark + public int function() { + int sum = 0; + for (int i = 0; i < SIZE; i++) { + sum += function.apply(i); + } + return sum; + } + + @Benchmark + public int staticSMap() { + int sum = 0; + for (int i = 0; i < SIZE; i++) { + sum += MAP.get(i); + } + return sum; + } + + @Benchmark + public int staticIntFunction() { + int sum = 0; + for (int i = 0; i < SIZE; i++) { + sum += FUNCTION.apply(i); + } + return sum; + } + +} diff --git a/test/micro/org/openjdk/bench/java/lang/stable/StableFunctionSingleBenchmark.java b/test/micro/org/openjdk/bench/java/lang/stable/StableFunctionSingleBenchmark.java new file mode 100644 index 00000000000..1cb1a04582f --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/stable/StableFunctionSingleBenchmark.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang.stable; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * Benchmark measuring StableValue performance + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) // Share the same state instance (for contention) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 2) +@Fork(value = 2, jvmArgsAppend = { + "--enable-preview" +}) +@Threads(Threads.MAX) // Benchmark under contention +public class StableFunctionSingleBenchmark { + + private static final int SIZE = 100; + private static final Set SET = IntStream.range(0, SIZE).boxed().collect(Collectors.toSet()); + + private static final Map MAP = StableValue.map(SET, Function.identity()); + private static final Function FUNCTION = StableValue.function(SET, Function.identity()); + + private final Map map = StableValue.map(SET, Function.identity()); + private final Function function = StableValue.function(SET, Function.identity()); + + @Benchmark + public int map() { + return map.get(1); + } + + @Benchmark + public int function() { + return function.apply(1); + } + + @Benchmark + public int staticSMap() { + return MAP.get(1); + } + + @Benchmark + public int staticIntFunction() { + return FUNCTION.apply(1); + } + +} diff --git a/test/micro/org/openjdk/bench/java/lang/stable/StableIntFunctionBenchmark.java b/test/micro/org/openjdk/bench/java/lang/stable/StableIntFunctionBenchmark.java new file mode 100644 index 00000000000..0b8e5d97cac --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/stable/StableIntFunctionBenchmark.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang.stable; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.IntFunction; + +/** + * Benchmark measuring StableValue performance + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) // Share the same state instance (for contention) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 2) +@Fork(value = 2, jvmArgsAppend = { + "--enable-preview" +}) +@Threads(Threads.MAX) // Benchmark under contention +@OperationsPerInvocation(100) +public class StableIntFunctionBenchmark { + + private static final int SIZE = 100; + private static final IntFunction IDENTITY = i -> i; + + private static final List LIST = StableValue.list(SIZE, IDENTITY); + private static final IntFunction INT_FUNCTION = StableValue.intFunction(SIZE, IDENTITY); + + private final List list = StableValue.list(SIZE, IDENTITY); + private final IntFunction intFunction = StableValue.intFunction(SIZE, IDENTITY); + + @Benchmark + public int list() { + int sum = 0; + for (int i = 0; i < SIZE; i++) { + sum += list.get(i); + } + return sum; + } + + @Benchmark + public int intFunction() { + int sum = 0; + for (int i = 0; i < SIZE; i++) { + sum += intFunction.apply(i); + } + return sum; + } + + @Benchmark + public int staticList() { + int sum = 0; + for (int i = 0; i < SIZE; i++) { + sum += LIST.get(i); + } + return sum; + } + + @Benchmark + public int staticIntFunction() { + int sum = 0; + for (int i = 0; i < SIZE; i++) { + sum += INT_FUNCTION.apply(i); + } + return sum; + } + +} diff --git a/test/micro/org/openjdk/bench/java/lang/stable/StableIntFunctionSingleBenchmark.java b/test/micro/org/openjdk/bench/java/lang/stable/StableIntFunctionSingleBenchmark.java new file mode 100644 index 00000000000..1e8e250ba8a --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/stable/StableIntFunctionSingleBenchmark.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang.stable; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.IntFunction; + +/** + * Benchmark measuring StableValue performance + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) // Share the same state instance (for contention) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 2) +@Fork(value = 2, jvmArgsAppend = { + "--enable-preview" +}) +@Threads(Threads.MAX) // Benchmark under contention +public class StableIntFunctionSingleBenchmark { + + private static final int SIZE = 100; + private static final IntFunction IDENTITY = i -> i; + + private static final List STABLE = StableValue.list(SIZE, IDENTITY); + private static final IntFunction INT_FUNCTION = StableValue.intFunction(SIZE, IDENTITY); + + private final List stable = StableValue.list(SIZE, IDENTITY); + private final IntFunction intFunction = StableValue.intFunction(SIZE, IDENTITY); + + @Benchmark + public int list() { + return stable.get(1); + } + + @Benchmark + public int intFunction() { + return intFunction.apply(1); + } + + @Benchmark + public int staticList() { + return STABLE.get(1); + } + + @Benchmark + public int staticIntFunction() { + return INT_FUNCTION.apply(1); + } + +} diff --git a/test/micro/org/openjdk/bench/java/lang/stable/StableMethodHandleBenchmark.java b/test/micro/org/openjdk/bench/java/lang/stable/StableMethodHandleBenchmark.java new file mode 100644 index 00000000000..95721d88cec --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/stable/StableMethodHandleBenchmark.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang.stable; + +import org.openjdk.bench.java.lang.stable.StableValueBenchmark.Dcl; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +import static java.lang.constant.ConstantDescs.*; + +/** + * Benchmark measuring StableValue performance + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) // Share the same state instance (for contention) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 2) +@Fork(value = 2, jvmArgsAppend = { + "--enable-preview" +}) +@Threads(Threads.MAX) // Benchmark under contention +public class StableMethodHandleBenchmark { + + private static final MethodHandle FINAL_MH = identityHandle(); + private static final StableValue STABLE_MH; + + private static /* intentionally not final */ MethodHandle mh = identityHandle(); + private static final Dcl DCL = new Dcl<>(StableMethodHandleBenchmark::identityHandle); + private static final AtomicReference ATOMIC_REFERENCE = new AtomicReference<>(identityHandle()); + private static final Map MAP = new ConcurrentHashMap<>(); + private static final Map STABLE_MAP = StableValue.map(Set.of("identityHandle"), _ -> identityHandle()); + + static { + STABLE_MH = StableValue.of(); + STABLE_MH.setOrThrow(identityHandle()); + MAP.put("identityHandle", identityHandle()); + } + + @Benchmark + public int atomic() throws Throwable { + return (int) ATOMIC_REFERENCE.get().invokeExact(1); + } + + @Benchmark + public int dcl() throws Throwable { + return (int) DCL.get().invokeExact(1); + } + + @Benchmark + public int finalMh() throws Throwable { + return (int) FINAL_MH.invokeExact(1); + } + + @Benchmark + public int map() throws Throwable { + return (int) MAP.get("identityHandle").invokeExact(1); + } + + @Benchmark + public int nonFinalMh() throws Throwable { + return (int) mh.invokeExact(1); + } + + @Benchmark + public int stableMap() throws Throwable { + return (int) STABLE_MAP.get("identityHandle").invokeExact(1); + } + + @Benchmark + public int stableMh() throws Throwable { + return (int) STABLE_MH.orElseThrow().invokeExact(1); + } + + static MethodHandle identityHandle() { + var lookup = MethodHandles.lookup(); + try { + return lookup.findStatic(StableMethodHandleBenchmark.class, "identity", MethodType.methodType(int.class, int.class)); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } + + private static int identity(int value) { + return value; + } + +} diff --git a/test/micro/org/openjdk/bench/java/lang/stable/StableSupplierBenchmark.java b/test/micro/org/openjdk/bench/java/lang/stable/StableSupplierBenchmark.java new file mode 100644 index 00000000000..883f13da05a --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/stable/StableSupplierBenchmark.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact 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.stable; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Threads; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +/** + * Benchmark measuring StableValue performance + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) // Share the same state instance (for contention) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 2) +@Fork(value = 2, jvmArgsAppend = { + "--enable-preview" +}) +@Threads(Threads.MAX) // Benchmark under contention +@OperationsPerInvocation(2) +public class StableSupplierBenchmark { + + private static final int VALUE = 42; + private static final int VALUE2 = 23; + + private static final StableValue STABLE = init(StableValue.of(), VALUE); + private static final StableValue STABLE2 = init(StableValue.of(), VALUE2); + private static final Supplier SUPPLIER = StableValue.supplier(() -> VALUE); + private static final Supplier SUPPLIER2 = StableValue.supplier(() -> VALUE); + + private final StableValue stable = init(StableValue.of(), VALUE); + private final StableValue stable2 = init(StableValue.of(), VALUE2); + private final Supplier supplier = StableValue.supplier(() -> VALUE); + private final Supplier supplier2 = StableValue.supplier(() -> VALUE2); + + @Benchmark + public int stable() { + return stable.orElseThrow() + stable2.orElseThrow(); + } + + @Benchmark + public int supplier() { + return supplier.get() + supplier2.get(); + } + + @Benchmark + public int staticStable() { + return STABLE.orElseThrow() + STABLE2.orElseThrow(); + } + + @Benchmark + public int staticSupplier() { + return SUPPLIER.get() + SUPPLIER2.get(); + } + + private static StableValue init(StableValue m, Integer value) { + m.trySet(value); + return m; + } + +} diff --git a/test/micro/org/openjdk/bench/java/lang/stable/StableValueBenchmark.java b/test/micro/org/openjdk/bench/java/lang/stable/StableValueBenchmark.java new file mode 100644 index 00000000000..505cfffdc2c --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/stable/StableValueBenchmark.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang.stable; + +import org.openjdk.jmh.annotations.*; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +/** + * Benchmark measuring StableValue performance + */ +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Benchmark) // Share the same state instance (for contention) +@Warmup(iterations = 5, time = 1) +@Measurement(iterations = 5, time = 2) +@Fork(value = 2, jvmArgsAppend = { + "--enable-preview" +}) +@Threads(Threads.MAX) // Benchmark under contention +@OperationsPerInvocation(2) +public class StableValueBenchmark { + + private static final int VALUE = 42; + private static final int VALUE2 = 23; + + private static final StableValue STABLE = init(StableValue.of(), VALUE); + private static final StableValue STABLE2 = init(StableValue.of(), VALUE2); + private static final StableValue DCL = init(StableValue.of(), VALUE); + private static final StableValue DCL2 = init(StableValue.of(), VALUE2); + private static final AtomicReference ATOMIC = new AtomicReference<>(VALUE); + private static final AtomicReference ATOMIC2 = new AtomicReference<>(VALUE2); + private static final Holder HOLDER = new Holder(VALUE); + private static final Holder HOLDER2 = new Holder(VALUE2); + private static final RecordHolder RECORD_HOLDER = new RecordHolder(VALUE); + private static final RecordHolder RECORD_HOLDER2 = new RecordHolder(VALUE2); + + private final StableValue stable = init(StableValue.of(), VALUE); + private final StableValue stable2 = init(StableValue.of(), VALUE2); + private final StableValue stableNull = StableValue.of(); + private final StableValue stableNull2 = StableValue.of(); + private final Supplier dcl = new Dcl<>(() -> VALUE); + private final Supplier dcl2 = new Dcl<>(() -> VALUE2); + private final AtomicReference atomic = new AtomicReference<>(VALUE); + private final AtomicReference atomic2 = new AtomicReference<>(VALUE2); + private final Supplier supplier = () -> VALUE; + private final Supplier supplier2 = () -> VALUE2; + + + @Setup + public void setup() { + stableNull.trySet(null); + stableNull2.trySet(null); + } + + @Benchmark + public int atomic() { + return atomic.get() + atomic2.get(); + } + + @Benchmark + public int dcl() { + return dcl.get() + dcl2.get(); + } + + @Benchmark + public int stable() { + return stable.orElseThrow() + stable2.orElseThrow(); + } + + @Benchmark + public int stableNull() { + return (stableNull.orElseThrow() == null ? VALUE : VALUE2) + (stableNull2.orElseThrow() == null ? VALUE : VALUE2); + } + + // Reference case + @Benchmark + public int refSupplier() { + return supplier.get() + supplier2.get(); + } + + @Benchmark + public int staticAtomic() { + return ATOMIC.get() + ATOMIC2.get(); + } + + @Benchmark + public int staticDcl() { + return DCL.orElseThrow() + DCL2.orElseThrow(); + } + + @Benchmark + public int staticHolder() { + return HOLDER.get() + HOLDER2.get(); + } + + @Benchmark + public int staticRecordHolder() { + return RECORD_HOLDER.get() + RECORD_HOLDER2.get(); + } + + @Benchmark + public int staticStable() { + return STABLE.orElseThrow() + STABLE2.orElseThrow(); + } + + + private static StableValue init(StableValue m, Integer value) { + m.trySet(value); + return m; + } + + private static final class Holder { + + private final StableValue delegate = StableValue.of(); + + Holder(int value) { + delegate.setOrThrow(value); + } + + int get() { + return delegate.orElseThrow(); + } + + } + + private record RecordHolder(StableValue delegate) { + + RecordHolder(int value) { + this(StableValue.of()); + delegate.setOrThrow(value); + } + + int get() { + return delegate.orElseThrow(); + } + + } + + + // Handles null values + public static class Dcl implements Supplier { + + private final Supplier supplier; + + private volatile V value; + private boolean bound; + + public Dcl(Supplier supplier) { + this.supplier = supplier; + } + + @Override + public V get() { + V v = value; + if (v == null) { + if (!bound) { + synchronized (this) { + v = value; + if (v == null) { + if (!bound) { + value = v = supplier.get(); + bound = true; + } + } + } + } + } + return v; + } + } + +} diff --git a/test/micro/org/openjdk/bench/java/lang/stable/VarHandleHolderBenchmark.java b/test/micro/org/openjdk/bench/java/lang/stable/VarHandleHolderBenchmark.java new file mode 100644 index 00000000000..65d53a42e88 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/stable/VarHandleHolderBenchmark.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.lang.stable; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.VarHandle; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; + +import static java.lang.foreign.MemoryLayout.PathElement.groupElement; +import static java.util.concurrent.TimeUnit.*; + +@Warmup(iterations = 5, time = 5, timeUnit = SECONDS) +@Measurement(iterations = 5, time = 5, timeUnit = SECONDS) +@Fork(value = 1, jvmArgs = { "--enable-preview" }) +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(NANOSECONDS) +@State(Scope.Benchmark) +public class VarHandleHolderBenchmark { + + private static final MemoryLayout LAYOUT = MemoryLayout.structLayout( + ValueLayout.JAVA_INT.withName("x"), + ValueLayout.JAVA_INT.withName("y") + ); + + private static final long SIZEOF = LAYOUT.byteSize(); + private static final long OFFSET_X = LAYOUT.byteOffset(MemoryLayout.PathElement.groupElement("x")); + private static final long OFFSET_Y = LAYOUT.byteOffset(groupElement("y")); + + static final class MyVarHandleLookup implements Function { + @Override + public VarHandle apply(String name) { + return LAYOUT.arrayElementVarHandle(groupElement(name)).withInvokeExactBehavior(); + } + } + + private static final Function VAR_HANDLE_FUNCTION = new MyVarHandleLookup(); + + private static final VarHandle VH_X = VAR_HANDLE_FUNCTION.apply("x"); + private static final VarHandle VH_Y = VAR_HANDLE_FUNCTION.apply("y"); + + private static final Supplier SV_X = StableValue.supplier(() -> VAR_HANDLE_FUNCTION.apply("x")); + private static final Supplier SV_Y = StableValue.supplier(() -> VAR_HANDLE_FUNCTION.apply("y")); + + private static final Map U_MAP = Map.of( + "x", VH_X, + "y", VH_Y); + + private static final Map U_MAP_ELEMENT = Map.of( + "x", LAYOUT.varHandle(groupElement("x")), + "y", LAYOUT.varHandle(groupElement("y"))); + + private static final Map S_MAP = StableValue.map( + Set.of("x", "y"), + VAR_HANDLE_FUNCTION); + + private static final Function S_FUN = StableValue.function( + Set.of("x", "y"), + VAR_HANDLE_FUNCTION); + + private static final MemorySegment confined; + static { + var array = new int[512 * (int) SIZEOF / (int) ValueLayout.JAVA_INT.byteSize()]; + var heap = MemorySegment.ofArray(array); + for(var i = 0; i < 512; i++) { + heap.set(ValueLayout.JAVA_INT, i * SIZEOF + OFFSET_X, i); + heap.set(ValueLayout.JAVA_INT, i * SIZEOF + OFFSET_Y, i); + } + confined = Arena.ofConfined().allocate(LAYOUT, 512); + confined.copyFrom(heap); + } + + @Benchmark + public int confinedVarHandleLoop() { + var sum = 0; + for (var i = 0; i < 512; i++) { + var x = (int) VH_X.get(confined, 0L, (long) i); + var y = (int) VH_Y.get(confined, 0L, (long) i); + sum += x /*+y*/; + } + return sum; + } + + @Benchmark + public int confinedStableValueLoop() { + var sum = 0; + for (var i = 0; i < 512; i++) { + var x = (int) SV_X.get().get(confined, 0L, (long) i); + var y = (int) SV_Y.get().get(confined, 0L, (long) i); + sum += x + y; + } + return sum; + } + + @Benchmark + public int confinedStableMapLoop() { + var sum = 0; + for (var i = 0; i < 512; i++) { + var x = (int) S_MAP.get("x").get(confined, 0L, (long) i); + var y = (int) S_MAP.get("y").get(confined, 0L, (long) i); + sum += x + y; + } + return sum; + } + + @Benchmark + public int confinedStableMapElementLoop() { + var sum = 0; + for (var i = 0; i < 512; i++) { + var x = (int) U_MAP_ELEMENT.get("x").get(confined, i * 8L); + var y = (int) U_MAP_ELEMENT.get("y").get(confined, i * 8L); + sum += x + y; + } + return sum; + } + + @Benchmark + public int confinedUnmodifiableMapLoop() { + var sum = 0; + for (var i = 0; i < 512; i++) { + var x = (int) U_MAP.get("x").get(confined, 0L, (long) i); + var y = (int) U_MAP.get("y").get(confined, 0L, (long) i); + sum += x + y; + } + return sum; + } + + @Benchmark + public int confinedStableFunctionLoop() { + var sum = 0; + for (var i = 0; i < 512; i++) { + var x = (int) S_FUN.apply("x").get(confined, 0L, (long) i); + var y = (int) S_FUN.apply("y").get(confined, 0L, (long) i); + sum += x + y; + } + return sum; + } +} \ No newline at end of file diff --git a/test/micro/org/openjdk/bench/java/math/BigDecimals.java b/test/micro/org/openjdk/bench/java/math/BigDecimals.java index 3c443db013f..e9f5ba90a7b 100644 --- a/test/micro/org/openjdk/bench/java/math/BigDecimals.java +++ b/test/micro/org/openjdk/bench/java/math/BigDecimals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -227,4 +227,23 @@ public void testCompareTo(Blackhole bh) { bh.consume(c.compareTo(s)); } } + + + /** Invokes the valueOf(double) of BigDecimal with various different values. */ + @Benchmark + @OperationsPerInvocation(TEST_SIZE) + public void testValueOfWithDouble(Blackhole bh) { + for (double s : doubleInputs) { + bh.consume(BigDecimal.valueOf(s)); + } + } + + /** Create BigDecimal from double with Double.toString on different values. */ + @Benchmark + @OperationsPerInvocation(TEST_SIZE) + public void testValueOfWithDoubleString(Blackhole bh) { + for (double s : doubleInputs) { + bh.consume(new BigDecimal(Double.toString(s))); + } + } } diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegerPow.java b/test/micro/org/openjdk/bench/java/math/BigIntegerPow.java new file mode 100644 index 00000000000..007d9bb975a --- /dev/null +++ b/test/micro/org/openjdk/bench/java/math/BigIntegerPow.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.math; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; +import org.openjdk.jmh.profile.GCProfiler; + +import java.math.BigInteger; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 1, time = 1) +@Measurement(iterations = 1, time = 1) +@Fork(value = 3) +public class BigIntegerPow { + + private static final int TESTSIZE = 1; + + private int xsExp = (1 << 20) - 1; + /* Each array entry is atmost 64 bits in size */ + private BigInteger[] xsArray = new BigInteger[TESTSIZE]; + + private int sExp = (1 << 18) - 1; + /* Each array entry is atmost 256 bits in size */ + private BigInteger[] sArray = new BigInteger[TESTSIZE]; + + private int mExp = (1 << 16) - 1; + /* Each array entry is atmost 1024 bits in size */ + private BigInteger[] mArray = new BigInteger[TESTSIZE]; + + private int lExp = (1 << 14) - 1; + /* Each array entry is atmost 4096 bits in size */ + private BigInteger[] lArray = new BigInteger[TESTSIZE]; + + private int xlExp = (1 << 12) - 1; + /* Each array entry is atmost 16384 bits in size */ + private BigInteger[] xlArray = new BigInteger[TESTSIZE]; + + private int[] randomExps; + + /* + * You can run this test via the command line: + * $ make test TEST="micro:java.math.BigIntegerPow" MICRO="OPTIONS=-prof gc" + */ + + @Setup + public void setup() { + Random r = new Random(1123); + + randomExps = new int[TESTSIZE]; + for (int i = 0; i < TESTSIZE; i++) { + xsArray[i] = new BigInteger(64, r); + sArray[i] = new BigInteger(256, r); + mArray[i] = new BigInteger(1024, r); + lArray[i] = new BigInteger(4096, r); + xlArray[i] = new BigInteger(16384, r); + randomExps[i] = r.nextInt(1 << 12); + } + } + + /** Test BigInteger.pow() with numbers long at most 64 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowXS(Blackhole bh) { + for (BigInteger xs : xsArray) { + bh.consume(xs.pow(xsExp)); + } + } + + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowXSRandomExps(Blackhole bh) { + int i = 0; + for (BigInteger xs : xsArray) { + bh.consume(xs.pow(randomExps[i++])); + } + } + + /** Test BigInteger.pow() with numbers long at most 256 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowS(Blackhole bh) { + for (BigInteger s : sArray) { + bh.consume(s.pow(sExp)); + } + } + + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowSRandomExps(Blackhole bh) { + int i = 0; + for (BigInteger s : sArray) { + bh.consume(s.pow(randomExps[i++])); + } + } + + /** Test BigInteger.pow() with numbers long at most 1024 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowM(Blackhole bh) { + for (BigInteger m : mArray) { + bh.consume(m.pow(mExp)); + } + } + + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowMRandomExps(Blackhole bh) { + int i = 0; + for (BigInteger m : mArray) { + bh.consume(m.pow(randomExps[i++])); + } + } + + /** Test BigInteger.pow() with numbers long at most 4096 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowL(Blackhole bh) { + for (BigInteger l : lArray) { + bh.consume(l.pow(lExp)); + } + } + + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowLRandomExps(Blackhole bh) { + int i = 0; + for (BigInteger l : lArray) { + bh.consume(l.pow(randomExps[i++])); + } + } + + /** Test BigInteger.pow() with numbers long at most 16384 bits */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowXL(Blackhole bh) { + for (BigInteger xl : xlArray) { + bh.consume(xl.pow(xlExp)); + } + } + + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testPowXLRandomExps(Blackhole bh) { + int i = 0; + for (BigInteger xl : xlArray) { + bh.consume(xl.pow(randomExps[i++])); + } + } +} diff --git a/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java b/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java index 505e124e43e..652ed134c39 100644 --- a/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java +++ b/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java @@ -27,9 +27,9 @@ import java.net.UnixDomainSocketAddress; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; -import java.nio.file.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; @@ -49,55 +49,31 @@ public class SocketChannelConnectionSetup { private ServerSocketChannel ssc; - private SocketChannel s1, s2; - - private static volatile String tempDir; - private static final AtomicInteger count = new AtomicInteger(0); - private volatile Path socket; - - @Param({"inet", "unix"}) - private volatile String family; - static { - try { - Path p = Files.createTempDirectory("readWriteTest"); - tempDir = p.toString(); - } catch (IOException e) { - tempDir = null; - } - } + private Path sscFilePath; - private ServerSocketChannel getServerSocketChannel() throws IOException { - if (family.equals("inet")) - return getInetServerSocketChannel(); - else if (family.equals("unix")) - return getUnixServerSocketChannel(); - throw new InternalError(); - } - - - private ServerSocketChannel getInetServerSocketChannel() throws IOException { - return ServerSocketChannel.open().bind(null); - } + private SocketChannel s1, s2; - private ServerSocketChannel getUnixServerSocketChannel() throws IOException { - int next = count.incrementAndGet(); - socket = Paths.get(tempDir, Integer.toString(next)); - UnixDomainSocketAddress addr = UnixDomainSocketAddress.of(socket); - return ServerSocketChannel.open(StandardProtocolFamily.UNIX).bind(addr); - } + @Param({"INET", "UNIX"}) + private String family; @Setup(Level.Trial) public void beforeRun() throws IOException { - ssc = getServerSocketChannel(); + StandardProtocolFamily typedFamily = StandardProtocolFamily.valueOf(family); + ssc = ServerSocketChannel.open(typedFamily).bind(null); + // Record the UDS file path right after binding, as the socket may be + // closed later due to a failure, and subsequent calls to `getPath()` + // will throw. + sscFilePath = ssc.getLocalAddress() instanceof UnixDomainSocketAddress udsChannel + ? udsChannel.getPath() + : null; } @TearDown(Level.Trial) - public void afterRun() throws IOException { + public void afterRun() throws Exception { ssc.close(); - if (family.equals("unix")) { - Files.deleteIfExists(socket); - Files.deleteIfExists(Path.of(tempDir)); + if (sscFilePath != null) { + Files.delete(sscFilePath); } } diff --git a/test/micro/org/openjdk/bench/java/net/SocketEventOverhead.java b/test/micro/org/openjdk/bench/java/net/SocketEventOverhead.java index c405de0af3c..0ba577f49d7 100644 --- a/test/micro/org/openjdk/bench/java/net/SocketEventOverhead.java +++ b/test/micro/org/openjdk/bench/java/net/SocketEventOverhead.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ public int socketWriteJFREnabledEventDisabled(SkeletonFixture fixture) { @Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.event=ALL-UNNAMED", - "-XX:StartFlightRecording:jdk.SocketWrite#enabled=true,jdk.SocketWrite#threshold=1s"}) + "-XX:StartFlightRecording:jdk.SocketWrite#enabled=true,jdk.SocketWrite#threshold=1s,jdk.SocketWrite#throttle=off"}) @Benchmark public int socketWriteJFREnabledEventNotEmitted(SkeletonFixture fixture) { return fixture.write(); @@ -73,7 +73,7 @@ public int socketWriteJFREnabledEventNotEmitted(SkeletonFixture fixture) { @Fork(value = 1, jvmArgs = { "--add-exports","java.base/jdk.internal.event=ALL-UNNAMED", - "-XX:StartFlightRecording:jdk.SocketWrite#enabled=true,jdk.SocketWrite#threshold=0ms,disk=false,jdk.SocketWrite#stackTrace=false"}) + "-XX:StartFlightRecording:jdk.SocketWrite#enabled=true,jdk.SocketWrite#threshold=0ms,disk=false,jdk.SocketWrite#stackTrace=false,jdk.SocketWrite#throttle=off"}) @Benchmark public int socketWriteJFREnabledEventEmitted(SkeletonFixture fixture) { return fixture.write(); @@ -99,7 +99,7 @@ public int socketReadJFREnabledEventDisabled(SkeletonFixture fixture) { @Fork(value = 1, jvmArgs = { "--add-exports", "java.base/jdk.internal.event=ALL-UNNAMED", - "-XX:StartFlightRecording:jdk.SocketRead#enabled=true,jdk.SocketRead#threshold=1s"}) + "-XX:StartFlightRecording:jdk.SocketRead#enabled=true,jdk.SocketRead#threshold=1s,jdk.SocketRead#throttle=off"}) @Benchmark public int socketReadJFREnabledEventNotEmitted(SkeletonFixture fixture) { return fixture.read(); @@ -107,7 +107,7 @@ public int socketReadJFREnabledEventNotEmitted(SkeletonFixture fixture) { @Fork(value = 1, jvmArgs = { "--add-exports","java.base/jdk.internal.event=ALL-UNNAMED", - "-XX:StartFlightRecording:jdk.SocketRead#enabled=true,jdk.SocketRead#threshold=0ms,disk=false,jdk.SocketRead#stackTrace=false"}) + "-XX:StartFlightRecording:jdk.SocketRead#enabled=true,jdk.SocketRead#threshold=0ms,disk=false,jdk.SocketRead#stackTrace=false,jdk.SocketRead#throttle=off"}) @Benchmark public int socketReadJFREnabledEventEmitted(SkeletonFixture fixture) { return fixture.read(); @@ -137,10 +137,7 @@ public int write() { try { nbytes = write0(); } finally { - long duration = start - SocketWriteEvent.timestamp(); - if (SocketWriteEvent.shouldCommit(duration)) { - SocketWriteEvent.emit(start, duration, nbytes, getRemoteAddress()); - } + SocketWriteEvent.offer(start, nbytes, getRemoteAddress()); } return nbytes; } @@ -158,10 +155,7 @@ public int read() { try { nbytes = read0(); } finally { - long duration = start - SocketReadEvent.timestamp(); - if (SocketReadEvent.shouldCommit(duration)) { - SocketReadEvent.emit(start, duration, nbytes, getRemoteAddress(), 0); - } + SocketReadEvent.offer(start, nbytes, getRemoteAddress(), 0); } return nbytes; } diff --git a/test/micro/org/openjdk/bench/java/net/UnixSocketChannelReadWrite.java b/test/micro/org/openjdk/bench/java/net/UnixSocketChannelReadWrite.java index 64b44446bcd..ffcb2739b0d 100644 --- a/test/micro/org/openjdk/bench/java/net/UnixSocketChannelReadWrite.java +++ b/test/micro/org/openjdk/bench/java/net/UnixSocketChannelReadWrite.java @@ -47,23 +47,18 @@ public class UnixSocketChannelReadWrite { private ServerSocketChannel ssc; + private Path sscFilePath; private SocketChannel s1, s2; private ReadThread rt; private ByteBuffer bb = ByteBuffer.allocate(1); - private volatile Path socket; - - private ServerSocketChannel getServerSocketChannel() throws IOException { - socket = Files.createTempDirectory(UnixSocketChannelReadWrite.class.getSimpleName()).resolve("sock"); - UnixDomainSocketAddress addr = UnixDomainSocketAddress.of(socket); - ServerSocketChannel c = ServerSocketChannel.open(StandardProtocolFamily.UNIX); - c.bind(addr); - return c; - } - @Setup(Level.Trial) public void beforeRun() throws IOException { - ssc = getServerSocketChannel(); + ssc = ServerSocketChannel.open(StandardProtocolFamily.UNIX).bind(null); + // Record the UDS file path right after binding, as the socket may be + // closed later due to a failure, and subsequent calls to `getPath()` + // will throw. + sscFilePath = ((UnixDomainSocketAddress) ssc.getLocalAddress()).getPath(); s1 = SocketChannel.open(ssc.getLocalAddress()); s2 = ssc.accept(); @@ -79,8 +74,7 @@ public void afterRun() throws IOException, InterruptedException { s1.close(); s2.close(); ssc.close(); - Files.delete(socket); - Files.delete(socket.getParent()); + Files.delete(sscFilePath); rt.join(); } diff --git a/test/micro/org/openjdk/bench/java/security/MLDSA.java b/test/micro/org/openjdk/bench/java/security/MLDSA.java deleted file mode 100644 index 36b616ab599..00000000000 --- a/test/micro/org/openjdk/bench/java/security/MLDSA.java +++ /dev/null @@ -1,830 +0,0 @@ -/* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact 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.security; - -import org.openjdk.jmh.annotations.*; -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.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.InterruptedException; -import java.security.DigestException; -import java.security.NoSuchAlgorithmException; -import java.security.KeyPair; -import java.util.Arrays; -import java.util.HexFormat; -import java.util.concurrent.TimeUnit; - -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.MICROSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 5, time = 1) -@Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgs = {"--add-opens", "java.base/sun.security.provider=ALL-UNNAMED"}) - -public class MLDSA { - @Param({"ML-DSA-44", "ML-DSA-65", "ML-DSA-87"} ) - private static String algorithm; - - @State(Scope.Thread) - public static class MyState { - - Object mldsa44; - Object mldsa65; - Object mldsa87; - - MethodHandle keygen, siggen, sigver; - - @Setup(Level.Trial) - public void setup() throws Throwable, Exception { - - MethodHandles.Lookup lookup = MethodHandles.lookup(); - Class kClazz = Class.forName("sun.security.provider.ML_DSA"); - Constructor constructor = kClazz.getDeclaredConstructor( - int.class); - constructor.setAccessible(true); - - Method m = kClazz.getDeclaredMethod("generateKeyPairInternal", - byte[].class); - m.setAccessible(true); - keygen = lookup.unreflect(m); - - m = kClazz.getDeclaredMethod("signInternal", - byte[].class, byte[].class, byte[].class); - m.setAccessible(true); - siggen = lookup.unreflect(m); - - m = kClazz.getDeclaredMethod("verifyInternal", - byte[].class, byte[].class, byte[].class); - m.setAccessible(true); - sigver = lookup.unreflect(m); - - mldsa44 = constructor.newInstance(2); - mldsa65 = constructor.newInstance(3); - mldsa87 = constructor.newInstance(5); - } - } - - @Benchmark - public void keygen(MyState myState) throws Throwable { - switch (algorithm) { - case "ML-DSA-44": - for (KeyGenTestCase testCase : KeyGenTestCases44) { - myState.keygen.invoke(myState.mldsa44, testCase.seed); - } - break; - case "ML-DSA-65": - for (KeyGenTestCase testCase : KeyGenTestCases65) { - myState.keygen.invoke(myState.mldsa65, testCase.seed); - } - break; - case "ML-DSA-87": - for (KeyGenTestCase testCase : KeyGenTestCases87) { - myState.keygen.invoke(myState.mldsa87, testCase.seed); - } - break; - } - } - - @Benchmark - public void siggen(MyState myState) throws Throwable { - byte[] rnd = new byte[32]; - switch (algorithm) { - case "ML-DSA-44": - for (SigGenTestCase testCase : SigGenTestCases44) { - myState.siggen.invoke(myState.mldsa44, testCase.msg, - rnd, testCase.sk); - } - break; - case "ML-DSA-65": - for (SigGenTestCase testCase : SigGenTestCases65) { - myState.siggen.invoke(myState.mldsa65, testCase.msg, - rnd, testCase.sk); - } - break; - case "ML-DSA-87": - for (SigGenTestCase testCase : SigGenTestCases87) { - myState.siggen.invoke(myState.mldsa87, testCase.msg, - rnd, testCase.sk); - } - } - } - - @Benchmark - public void sigver(MyState myState) throws Throwable { - switch (algorithm) { - case "ML-DSA-44": - for (SigVerTestCase testCase : SigVerTestCases44) { - myState.sigver.invoke(myState.mldsa44, testCase.pk, - testCase.msg, testCase.sig); - } - break; - case "ML-DSA-65": - for (SigVerTestCase testCase : SigVerTestCases65) { - myState.sigver.invoke(myState.mldsa65, testCase.pk, - testCase.msg, testCase.sig); - } - break; - case "ML-DSA-87": - for (SigVerTestCase testCase : SigVerTestCases87) { - myState.sigver.invoke(myState.mldsa87, testCase.pk, - testCase.msg, testCase.sig); - } - } - } - - static class TestUtils { - static void printHex(String s, byte[] h) { - System.out.println(HexFormat.of().formatHex(h)); - } - static byte[] hexDecode(String s) { - return HexFormat.of().parseHex(s); - } - } - - record KeyGenTestCase( - byte[] seed) { - } - record SigGenTestCase( - byte[] sk, - byte[] msg, - byte[] sig) { - } - record SigVerTestCase( - byte[] pk, - byte[] msg, - byte[] sig) { - } - - static KeyGenTestCase[] KeyGenTestCases44 = new KeyGenTestCase[] { - new KeyGenTestCase( - TestUtils.hexDecode(""" -796732acba3efdf731bf7c242aeeddf5eba5b131da90e36af23a3bce9c7aa93a""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -60d235ddc4f334bfd91d6b7df1a4fed84c88c2933806f13fe06ef15aed96c9e1""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -c14612e7a22ec88bb5e9dcf865776c37cd5b1c6d1b18798be80b9562ba4752e1""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -ed5bf4a40e4ce8d367598819be8ec4ed706df4d26819f69729c2acf274515c8e""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -78981182b43d78c40b828554c36d70b960a02c66490c15a4caa6a7d5f1e9ce34""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -917a2234587c5969cc1ed10d51b0dcf8b3017143ebf31687930f3e2c610a4850""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -df022c3c86b725c5f2b54196b7d68684b9fde93be78e38beaeef18195321f4e2""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -865f638c38f0852d2d712a708ffbd7d96f0df21071d8bfec74c2302ea4c5adba""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -741a60c9f1715c42a5a9e67b4e69e5f128372002a6c4f54ae5869500171e2541""") - ) - }; - - static SigGenTestCase[] SigGenTestCases44 = new SigGenTestCase[] { - new SigGenTestCase( - TestUtils.hexDecode(""" -8109bb66b04ddeddb48e77501a8b1e2431fefb69da28a572fc535be604e351cd9301291a5725ca7d7f76270174b0db0688bcb93ecfcf0910b31afe84d7f16ab5782238b7afe42480fd01964142f634d8d50924dee8016f381b69cf0e6f9606e3c2d68b0929c489a45eaecc40008d64ea69676d454115d8d2f1413962db5eb800db36210a246581384eca982121076083a609c4828089424511996c5c164c183669841624e016259334021b123003840920b6854c984921b760021666943849813442c8c84dc8820124829064460c5a4430828089da381253b665898290e0086cda86802428721a244c9ca41108c550dc868120b93121052210134a93a4284ca485914826d3480a59124e63944464223161362e52b824e1346ddc34511c084523823192c29084b89100c92819139294186ac326494224214a0821c0382c9842504a8884cac2882102865c366420080614b330e4380604a820c390450ca48d63062561946c42947014972198c2094b422dca06015b000cda468edb00659a18712448840ab1814300900bc84523010802b240d08865a31262213091598024d908081c89051a1502db3850033666030521c1b489800070e3048061a25058c6091c318244244dc444300b130cc8c401d2320a51a26c88226a01b4810015711a2840631629624866804202a3440d0a160ec3204d0212481b406ccc4611418200030781049588243822621200e2c24c1a19682224008ca46844c608dc288cd034411c03520c0050501082d44885d2b66d50088103160c22c964db2484c84290dcc801a3227254322e14030e189808c4385122a69111266402182a210172649240d844248420210ac9414b80448ac669e1c664c3808598020948982d01450660446424264c09122ad2b04c9c4691211832238841c0a66d41422a49a20022204ca0360120968c18a088dc142a9042082122640c2649d014048c90280300700c40822420229bb285e18651c0a86c94b0218822805306250800111212008440224028728aa60ce2867114354264a409c2228604385282428e103422e0c0480a968954966c20c87181382894463003104cc4462d22068dcc180ec400911291644a926c9ba26908b9411ab08082966d03026d9a16422244419bb49112a06108c71112b625010202c90862201646212731db144113152521c22199322c10832522495010250ec3844d4cc6658a24129b24001b020c91c4105b88710c44851b227012278d138871d31ee0376e3631e0a724ad187fe258ba1af825ab5c3a8bb76a3ae308d11580696408ca1d21d4591311c3d6fbc0744aae0431c7c70d40c7447f5b9f6530c21f965022b9919db9f553dd1cb74faef7163c83b219533d3c2fd3a8204b55cee8792de783358f944c2674fb79230fa808353907f1e56aec8c39e9e6e64f83b4552d76723f41d44ce494483113c6f63e3fa0a8868fced1433adb004b8cb502a9998671fe73a914adc2c42c64cf9eb2e77ae709229bdff22046d5018a5193c6de49fd45f15d151e1c0dc4473a9948bb5bbcf29489a072ad81200c16182b034e29654f9da3d35d7b1f3cb9bbc4e6acbd97836ec4787a8b918509aeb811bfeb242be7fabebe5bdef46aa405dfdf36811e1cf980acb00eb323493b260a542dd2b0b46a3d571901216369e58e855c18a6276db360b0eab396672ad9635bba154b1b4fe0490818b17039da441f055a87c65d902bfbc2a39e94729522b69d4e47c4122b5b19b87e6fb85a1bd682edabb0772e74ad9eeea2e0758e2f8d3e4dcec752e88e936bcdced768911cf6c33819a5a86eb6fcdc4efc375c3e0a21e49cd4ab4827442c96bc176de8b294daa0f41b8ca536e6e12b915750304a71a1b3983b6330289f646e98b3c7fc38af5ff63a988564d85f0608ae9937d2c425464a59150e83daa2d049c1c80205acdc18f65187ead4bc78fbf1416c00fe0960355649786d83520cc7e3f4779b212abd329c4d4093d07c9e0082267a0abfcd6a391645eff624e47137765df08c924abc1a52ba8f4067c3073e7b2d48eee5b366db9e960a6e55aa0e4b48e4695b880dceb98912a18f671d262703541c8e5e4bc16b9362bed20f58d5f5a1818800308b1922cca258e8429490ee4fa79ac5f654b67993933e983c5874d696a8aa46ea0c27113229387fc6679cbda800c4a934625ef3102032db2674b7123cb748521b0a67e83aa906bc52ebe7f222b118661a3980102711ff679e4b6242b9010e8a894ba5c93188d03ad8da548a9e59e0d9f1e08c27abb8027708eaa8899495bb4b289ab03f562e821a7b97118cee1389ca5257efd73cc53a5c5ea9d2588a3e835acb268159434c09923ca92f34aaa22a7f8cce15c800fa385f49a7d15772f81277a8ac2238fd34c0eedf75ed2bb6a983f45d27d9b972f4796923274c588f9d1e6366c805623255528cba1500c88870395207f19d39c5eaa80ee5bd9e776fe73017ca32ba0b0055da4452bd1f96a162ee32edc587553ea47fc3bcc10e27f9a29ef9deba54150032a2608cbe2ae2b8f597fff99fea769b76d090f5922207f17aac49355c756ae802a50f7f5f6990cdcb0b31d8fd6a9b4915d91f0fba752f8424c4aa257c78f2c378364fa6b6892efe4744e2d77d0c5f02c2cf7ac28ba757d96c2c26dcaab0e9f2371ce6e1e7111cc5209a0e053924bd5202eece6d4135ea05c76040ee5f2c195fd76b4dabc10eb03a9b4b36c8e0b723110b1a5ff8cb4bd3f0f49f7dd866f8803c84c083171b1a3ccfbf1bbf90b524dd69acdb9ee7d0928cf484f90d442b815bc91c6b98368bdfefe0e63b5e9039959e7c369b38cfc78a49f596581282f820609ea8e76b2a15d78fd3cfe70cc933af7e8b5d1b28aa0ca8f14479c6bad013d93df59e237ebd3c4f96be20893577b8e98b875e40fb96da3fd0b69b2c4a9803f92d7443db64b61c5bb8f3493b7d3d7115e97c83448a17170364d7342b19f7f1eb8a28907ae0dfc62ea5b17154d4ca3a91a3b61db1bed25dd2b9436925d4de903e559441a7cb80b464ad873227230295676f2ae7822ea85f30c88596fa988e05a60b8d53beda03e203432428bf799561186b1fc1d2c499daef45cb555556ed52fd8ced0864814bb27616171e95239d1dcb3bbbfd91e5e1f0d876cc6ceebeb8be145ee063ce49faffd41145db908b13dee8df37f8b01d1a800f10bcadedb5e8f663a4af4c37a0b09f9e0b2e42dcd4aaa901b6781f5ed8591ede5613241d67c71a077da204ce912a4db8d5d083e405abc3e6ec6d5781a9499eb8e2427e7a928fbc0feb403b797f1dce6c7a83dfba45ba76af2a3231d751bbc9e1f7d0750a998b3b39df2cd0fa485523b359b93ca56de28087830cf984559a899b0d55a9ef696cc60b0fb2217da1f7e57fca279b7a4d5e948d1cdb7fac235445950b0fa7dd9b1284fb09ae113ab9fb4b03f130114f1091a471f185384a0913da65c9153a239cf69e5977a387ea9a3f1c665acb9130e7256d40f8a8e029554c047ad63eb9bca4198b45f7b03e8cd22d1ab05fe4f30de749d97fcea394482cd4c2116870b009d1c890ac6f5099d45d0c37909d9ae58b0823fed17137eb7ef016466c1cd06a"""), - TestUtils.hexDecode(""" -430B1F46E87DDE9A3D055A7D4D6AB1277B2DA6EDA642896412126391AA2B29AFD81C246EC839929F5C06749491DC4D81D58CC989D8500B6879E8807B1C3AA0B199EB599AEB86B344B77E3DB1AA034C938D80CB4BDCC29B31B710F57C7E491D99B71E97DD6FDA01A0D8A54C7481C2786F64FFC53AD358CF31C9C875ED278CEA03F2BF732372B19252BB9FA4ABF465FA2CFD1C08684D10582B410A8E012DBD407C5140D97CEE768C6D68124B2C84113B58C9A2AA67093B44CC3B6199FF1EFA6506CC28BD30BEC4CEA88411A491DD948DDB09ADFB92C40CA50E709840BC1F107E0CA428C111EC4505C5346E74AE4AB5647C1EB80F9C07092F8D39A975C4890317F9C0EF474110AB941949029BF39ADFB8E65CCAC0360A3EFCEB69D2BD805E4FC8D0620F8E039BC046DFEF1ADB03F5995FF62AD41352D479084EF3E302578B83332506918CFAD6E3BA701C94B0138DF0CF6C2948049274CE61EE0A64E756306273A02D68F3C405883F2F668820356812B2DA3A32B9FF23608DFA559183151221F83DCA18253FCA099FE24728F302C8B7808D7AF978299F3EB853A8BECDA46B8657598BE9ECE8A02DD4B25C593DDCB436B82335EF9C6A7B8426B701C66C9EBBFB3C8405A73881DAB57D1664F3AEC6F5BA19155D89A0A80B5D01C46BC79E1D4338A50B203397CD4B16ACD597A7C77C49917E9FE4B0D761065CB89C758498868B14BE2B6FF758745AFDC535EAA605C3F97648034D2A320264150278A7F1CB114B977C9D6BC1F29295CCCA16B23B7709D5608E4095E41D08B22AEC6289ED402414787062B0DA2387B6DEE76B32E42C51788B65E815E089BCF92D778F49A9707D37FCFBDF8CEF953A48A4201FA0173529BA360BFA6A77200F57FD5245146C2CD7FE8882670EE6878386D06036F0E1BA4B728CFB75806F05BA6409C514731B0BA8DA11015A63A8B5B5AB8C69703185191D12C5611F1407E8FFE3E50FC39C3310EF4091BC09FECC11D3AC107C696EE89F74CD6147830B4B3A971A0027747B62C528F6D858D1F9E67F59496C6B4E9E03FF0A598B26625B06C79863B5F07E265A40175E1A6D6EF3F900F3C4A28AD3E49D4D0B7E4ECEBB79244264474CCBFADA43FCD33F4FEBEB0F7E5928479F869D6A0FE52EB0CAC1232D7F674A057DEC4C2248934A40F5E2C9CBFDD53F71FC3BE06E48E13398ED426D8D3CC82118B7E8E5BDCA248380F4E64C427D1BF2384F60F6A07F01EE62AA1746CB143F26412547E7EF0E8FD1F2DC606F3643DEAF330D81CD6309465F9ED7F34D9B175FE1641D90212D4FFFB91CC300E7DFA0C555F7B35D2AF6A343D1467436EEC7AB95F2C34010FC99D66391377770A7DB8CD4D5C6BBF931092322741929F790E037318D6ADB74B4768C11F0E4674D18185DFB3D051725F93800CD38F58688AAC747F885908804D6CADAEDECB43131D75B18FBA2D4BED8D9BCC2156FB23F8F6378C622153EA8301300D0FCDEF1E2BB4E6F807784EA0171E95C372EC19B05A6C7B8DECE7080A057D29CE5A445A83410EB83B174590647424736A3B6967BCDF8A416A51202CE3F00E4D97DCC2C48A78D12CDA98E94A9BD6CCBE09DAF8085304F6911ECED3547DE9512461E16721322E4E6233BC7CA360A9004DA5AE064514603EFF0DF4E2D8EB04E9574C59F3AC14726C10100C688203F4960197CE696730AD7E558D7B939E3E6E7EAC4E70A7F6AAA80C1F1546E282B5CC7AA193213769B137C7F450AE5410817166F29F2E4E7E962932DF282A9F08A1DEF3E19C251F95611DDA9CFF4E2FED873439B45F8451B9AE06C6B2C698778BC4C742708BDB54CB35B686F0E7FC856CDBF977AFB663DFE44F7FCCE0E0555BE81EB28984BAFBD6FED3F0182F78A1396AF7B7081280864E5E4BFD7C52DA28BB5DE5FFA211678D13D41BF825F4B21BE1CBD29719ABA341E7B0C3F101CEDFE2F709E4DA4B5A6D0C021152AB546837024F4DCC4C45C132A038315A0F1D69AE768F70606D070169AE0818685C4BDB7341BFE15AA0455F535766FBEBB50875246A6DAE86C7B9F6F3A9FE01AB9928A99C13E6628431D41C1506381A63FAAB57BFB3B180F5D7FF59A434233EBC5A659B71CAE6970CC838D5FB638676216E3B16E8BA6C01349A7482AAF32ABD17DF7FAB8C69789F0194022BC4E62B6A6AAA4CDEF13B1E3BF5E1F4FA69F82B1EE3FDCC16DDE1106E3D2C41F6E661E33984DE7AD6021EAAD3E64D8C9CD7B5CB538AF88DB82FA048E5705EFDAC0EF479827EDCA0255BA60771A5EBC716C690CD3AC840FB6FF462063503D68C199050BFBD64533D94E093A47658822A25D54CBBFC689DFCBEB1DDD5BC6190B8F02C6FF3D001AC63729D35C8C50FAD3DCA2E67C5CCC6A8799420B159C7C5CACAB958B423964C489DAB1982A4E2222D700BA5AB772C4A11A44FF64018AF477D054217EAE28FB8E37595941FEE7AF87FD44960A144DB0CE2A44B33DC79B1EE31CAF80DAD620666D0ACEA76841EEE6CE81C6FF1F6D1027502EF89F1595065CDEC19B30E4B5314EFD64031B3B9DDFC6C95A4943247ADF7E4C93350C241ECA71260A454707B84017C5EB7AFFEB5DBB863A1CBDE0062C662308A2E824CDF6397863EF78F62319E2873B506F8A9EE82135B803025D962E609E006961EA3F7B67347518E70D9273893D79530F67CB678D6A8D28A0342BAF904BFC0A69AD575CDA4AB73AF22B52AE5D58372E0C26795CA96A16B8461AC61E6F68433ABCEFCBC16B857A89C475D1A322D34266539A17D485B8FA356EC3E154D37BAFC4CE75829FBE8BC823FAFF15A49F847C286F999A1F2C12B03E8F8A4C34A97588D91971279FFCB100EDB943E636F78ABFBAF88BCA5C55C935F6147E51BF798267E1350D2F5E3F74B339F6EFE86208C5BDE149C5B71056BEE748D06614AFEAF6DDA2A6EFFBB56B0880AF9B201B3C12055D292E3BB556240DD031C29A67BF244F59112BFB6865EEEC1DFE1CDB1E27F0A9E3372638FE4407099D0E54E9A188079C8BB9470BE6F63C83612D80BD60C21B251B64236E5CAF09A11C12F1A5E94F199DBC7C9E394C0B0E07A583E707E5241B8FB33E39BB26C31929F39316F4FDE206493566E17B51CE635420493176D8FD353206EF87F0994F039DF8F008AF602F50D7F9C0051B56227F3A2ED20B29611219FC4376234EB900093A81389ED00991272B739389F1F978A92A3E41F0A28985D697C01240875AC46A82B2FE94004CBD7B1E7594AE38A9DA0E84FE7E122482BB391538EB8E85AF9DC022CB32CC08FDA7A95165725EC29A0F824F97F0251BE636B57E0791A7F50EE190D45749472B29A674239AF95B373A40A6E0E09C674071186B125EF5AF72CB434AC0AA990341F063EBFE30963451491474B603733959A23A6D5B8A378F15A5A5B9CE4BA44BAEF6AA531AF5097ADE73F64AED0A541784119665F548FAEB447DE108AB74A74893017F0A1AF84AEF0730B555767B0CF6AE502E7693374D2E01C54C64E411AA93C96DC5FA010267B387299D4376FBB190E1C51A560871B559FC800D82ABD119A5732B50270BEDBCC8A636E7499149AE0E47F736FDB71EBF1995D1E8BDCB0EE96E732E8C2509F98717C3D174C78A4A2BE43DD89195408CD300505A219305809A1BFE7294BC2EECE6D98C768A8A1E0F74B665EE3D652AE8E008EBBB11F0D2148E4E5C93D7FE0190D27B3EBB7D2194BFBB624AF3A894CEF7AED571954D006824950A981F4ADA72BEAA0D820C5DD9BD519D39BB7915681F266DA66D49BDAB9E55879B953A7332F877DC5F5CC7BB3C9E1C1F2E41EB55EFC02A450B5142514F1E06D43E48FBF5DC80DF241169D5936432BFE9BE99DCB17293CF968A17F3111C884635EF2BEDFC87DBB80BF25EE9BF57B55CFE635FD99554F5FF2B4482D1948BD282FA282C48C0302348982E30A772BF14195CAC7FE39F836E6238EB1E1FD074E63B9AD0A8D37111087E47FE5D04B62DEB496353457BC76C53A2FC9D5AC9AE6A47F632E6D45E08786DA128464FF2266BFF92B5CD89176A19226F2EB14CDEB331C497F1836FB6C0A117ED6BAF95E9DB8254487B0DFA7301397AA29D95FF2065D851BD302B747AB47BA0AF408B51E4BBBF042ED1B2B604EEF4C266FE243261515778BC9451A8DFB025FA3212E868C3A078C7CFF65077DE94E50ED90A259FAFAEB398A94FF15C838EFA7F49904BEAFCCECD8C9ED4E014EA00C7AEF1D437DA306E8B7DFCE536912C169BAF0A3B78A643D6E210E5550E3B2BAF7EDFE01E721E3D05BAC1378EC1DFDEB2E2AC0F0BC368E0A8CC64F375DFEA2FC20CBDC515440FC2ABBBCEA3584E103BD686C5403EFE376D44F5242D35C9F9D35E1A869FFCB6657823EA0D4331ADD5CCFA99BD6EB3494A48ABBA7B7ABC32ACB8FF00512E1B0AD493F579898847E328C06FE05FE282F8D4AF48A1AAD0495AF1AC7354275A6D45AD5A7B3F6787F893EA558BC5D4ADDE1F0D265ABF73C86550D25C00821C3138B385448E3E02901E2E6EBC6A0F211CB6F22F8F865F0DF3893B987DD086B6674F5464ACE18B9F0EAE948667B2FC04FECEA3E2B7EA6B869D5F66D02D4DB124A59621B96E0DEFBF99A91AFA0CFD6D5A5968E62EF42B4C8908C3719BA0254929A9A183D50C566CE4FC970E047474490FFB07F576765AC5286B2E0FDBF1EC56A8AE8E6F560C69614FDF5C89BA53B8B7189E6388F7CDF7B819F78F3E6EA54C40865262BD2C8CE87284FEC36E2E73BDB8AA9CB5283272A90A6BBBFC3F7FED5F124E8BFD770B6254CDC695FBA0D8627315370E2CCDB89BCC84C96E20805AAF087F9E9BD1A189F4C6D66A6DC3FEF773788B3B57EF876CFEAE1F2C876CD239BE3B8A94F21350EDAE6C269698CC66BAF90B3641593F96399C71B2ECBE50F61B5D6F37D47DF702A9B9E47BED2824DEB19ADE7D7D8830A8F610088CF4BD0AD22A5A4FBA767D01987688BE710235A74129666FF7917B506A18E6B5D6166E8B682BE6B1946A4D4420926FF8CDF2488EABE71EFA7F2536B9DBEFBA08BB9E94086F55B1B991E18E6023E6952D4A563F2420A1536A1EDDE119E5779223CB712AB5C0BA4F0C176830FE523DD8603F1B316E128579E65454C2BE62C922C1DFE09DFB47D4497CC552AA9987A8BFE19C44E207397204686C718A0936145FC102B8A7111F74A421226AE016EDE658DE5DF9D3C28A247A87F2BC6FECF66CE7A6699880E0871CDB6F066D2CB3F9F625DC5E80751DBBC85982982E2EFAE3AB8F4F1EDA0D13C3B65FD2178E8AE4A712B521B7539785BB058176AB4396E6EFF2FD9052D4C6AF17DC30F50630233C3F05C62E151EECE13CE124E58A25F0F3AB65033ACAC9EA6E41CB3FA435D367DFEB0B9C9B37414CF32DC85A3C43087A578165C86D100E47DBA1FE7061111AAA961E67ED057C715974D3144912A58B6DB22D51BEDF6A8646D810190D91B61F0776DA00C8B0BAA7A83F4433F357E758F5AE8F278119908497E717A7AD25B09EA7C76B306A9A3AFCD9AE6B4F64016D5E80BD3FBE2F5EE673A7459B03AD9356148EA83461B66716346DBE85678C37C932EBC53B033A3F46DC28219880CFA8BB5E15F8862D345923BBC179FD763A0F943FC56BAB69F26C0C15D668BAD923D7AE6B35C07621768F9D972E2D6F46551D45E3FBBB577D13F01E8C1AFDBDD2F052E931C0529380F290FA1DE8BF5A11F82612943BAA2C0D086EBEC84069B271AC8656883F686C67B1808E27C860ECD1B95FF6CC6E6A5846DA29992CBA450081B8C37DD4911470EFF281FE94F10636A29B790E41EA6A342A5BE79CAF575FE9B0147F2EFE02874BC8A0E136A395B42E77D9F18CA4F61501E6C1805CDCDC10D0292593481F7E0F93281D0456EB51F6ABB7C379C028890F445D9FAC0D96AF68CDF6CC879A406CF2F0991916B33A72A193CF170B45AA079DB1BFD4B4126FA9AD3ED13FC98CE4C6C3C30923C8C53BCE1812B21BB644ED3A0CC0596C60032FFB1462DF5182528553AE865BF87FB7C7F61D1FD8E40D830B8D8F54924EDF934D1EBB88DA90BC59EEF1F6BF9FC2D17D8E9E0E39FFAD22EB84EFF39BAA70447B124E492D760E55D6301DCDFBCF9173FE293AC4D6CAF2E1964B32973067EC76BBECC65113C1FAB85375D92CE1436E1D1B205A88202B304264620B282E62CAAF5CFE1169EDAD9459B15BF0060C5744A17460F9FB164974CC55B3FFA71AAC13437BE58325E5E27E151C71D195F886F5630925D441A54695DF23F64C6BC3B0CA83F0E88D01BA4DC748A29F42AC2997C2A21EC258E430032C09E73E73AC2B21B55E1DFB2DBA281426620A0545D2507D1E96A3778C780FE77F1DA3B615E1B0D14DE8729229472E6619AB3B67CCAF21CFBFFD1F237E780927F147425B2142BF62CAD6B467A10F7B3DB922F095A0012EC179C4F8D5437AA8024F13A2A485E8890940DB69FB719B94B7D2629D277B593B94ECC744AA4CFF3D33D2250236C74DA057496BEFDB961B89BD6F44D581AD7A28524A6AF2253FD27530B7FF16FB5804FCA7E44BA2A3AB85FEDEED837DC130F533E8215B3AC3F584A2EC0E9B6194F97741EC050576E16349AD852DE8AAE2BF83CB1894107299F101AD5A2C05EC590B2CC698663C44FC0DC7F893F42BC5A2DECFF2FAF46CC1C00FA7294A0184A85CDDA2B1F38A89B1B17EC08555D082411A4CAEDED562C9FBBC1F512118EEC3BC931CC91636461151BDA454C4F029E01231BF170EBE17C526F3D8F705DC46560642B1AF36E3B401325A6CF59B88BCD4B3242D676FF4066E4252ADCA37786CBDB340DD81C5DD0540992F0B142C5A18D3BD1070719AF996E3C3768C3B234D303E6E9850B35C7AE52496C76106D7CAE4CF8ED01767B6DB5603F339FBAA019B08FA35E3DE1129A6A4D578264CF1FC8A1DBF218DD72B4865214DAA795A00505D4AE2B85E90F589065D65FC60CDD828007D4D3A4C084C7EC159C5D86817860CA03545FF74F17AD8570B2ADA55ECA12BFAB5C10067A086A34A57AAD8694C953137BBE901F8D3DEC27DB5DAD2AC96D56C312E25FE48BDC889373ED252B4F88D32DED6702B58D35A1FB40ABE2F2ABDE21CAA5FD0F67E7407A8"""), - TestUtils.hexDecode(""" -d3bed8aae32df74803b6961baa9a2266122e26fd3cfdf1568b460abf5ebd475e1764c7814c6a48cfd6d4df272ea9790c8ebf12fcf5836b0926d593e90828bd49ebdb997e79b79ea68e66f48dad497fbd3a6c3e317162a3f46a4dcc45616be6cefa68210b11fcfc9a906945d30297d1714ad28b1fc7b4c6cec5ece1f5d20729918070cbfb25f285a6fba5e195d2dd75a8c62f581be2d75607b5a8740dd2339682f31230354ea03d0e7cf945f167937592a2d2dcaecc5cb0d36217453809886151073e5d15e6bf7763cce81da19738be3a3bfe96788a56c47d2d166efd18250ad525b4e9e5566c19287ffc277d26a888d0b1073242da5e92b23556552b841ec3355e14173090649a14cfc0134b7714dcbe52095d759d0eaecc7d26f3f12494e4247435d5a6eaa9957aa503f710f8e2844905664905de2f30285e774b46270c58f45d267e850e1a6f711b00e5153040ce090660c97b14432c27d0dd50c0585a8f4c4e1e15d2888a90c184508cb400af2f5d3dc0af3eda99a5e97d0836d079eed38aa6e3e4f724cc63adab509ea5f28bacf3181cb7617a3884407a274824742623eb441ffe1ef15bf6509e7b2305b5341c7a3d73e5dece5b9ead5b99f7e65169ed1673bdb925b52a6b8d524ee37e8538e6917327a8237bfc3ed3f729cef6840e75ef1cef707fa10009e4d5c72561eed18c06e3be94c579f6629373af6a55019c3faeed00abc22deabc59dcd87ecd40e9dc0a5f4b7fe1d711990fc8c03ae9fce980450739c0a441e3512ab7602038dbd1352fe0da554176a58c47c29111eda3d2b9560b3fdcda292c31621e22bce8695748fcde6c81a1270a1944790c174de8a18a505543b459932c6f4228a00984166ddf33e981c2d3ad2e3cd9ce87aadc57e1e437029223e729a99667ad87ca718db5b133a930e73dcfa2d37ad7580373da272e54f62f3d13db9a4bdafb1922145a1624fa96921c0b6bb1b3d7a115ee58dbb2872db79f4d38255c11f160397052aae3ec34921bdad97da72714f37eed4765769e996e45974961e7439352445147dec09b1bd02a776c2c22be612a723b8711f8391e4918a95605fdc866ed64cff6cde9baec4eb42bd880dd0265befe1a33f4d2c0900627f0c7727228aad47d0922caf2a7c86d70960ac2634cea63dbf5d33af04cb149eb618f9ee97adeeb0df8bf599358a82ceeeca582551298a63cbac754b6975cebf7d6e78b6d5ee24dd6c78b51b022f857e230fab176446cc2cbf6986caf8e76734f5280f463641bbda5137fab4800c58f0e1c4dfd45d5813df3f917666bbadb3547c7381eb33b00fd569d58dacdc95a25962024786770aed94d97d4682f9e94d34ecf09e9269993f547901d0120e5e969e3f12a5ac219158750ed0f381dd72a91ffce01f2b612decbef0fa5441925195b813e1273dcd9988457214c9cc503206eb4756e46f900cf2011963e761e12a3774381b877d93aa1c7892f512fc0eeeb225ace5dd7816b919d1717b6e4a34dbd30171a1d036d9ef9d37ab821bc03d881ced0f2aa94eec2fe0b1ca72b7049f749c9e86ba4ff44afdc90931029fa59538014c519f76264a2a45bdab759da02761303ece94fdc2654cc9c818f4af979dad60a9506dd381d150a66e5b0fbdb6e734404f4cc71e6b4e7f5690556d28158cf049f8ce6e4043a82d1ca3c15e480ebeb7e211b2fb00b4bde2733f03f9cc705038050769f9aebb5a1ffc1c9e3d05132ec1ac7b55b6b3b127ffec67cd6e3a1649fc9313e3625c01ebb600c30f622f8bccea15d6f0388439fae057fb1ca54c7aaecff7b1316e74273a2c66037926b246626ea2321c311aac3b5b907e551d7b03f069ae354ddca45d1e5ed3023c576fdfd1c1bce9d8edad78acfde17c9e4d83ba9087d889dee4bfbcd8908a41ebcb4738861abb6b6d8e65251dc4b7c26de398c687b30efd895069410e58d7bc2a105640866321a83dec80ba7b47cd64b002300a9fdb7e7648c2d0f9784ba55f837904df1fd1db46ea82802d4c3e925d4c3e3cde9b9b6063d303d410f3e917f10aa0a18fde5849d14d0a79d71a983f9b09a41e9a3f80dd36e46bdabe65a1d40d7e53b94aa9677561a549aefd98826cc32f6dc5961714d9cfbe913dd3bc68b8891017915066792cded38946c0316fb0eb6d89c10b84df01e0f910a9ce8fa1cbde71edb210918562910cb540d3eab21c8c8e43151a333c516239370ea3dd42294712d6cb920b1f5469e74fa82d4bd7892cec246db13f3f37ef0e980e095faf06e5aa417f5e16de83c8c1ee5ba8340d10785e1b10aa7573dd6f77fd87eab89a014449210e285fb17d0ff7cc3a2c61e6485c2f2e81fec821abf0c694b77f71a91790037d0f141cfb4a74caa4125dfd7236251526a44d4ffaba4589d5237fe647a4082ccd708e27e82bd28597081fecc184a5ecb2d19d115acb18d9d463e3f642e2e606d3f6d496fbbf19149ccac758dcfe8eb53378b65608940925c23754e0f1a390d520f26c4cc088c091e55b3cc475565c0d166265a0396c50d9983e3433bc5527e9fce7fca2bb408b39dbf96bc183c3659f6e8fee0f23e4230c0eef54ae9581b3a38436810accd7c37e83326e3fe7ed1821393a11127027821bef0b96f58a66968271915c1cbcdbcbcd8c62a54bee08b3cf143e859564b798892fbb9c430a6645bb4c8a2be76c37afaa67b7b5a621f987034e88b1608de8a0a09384d85b0c2c872cc2a9f8ac348c5f864d28558f6c6e4523f408586490a78ef95ecffe5b8fdbbc264944869aeaa3ef428d5cc5fcd363d1003239a6651532a442935e674e3cf1aec6f8b32e32db762bf2512efe763c88b9bf4413ea3344835b96fdcdf71c83afd75ae5925c3e76b9afb9fdc72b17f41ec516ab23529e73b9639f5ca42457c5afcc0f2add498456e1db6b3e775ce48753a9a70840c45dfe7cf396b627fad775acd051829f409bd37046bc4cbb57938cb490891c3aa6a04f60769e04685ac1167c9de32fb20cf43f730d8d09b0d74e7f80aeac659509d7941460018c38eda19de38967fee38f7e9526babd21ca1be031dff0591d765ae30361fd8c2a33bc1dded2c43e0e43533a55e72bf1015f5167c8d6bd5e6a19cd4e2ff19f1d47cf42fc361649a669e4524c731bfe7bd11c2e4ff599724de173dd6990f30db8d3b2084d2d3aaa0c0d8b648667b951d510480a28d40c938b71974d749e62d88cbc686eaa31e7f89cb86dda1e778a167610e7bb3cc97cb27f37ef9121ac1baec0a10b40211cc314b02b5df4274acfcd13de277e470b63c0f0fa387dced40050607517a979ccadff817383b404b4d627d8e92b8c1d8e9ecedfc2d344c4e85878b91a4a5aeb2bbc9e3f5010611121a23333a42546d6e8e909aa3b6c4cbe6ec000000000000000000000000000000000a1b2b40""") - ), - - new SigGenTestCase( - TestUtils.hexDecode(""" -f7dca662f79909c3ddab57a31bf75b9d925ee06460453ccc8687ed15f17d9b3de688567d9057463268b74002ea5a1ebc35df84945f296a52665eb737350da32513ec98468356bd8519b3518b104422594072d906b1e37392310e089acd08eadba8e647a2bccaa8ab65335bba2d87e7ac2f1ac90996724fed92021ff93acf1797dba20442942de3a04824454521350e08858124186e04334562082a82b451598451c2020842341218878510c540193060ccc071011492218320c0a21022182ee3a28021880024a7050a9631dc2832118471242430121866d0800940c865cc006911086a23c72dd8c068103028d9040e144029131989a4468e139268091492828630c0200648142061286d00a61013492d5c302a6044681892880ca589a0088691486410463210314044868dd4c228539489422432c49650992831dc3626e0b8311c816d0bb404233291a29491a342711b838122a268cc8845d0008adb4872d99229c12804a40200993401200571e0987014c34cc0026148166824451190104c8980858c366894486422b6700b2324e04626241192a1900541146ec906520835828b366481462cc9106218098e04b951a4309284b628a1122a0c43050b28850b210c5c30501900811c096e83964581c28459b80414858d530031209130180664400802243904e3284554280452325219312a133364c9a8251aa2680a28229480600cb5054ab88109a52912360c200261031142d89251db062119126212a320d9b24d0b391164a20820374c6498908b362ce082290c174063246e811828e388455b20261c264508162288b0890113008cc69164146c13c7855c40852225294b969123a0886184110205888ba41144182259a271cac00d491081d8b229cbc02480a04c4300424a86419116100a976401850d24117009216400924048440ce18248031406c9004a110886421465cc9090d1424c124370c342452180281a150222426590248a613810c28050e2b4259b204e413281a1829193184d981244180684d8a26592a269d4100e90a2241c0541604409cc102d99287121a1210ac2610399500c156d0bc72919320e1a86699a4249c948064b2668492840c4222100400a03c67164b091c0286901470dd0221011a12d91448488886c084464ca0662cc384a63460004396c23c1650a090cdc06325396800242614b3249cb282d44385004889121a48100a78410476de40232c9282519077183a0691b23224116091c088080240147916415573a7a76b6e004d7d3fe8a894ad12949d2c0aa943f5a7210f31077de2af8e27d10ca043ddb29e828db0c39953bd50fddbbbf839d5e242f2623aee99abcec0edaa8893b5c79f1a68387d232995823eb46a1968173ee79bda6e849e254b0e5c63499b9c8e07edf0bca6f0436a4fce62b7d57bd80f49fbf2b7d4ab1bbf1ed004950616ab009ef6e935d4447e287d834106cf017746340e79c317547d051a8026a31c8868bdfdb6ee50c1645ec8e0aa9f716f42502d9eead700f29a60058821504dc6b0bbc9512e1af92ec73b7582676d2ac13f2c9cdfea411fca42f2fa5d286bda79ba0739b0522e18b22d831fc29ea101e835932861b705803a2abb60fad2185c076a8dd469dc8f80522fc546ff0226f8916bade8e2763f3182e431482bec626b2f18d1c046e19a11d79eae753640ffcde6345531dd557c7bbbaf8b727aaa3591abbedbd5f9afb8cf7ad0f645db4de84d91be8b52cb7a407624a0b13a2976f42aa40a1a28a1559be8c539df3d8124c5c111880a8aac2367c312a8914fbce07838804dc956763147fec591eef9961a9c71f11c71512355234c29b65d8a5b232116dbdcaf72d00c78bee6f8c5508b83b4981cbef5b21430ac2bfbb892817254e20c5c3d7611dbcc101b4fbaccc4856b37bf06fbfb231c587ef281cd7bb99f5bb2ac8681d05631c61c3e31f506976e90a130aee0416fad01b68c760d54b5f63231f3d118f18b4d04f44c255d95e1f8bdd7cae7ab36b68c62a353a8f85d70b6f78a9dd7429feaf4626204cfab0e267bfc9717eccc4b2a2849ec803975b1237d01c1acafaf02bac8e6cb84408c327de940107c067c69e481822581056162531b120cdaa067a7d65a3a47a7ae35f507a9c519f7be179be822b1dcbb8cb7561b9d7822e936e5913dff73c3c02f74e419f8185661e60ce39c411295c346d692def165c38ea53b1d61b08f9d6830fc3c13f0b8edd1dd56b1cca3c18248cfb43313c7f91a5a7f0bbf24e0c0b26093eea6779d93fe128cb19266968bba07f75eeff77ef02b509045d08098cb00af145d1ab06a4e8065b9ae3c208a1556237bc2a269c030238d4fc2e0661c6b1cd2c1dceaea81b837cb4c7b032921d8e77a2304b70d1e9b1140a0866284c50389f581c5c733afd3d18651d84c0717943b86c3c8438defa777f0215e270c94074e1458cba5e0e51d3fef04fa3c51b150068f8daa4ccf533ecb075782104436a1333b2d9e71add8a1684b8a98d5050b62a56df930515cb50567d678cc782c3f72599a8e348c753fb3eb1e01c36a74d3e8ef8c82d92cbdd9f759fee568525f5d1b509907737b595aa2f77333b499896a877ed157d230c765da0e0597388d98eaa4c6a49d2147c5fe963abab12ed3e00fbf0e09982e7c15651ff87b3b11596a95c320e495277963dcb1e621bcc4f6dc81bcdec747a879569c1a99f23f2613e781abb0b3b330d5271f25e780560fd5cbc06f859de47531b1b8ca0c6b60b6c668b59decd66a395e6f6d7b170bbda9ad458b8832ed1e232de0e8f973af0f0e2c5e902c7253f22310740cbebf1830b428d5eea36734db9a83fdf8ec49e91c01f0edeffef4327195516e2dd062caf366209f99802efd1fa460b6122ae840d2ae809cfdd27eb403f4b6e26473936cb11fe381caa01ad7565d682ffc2df5617d16e36cb1debcd2a6c42a2d8588a5186ce7bbfac7ccda8b00b32af6e265f7b9dfad36d0f98fd5a70042f40c2e4649eadc95f147122b437bd91b3a0749a02bec4b0f31f2a256a3f59344d192934a4c41bc4f02208a967a096bf198e9021de7aa8bf646186c1c8e42917c1b6ba03920ebe1c6eff205d027f7ef7e4f8a17e87ad83a7bf706d16115aa66deb41bc486d932bfc14b4478b37e104467004ea19e5d91a0c8128a0c0df11f7e76f7febae4368dedec4ec34eb1c46a45d671850b95340e6fdcc1f69fa63858f5c9e94935431f0681d2a81230e44675db413a8b475a29bd1102febb27ce0a60f265b767a91f67a8c7ce172694f933c856b3f0c4f4a5362222c0fbeb16ddfab6bdb62293ace0224baadd06248173cb6a3c3b31f0dfe2969d42b28cabf0600f220fdfdfb126b459f8f9b1ea285bb7b2899b3352a452bd1ca3b807ae648d2fefe4595537f4f8f285a37270b96ee31f8381b96a54ee36df081bfab2b518d6cbb0e3848bdb8ad4b9bc74544de21b5d4f04a847cc88076ad7124aed1ee2014ee352b69373f2a300acdcccd58c622d55dcc95672d62bfbdba992d1c8db3b686856742de083d664880d9804b7e71002e1b76963d3d5e32737db07698dd8d67e1b1c0d89f37d62be3dcb27df8aa39a12060060645486252ed"""), - TestUtils.hexDecode(""" -8F69A33C4CB9627BF27401D4A1BC131D28AD0E2E5A317CE983BA2CC7465861A414FB72745E4DA31C0E04576DFE0D0EE834A1EE323D5A0901DD0189EFD6718049E2FFE1AFA548BE16E04B8963325AEB0CA90238C7A243A3F6AA17BC1D63836898688AC8E919B8EB6D689075E050B4189A1FEC723E0AE8D4AAE9FB6790B527A7552CDA174BF40BF91C4142B076ED8CF112A871450AD994737FD5BCF513D42DB01906636D42C6C10B64F74BD37D68A966DE0F3BBE6541AEB9991DDD0C0070F16715C01820546A014E66D786B8922E905DE2BC65053C42703227B7D8431427E3EBB0DD010DC58C2343147700D673D5707160F234E35BA24516CEDEAC77AE15C667AEFA8E029FF14F169FC0A781593E11D42E8659DA8E91E53EE0A1FF15A3C203BBF9591584A99FF8BACDC37541E126B8CDF3503AB2D1BFC0C37F38A298AB1DDA150288A8110C052469382A9A4F5565778339AB327DD80644A26B218ACE0830E56813CAA658A9F17826CD12B815612BE40906ABC89185EDDFA8E05102842CF27BF040FC7B396E7E2E023CB86AB7AE25F36DA6B6C0842126658E0315D6D8F4B5DF38CA663B55998ABFC72FE9B7EB7CE3BEB72AF73A0B2A45577C5215C42E465EECF4A4E69B6DDC1E65E0C1EBCA"""), - TestUtils.hexDecode(""" -f0fddedba6482c562d0ea6791254b7aa34da8b70ca4f0a7cbdfb0e4fa31f902aa37484c4167f74093f5ebd508e4b89966aba03065194cfe3376066b848da8faf1768c397a0e3797bf09e1dd02be5f1e77703ddac9063901b52c9b4be73daa5d44da1a59510b25a974d9c54f8f7889587c6f69a17989ea8b69f4dabced9e23442f337d015ebcf84cf8c5776f4863275532c4bad840d314797e07de00a9c7fdbb60f83392efc382220ecf3f9d60b5594da6fcf00580df29a378a9cc3156bac8ec8bcaa7de1d8d48d2a1f33ea8a8f4956e3c46f386628ca96e009852405b6333710287e376aee2ee7c6f67b1adf07f76fec3688201bd3b152e202c192db41d9bbc0d8411ca019f9a1bf1268b34ce82a7c037fc63d9c63a561003d8247c645173e01c8ef63853e4451185d45cc2d5d2da4261eede504c6da88a55d7cc7bb8df33eca74e9f4b9f9139b9f98964aecc5278448ff9f2a032226e908b32d741037ae689c204bc1f3bc07850debc3fbc839580e6ae1fcfdbd62257ad64c2d6f6945a6757242d1473e64f089c46fe050d79a082e43cfe656f09d01ea219eeb7684188fe80ad59c4bdb57905cba37fe0fdc1b205f1a5a899ab55a37c7d3e003f1051bd3b322b37289df3d350053d6ec8ec1c9cafb49fe147c01f092dcdbd9ffd2b7900205334a077b2ad5c57a53410bc5b9f32930fc6f6a270d84d4436d8c716344df877f5e523ec9e1ecdd43ac21e2c4cb8706415be0ea1060c7127d6a327eca92956771af363c03ec4a0ccdf958bee76803208191946dea6e51a85dd071f3711555cba324e5a7d7459a7662fa6cce043b34845fe77cc651883c478d0d4b2c09e76bf401f0c12721d21357546dc78d2f054b409b6a702328d720023096e911144b7bb724f1d799b0b446954a305bf46944f122867cea17b9798636498a8393bc2dd328b0b3ae78b44ae35cbabe62e0f0d3ea4cd6db0bfce87c6e9fb3364c2ee27b5edbfce17c8df592882dd057dda81855abe0d0898961ace81b0ff22b4471bf96ce814a45f7c6b3e07ef1f18c9eb238b44dc6a50d7489a1af58d2dd1ea2ab2b1a0b4b661e55bbe6dbe9314e76207ec0a02edb2fe7e8fad8141401d1f1a80237cf5a10604ebd26ca46c0ed5d8bfe96c3a1d6ff5b7d2de69402d348e5db561e531deafe29b0767620d7613b817d4d3a6568911c291c3436b40043cdef83a8b7f527aa8e9ca89dc923c2bee6e41312af6ca1530ec7c6aae798e25a6a31ecd29f4ddd56d663e430e5c1ead28a23d424148b1a8aebe9ad7faafa4e295215962d294edb7b1f994ccf43238038ff1af9597d24ecfb68aad4e4d2be280c6fda0cb88b4a1b0deacf678857d83c955115c094980ef8fddfa5045a3e38e733bafa243a91e89a5676312db195f1fe7c0f7b0262628a68c6619db1fd85d84a02b9e7da8234304192aa3db15a294dc4e9e7cb32f8662ff0a49fc4309700e0dea871edeef3df09ec78c3791fa604ad69bbd8c211f136dbbfd49009fb5e4fcbb2c995bbe361c580a3aeb1c88dbb2f148cd05fa9ced0d826e24c268b741953c8ec804add66a9b8dbda05a9296201d0f447b45a4bb7271fbd3359a29815bedd33ae87b52bb270cec2369dbac94528eb48a1a66c129793a4365212f1cbe7e24c87a805ec0f41cc2f36bb2f2423ce6904406b1362c46d51d6d5685dcc06915636e20ea3649d6d1da39c6177630d1d48f393d7093fc12415e5789b15e1ffd07e1f810057ab6545b22b24a93f9af3ae254407f9920af8a48ec40412998dca523ee1e122a5e1107a1121cad25652c1e00f6fa115c58b4a7a60cb4e3b219d9828f2c8efb04a443717e73146a89fe1a4f887b564010eeba3695164704c517d3597ddf34dc51dc460773394d8cb4d562498cd127020973bcb2315c25ad136dafcfc0d674341045ab1de0e4230ec91d579ef1a42ad69892f17dd271e9eab28097f8f9c5e78c50c36c8a02f1625ec41132ff1731e3c59ba20cafacc9ea890db35b8c9606bbd5457262d0c44c4659f933adb64fc74a884e152627cafdb20cc64ca10ed9ee16d814b506415cd0141406b0286124e37f777dc810d70d4125a72bd98a2b73bb26173494568bec76350b2b3b399fde1e3c115f1fbc99929a58a8ccc2b9cc1efcdffd210d88ad48c54a48e837cf841c9f1a350531b695c6fa08ce3148682fceb9fd17f121fc1e3275f65b5a8cd93a25d42318bd21e94ea8873744f2ab530c58dd3bc1109a5c872e61887bddc455b1bcdddb91c0ef4437a49a9f6c73fd371bc6c6d2fa594f78224646f2b8cfee3563c57149aa3a6995dbcf0e6782c53694b39b8812dd069c0cbe713fe44446e44beb4ffe38072deebf3ccb20134168702fc023c4ddf9aedd387a8bd6fcb075850cf1f29f2bc283f5731b75b68169dda2289ac221217bee3e2ed479fc5ea8244a99cb27a015d7a3ebbd1f7acef07b63f17011c5e39ccd0c025d0bce5aed7c482685c39f1fd82a9b08c197f9cc18da457ad0ad55250ea935bee50df659b2c7a501a348b8759643881a9c5555015799adafe10130d6107e0b964b48d23c909e55843b62b9dcd1dd3b235c487968c2c3d87fe29b2fe3ec7a8fc1c1666fc8d2b6adddea39ad704cf5eb6c22f0a5aeb80e2bb04f6c2c6bb9ceadcdf7945140ba942581213dba8428a8c06155f200082f7faf357ffaa653245e2752787fc1598e000eb567cedd49b98d5e4fcbcfd5c4ee10793c16a4767445fcd16ce4201cdd005e95cf5a714a9e0f648673269b5fcd8ca0cc254b6cd2fb428075a12b7ab2bb07a5ddd82e58c04676563b11dfede4daf13e1362a5171364a2f556c36130c1eadb59dd966622f8b86502f379e0dddf69a1f73f58ca6867b4612f28e67c7dfc49dcb56dcb17a79aa0e56a08c14e1e909fd21d05003ea921ab717bae0ce1f15a74a71c4d7e6936d20c7e661806d5f8a5f4cd93ab6720775057d4c0450a6c9e2211af47c57a7127f59983d824d35f48848043aaf3e76209a6cb6f34b15e5099b2c3801bcdca3a5c626bec9b6e92a67189dbcdad0d59d2b30a1f9cf9de45084ed6d35e32722b6642ab870247b42eb8f5fe39e97709141e36b5888fbf496199675274d840f15f5ffe40d74be3bba8b4dc51425f839ef7d041a4232ccb93b754c524ba141c75ba94209f9e76a0d7c8f2aa3e126e6eae35f19de3fbe38f17143d1a83830a2b9b4c8a8b0bbac29363ea9ed0fb1001f67e1501b6f4d6406e2335a61f3386c9e6a2447e3249d3db8390158af9b7e57d81fcc00a4210194ef6f872821a8cc475187780d658903040b0c0e172030576772769facc1d3d6dcec001c30335b5d5f62656b8f96aab7c4d9dceef3f5051b2240435b75797d90a2c9d20b1b1c585d89919ce1e5e6ebf500000000000000000000000000000013273441""") - ), - - new SigGenTestCase( - TestUtils.hexDecode(""" -8a37e080550701795416f5587b977446898ac8147890840db53ae4c7a65508bbecd64901b484b1e1ca4764c26360fef4654b49d61b9b180ba16c6d346251b630e2b21822a4c2d9409a025868c3dea90b7eea36f9dfd34822ce07865fb847d73e1c6e9755cc9cd520d6120fc21ece975c4f2cbd0cdf71c565f3511cfddc2e711210192dd40664c21805c93229cac8219bc609d9388c20498e839821d390881bb58081400c000345200485e3400e489851d34468400025113051c1c821a0c08499988ce3400e1386690a022da2a051d8a2605b9611a4a8092293308bc4450b276ac91269dba648c33484d2243163246d0804660b234d4428021b004110a0641a0870c39811c4100164240019a46dc88811c306656342048c0040119289d3a8700037400cc96423896804119203196c5b120a1b02461c1428db464c62080ccb006de4286ac80621a3388da0406124123019c449e030521280642306888384281cb40c412692d3b80124117191c60d201110049060da949004974409332ac11472584069db1431d1322a243289542628809431e30891c8a84d131960082171c1326800225119002c51006658442d40b02581268c429088cc102d8ac68153442058a689d980485082281ca86c44264a5ca2686130641a310209b38048360e4a9285a2a88c02c6250889214b30094a101104382962b60dc830614a2205a0420d8a880511b09022356884062982026550446ad9424e10418408b5710093491cb6844342854b02321937410931502296655044618b08869b006a09262ed800412190711800091c33660b1785c1c04012990454b01081440819204e5c3466daa484cc3491d8143218174092342288281048a8700b190c91a0850ba771214022910241889808c9188ad4a64892b48ddb062500310643328964a20d82288c21304112394619218818156d51928562984c40a024633281e0022884b24d51948124295010934c18295281a22d60a620a2324a0a13059910880a083101990c1c102d8110054220868ca6080039115b2822d8c03004076623084898346289b24d483890db848d5100811c228c00b8240cb8209a344d4c4420c1988194b8694ca86512318d60167152820c0a012189142ca32231491824a106281a2904988450241160e2124c8b02812214221c316cc8442a12010c8c325121290222b14048a60508b201a1c2811045050336619b32220b8089203352a29049cc12900c124019a47083b66c63a8057a10b245a52f0ad7febf3d3801447b8222ba342649dae8395ca98831880c859419bf766393ec97f18e26b6e6e29718332b2fd9486ef5c149fc4f49ad1d2a2f7ff7397b44771f3e9d90c38232a6f30a2278527df3ab103a952fa94621628537a3cd9dc1a1b770e6ee8a62e0f72d187e9ba284ea8e264f5aca8d6ee3b566113310c813929129a04354a7ae12a1e0ff6a9282f776fe56b6cdc159da1f5dffd17631c84cd5fba7040450b924b93000317fe80bfc062e1f4cf7d991f5aafba5db5928850684d3d5c719355854f0ff74e42d9fbe4264e29f5cc74e717d5b8f592cb9e070b252f1514e3a17b3035f10168f86d688956a0461e0369aa2f7d3fd7840895b56f2c8b9bfe0347efc370d6bbcfe1c885c5c906934c1b188d3183443133273780dd187a066df1d1589457fe2f619265381f50bde9758cfac5fede514a2ce0861d297f1f47d512ca1fb15cea7d3a4582a4492f8a5c6dbaefe67c314fee1ffdfc251270f69b2cc654b2a77ec0219e85b5814c082dc618391d8a0e5b860ed1391a2bc99493ade19152c069cff589440481aebe4cfa286b9e15977405cfcf944c115a8866f88733d9fce246357652e7861bb3c9024e49e3b9efd99316a4eee4156422ede4fae9221334e2b4763bbe7fd7f88ef7f196685e00f4fb99d38570914e257c0f6b5da76c84c9590c418518f0825aacd131ccb8667abe7cfb428b27e4732290edbcd6f207609a71162e7eb4f9c370bab3de6dc0e531fa41dd63ce11c42bdeb4cd1a6b34ccefd8a9e78bf0fc924070e0281dcb67cef5ea3f4da04b9bfe85c622919e7de5fdc1cef8969a7484ee87bcfdae4d329d4627cda2a05a4334a1b0a326e1ea8cef839bd5317b7a2d84ba7737f4274e9258cbad6d07cd611a4276377f74b1f238b5fc2fef9bfa18c8196e303388fccd2a582b431b50de50a403b7560f31eb3b22252fc4558faa9a3a46e62469f0536848516e820c9c233ebfe1ace57b42937ae2ab801c5e9ab16b2dc06edfade1e86b5385e8b11a782ab21765279a5584122fbc8e85eb9d08106f8702a31d434e44dc780a05d2f47ea8ba5e999096bcfe20dcefbdaea955b08506fc3c7e4a912686d4d0ddd96e3db254f0585405ef8472336129d348a7c98be6ae4fe6e15068e76926018837e3d330bcea69233a6b07eaa5e0e773b0090c5068c79ba2457d23f7ac0f70a4ceef3323b5d4bc10b840b2b7a58444d00212f9fe767a00ccb3b740fd4f7502f12ff86c22aec43f1571c907b6e317ca9fd25a4f10bf5d1e839809742b0f116625735343f6337a77c1a9b63cbad92877a910830e0336010b8794f28f7073f5f7193aaa68f5923cb3700cd3283e912633a8e406067397e84788f067065d7f21a265c8ed878df6e0373c32a2aaeecf51d97418dc8cd77999191043263ea1caad2f23997e6cb400aa1fd54a968fce4d69d44b37632220e25df409fa2628bf17d39c4a2fa90ce1d39027177aa445a352344be19cc25ca0cab87a456ceb256d0928890f638d3f8fa046ccdad16b49ae0e71c9b9b947a5866671a029c8feb90a23e8273f351eb407ddd7dda03d30ddbe9750a05a6158ae14b84330ffb20666d17d73255c5bafa6a02d9bef615b9925aa716d20368eab7550328dd2d251d5a127070b1317ed7ade82e4d49ff9c7069dabbad20b2dbd9fab0978e1114f50f9ff10474906c3be4118103b8d4a2a576d5291685c37627a55fcf9187e9385a76429726646edb07ace3e02843212ef78f91dbcd9c54bbf5b6ad234834ff8647905a87afd41666fe007c96a2315c3595ee2196091c0ef5e0d1a3749d7957c864642caa2b52bca30fb62e455ad102b830800d1e01ef05acfd5677bbf4030a8800ed9afd9fed444dae96e85ceb9bede5b34230ba8030e887b27a907ce533ad40294cff8baa73483f0a6a346372172b095f435eb9acbcc2f6568d9f2e9f64decc6f0c584a71fa128de4a1f5d7ae55f7243fd83ba7449d4f5d1812dbfb7d1e49a5d027c240fa71e5d5636b07a4c0e65a168a0cb17a9fe088c86ad0913de787d2cead5930b4dcc2d097f8ffe8a04a078bd83ba6a6282663e0d821e432e3574861191aa82b1322441402120fe80fc5f60f05f4bcd242693b9fb89f0856af628d69a21d5a046395092c20c5860941dc4d129b7a2ec51fa56149112f0af7c3afc121ffe7caeb41370642ee8b4c3ad7f0a1970fdd0b37d13377a52fb4db0fffc71a1726e63dc9b914bace81506d320a26c8fc946cc68caabc990bf611e2cee065e55ff11c44d95d819c56826e61c088e24b2e01a697be804a8cb82be56b097039c57a854497015eddfc1ccdabe6cb7ac7b3989bc1a51ba9"""), - TestUtils.hexDecode(""" -5DE75924D05BBEF6B34CEB195AE3349EB621187051B1EF95A779B99A3E0F729994BD19C7D1172418BBD3E015B20699DD09D8BFB0A343F477AE2A3BF5737AC994619D1FF3C13E7676D1BCB446289DBFE36E2D1508A3D437B4B0DA06478DF6D4701909B272E9070B1FE06385DBF8A552B471C8EB48EAE39D141009FBCC5D57D95697ACEB7B5231AB5976FFEC41E947BEACA7639F664C6C1D058505A49561811ECDA46E23B651F918112F38B407E82219B49E5C4E7C247DC4BA633C746B42DB912B07D56302FC5C08F5E0C3E311268041F970E670F3AD26A207701F1359EEF9D4134ADB882A1C899B0E4FFBA2C68535D97796636417EEDC0790FF808C976B57F0838A694700F8D75DD4FE5ECFB4B6A188FCB77FB1DF7C5F7C91DC81017A5E9A6D1EAF59680D3291F74743E1776A6DE31101FAEA31D876A0DDF3777A91EF1EA0B575C83C97C7A283E7E958287F5A52F30B6E70201A1410355B47210B911A7A4F6FC23BC95D7951822115FE410ED2E7FEFE08940B3F8E63F13F26B6E949C498E62A66FA675850FB9F7AAFAF7D054F5C12306ACF2900A5B66A29931A5919CB31D19304916AE41869CE3294B0F5F88D845A7FCFB57B952BEABCD1DF7FC11E2D342AA5A70A8AA9DBE1E6E66555EA618849A95439864DF6D7789D8E3B46C6FE4F33877F127D4136D993061DAB530EC979F818A57E1052B5B33D22E941643DE2FF9239741F6459A0EE28658C3C0033FA62DFF37928C59189A7A7E36B1E305F3E1F421EDF4D71A96C71406A0F9AFA5C96A9411AA1A35D241D7186E5C8D0CAE15938FF869897DC3B7D8196D64DE202108D6FB436FF89983EA6DBB5BC88EE2A02488E4D12AA87CC4BDF41A339E10300D32E0FD4F3D3136FA64BA90D64E2BC7C20BA77DA4DB5311F616288496F2FE3E7B3409879050FE57A23DB0344CAE82ED329B0D31DC9B7406CA715E3D84E364BA98F73F693B6E62DF4D741928D21D934453BD67FBBD9725BAAD34E5F3204BDBBB569251DFE2D69A9A96BAD90256213BB0747E7950AEBB4CEAC7224FD5F8F99A16866F5A1DCE07C2CD1E06B70A81FCECED0AEEECBA62521AA0A01FD7B5A3A8A14DB55AFF331E469F5138DBB2B96BFD0AAEE7F38EAA375F71759268546D590BA8C0C022F78CABC4E089992409D3D7BD19048D30B15C796170BCD7AAF7FED0387542BF8A6674F197EF994FF81BB80C59208A572495DE4E584B36A7E9149B5E2081A4DC162CF8376029231EFFB4B4981895FC36562F51DD5158DC82ADE52ABB0E98F4BCB3C0A24566D07686732FA734CDD48D03DF99F7253E589CB8725F17E6BF964E96F9827CA5A9DBD04D448025EE014EE1B5DBDA514D3FEE4F20664C11371DCB16991DA883BF9A68EE30D727137D7902F4839635B1C63F6C4F7D42070E880CA774680DAEF105D277EB8D9090A98F6B813774D42DEE922314480EBE562775F68ED180B67EFEB077D8B174C7D4DA877B0DD3698CF506EE382AE6FC6F68EE93ECA3627B28248D3EEAC469EB0C26BD1A10A7779CEA142958F9F9A533BDE974E1B3CD9B74FEEB2EE29ACD7DB65E00D7ED6E94E5E44A925188285166570727FC687AC7EBE4042BAEF68BC23F4B9C51BA5040BC6BBA41FFA9AFB1AFA09DE1BAA4DA091A08086128A9CA5F27D3F4420327C8FF4801BBF2057282D05D1CBDE60E1E6FB6715EC41AA9A852686DCFC47279FCCE5D86ABF02A6B5B57DE22B2097B12381EEC567E4ED1855F9B482C174D6D40A5825687C02E1D0AB634C020497A44E07E8FBB2D05280C53562DB4C90AE0901B88179D06F9F991E33BF17E7A9227A30454430CB768F56842995081520158FC34BF5257EC8EA9338B3714126D6A95A3D77FB61207154F6DD0041BB03D84D8F75E6EE910460F22CA765A2206D6C56C6E498E063B08B76B1DDF98571F492F9DBD3DEAE7D9C8EF21EDBABED962331F06371364DFCB3216E24638A20F77FCDD894FCC5525DD0C8FC329494841EAFD93CFDF0053FCC27F5A1263C7F4599C186B35FCA9C6F5F2FE169B00275F15447AAA3A823E27E322CA2316B25823F3A79FFA785E9CBC953815FE06F376B6F5860C6A87CB9BE98690C9C2A93EFF1BF1050A01C72CD521BEF265D66BC4B8ACE5736215DE59290DA957175D704BBEFB0E81C2CF906C3A579BEAC3A0C945409DEE4A1E683A0DADB3C4AA7E0174710C72A33F1BBC62A6E6F3EB9C138C0CEDA817688BCE8CCE523A2A4E2566775015F3BF66C09E716CA929BCC6DCBA7427EBD93B21CE276820734331B078558C63ADD096004B67E618D9E58FF3FEF00183EAA293A1DA2520BC03FADEB6A74B52292DBBC6EE4E5ECA8F8B0556FED36C2B41F9D8FBDA8EAA1F74BED46F05E7712E20E463502A420B6CE67D125BE999EF906300C627C57C468C8DD608F9AB354791E6FEF0EE63DF3C1821AE78111B27E57DA88FA44D89581D11C2C72F565A3D0B5E8E2D83DF178810075E5F8FD29E1953BD2C6326B693C5CF6ACE086673D69A67A181062A6ED511E0CF36381358C2DB2A394B05E0C1EE9C54B89C68E10857463F71A842BDB8429EB31D250542F88E6BD3BF10BDCA160C0FF44EBE7D0D982F15C4892091B4A69A3AE7051BECD1D2DB132599F1101E2BCF60136CE947F339A3DEF9F6D81E1BA3F5D4CF2ED989861F7CED86B1A6A167291CACA74C45BA7B5969C09EA20C4EB061D4CC4B68392AC866AC591764A16D0A42710645988FE070314D0859A1F022789442381EA0E3E83F5245272CB5FBB861C3729EC484D2F299F37D2F50688D1D8DD91F131D03207CD1459B289B19E3ED609D70D6BF8E0B97A75F4B4F1DB52DCA7AD03100A36C45D2AA221CD01C8A51D5328AE47E3307EDCEE9B27F62E5DA9EEE15B7A2FCFF1678551BB3DEAD4CE54A16C22119BCA343822DCD20271BB1518688CF69B566A123F65C4787C1C525BAFF00CE20C46C536E47DB1E4410E572BFECDD7904583BF61847868D7D1AEB1EA071EE15A9CB9E3EFF8D17A5BB7EE8BA83C95272E065979904AA99CF036BE085ED869D3CCB694C025FBDEE9BE140A0A21689F95D90D8A54DAEA98EE5DDFDFCEE2908E65C210F347D26F35B95B34642939067CCF04A098ED3E2CE3C0FE66305BB5391E223E43119D38A33672FBC980BEAB96558D3A940700B3CCA9D3AD2CEA08E23082DBF30FC08E94B6640CA04BBAE80091ECE96F128B37141131FED2A5549CAFD7BEB5B180509880C49FC6CB1C11E4CB7C7901C89ADFA0E5335C43A74053347D3028B23085647993B5844FB2716B7154D93E25DAD1CCD889EF3B16FAE34D04145237378D66BD09A254D395736990204A5627F5446787B467B619EE8F06CE664BF7B94392B5C77BCE828D6186348EA2DECA1CC84999FCCD95C9EC55E28C8C2FB559C9020C6EEB661F708E40351D7E530BFB7B1C3683BF15FAC5B17D1CE7EC5CC3C27E04889A9E59E6534C08AEF6934747083CCEE84FF2345D519CABC7D2BA6B783D36C864C65C47CA636B28B71D6797717950D652659AFA8BE3CAE4E269BD527C0425168D04C097DE8F34834A7D1728367F148524366F9E53C4CC255D3BD6FEE7B5A6CF459E1685FE740CC203EDBF58082820B967A40822D36BB4A489BF0CEB51387009D5205056387C292D584309076956E56926283657BF7CF096F54E0128A265050DF528AEED9247E19EFCC79EC301A9F38BE7AE5057456631840EE39E191B25F4F7070BB15CE2CC18777F7CBEF100FE7993681D4E965D0C19A68591BAAABE601BBAB89FC27B3C5BA83545AD645F0DB716C98D5C7A37E0AD97C986EDB88B025D25E3DCCCA816C707F0E2542E44F4D69F943E1DBD08E344F88661B68A822C3EFD648AA23AFFA2F533879540BE2F670F4D53091AF68867E7C71EDB6E9E494E9D30A1839653422AA8AE34A525EFAA62D3F5FF00D91F5DDF80FBDDE464A8502AD9AC85EB21025C0E4E2C2877D50962C5AB8283BFC823FB221CC285F3629056D1260AAF87B556E556B4C723D44279A106EE4075BB79773588333B42065811D671016AF177105106203EFC36FDAB2F5E5EC8DE043902583C1782BFD8BB772353EBC5CF03A0D869E5F3797713B58EB7480CF7B92AACFC9C41040BC9E1F5447F9852B2C5B5F33B5517F28A01D5435C47E063B41D3B0F7605B07AC33FF6F05C6FF44EBB70FD6E1AFC2A32C9A0B1AC17044401B93D6439CE53C3B033CFF06688E1933CAEEC48A04999A01956096339B5E44AB3A57FD1F0ACA23A03114708BB16803C2CDA679061B8E9808A2E11DB0957D4F73C8A06E6C50D6DA43E4D008ACA23CE2A3213BA0DAD20D5BA8B44DE5D50E188039C112B8A40B250E7E815B1367375C5698B61BD915A70096815479916F455B9EF837300908C5A8BEFA5157EB688EA02245AD3B309D10C769CA1B8E5CCA2F5FC66CC3920759A203C3F6B8E9ED10CAB20FA143B0BF0BC8529A4E89AB0C99AF77E43E68B61A9E4176066C4708FFAB05F3652817FC42039E2F22DE2058CFA8701AFFA894F3143FDA27AD85C45D3AEB30CA9759537CA4AF2079317CE5F4B5EEFBCAB981E42065AD5CB8A4CC9B628CCFAC18D2E637CB73399CE3D90A9060F88EF438E8511CE6F403A0CF14C6B641830983C1EDDE73BA27E41BD678E834167C718F5B1E2E6C109199F756905FAF9F0005CC1D110CE277DA02675461AE70EB6A412EC455B6575F16A4DEC0565DBC8F387D84F9D3AE67AB35E511657D82B5606A4DB45CEEE81C94FFAFCB88B8185CFB67E4D7171EEB391E9E1DAC625B56FED22D86E8A34924740F94A3D50CBD05B8E2476CBC7C54D2F742F0FD7162E7A138D4AC788E710AA45824513BEA162E2A1C1F709413942BAB5AABF7E347A148D53B8EBA0336D91539766AF0E827BF8EFF36389ECA38232FF2D7E341A3AA710F590C78EB69156462BAE9B8B73386F38EAC4FA26456FA555E26E7DF679983FEF23DAE87DBA66BCEA19A9F991F864A17C23F7CD592ACAEADE0E82F4737B70F0243F94F015B59330B71E25F1304DB3D8D7E2F96669BD7F8313EF9E10EB1EDB0F0BD94745D03C83768A618AD9ADDEDA7C1E6E134F8B7BC96B84652C982B1D9242F8D2CF0ACAD146EA3185E2332904E84088CA2D7D60D3E2DAE411171726B5FB6C95B3DE961E62474CEC73226E55AE7D9C7C534E278927F5D669EE6D111E325D54F338E2A6A06493D6F1B7A556A94CC9512235498409EEA477597EFAB239380491C9CCBA1F00A0D1C5D758162E9F4F5464A1A64A22C32721AE57E246722A6B2E07E544A5FEB06AF86C580DAB2B9DFB5AA0F0251E6840EAD66FCB6B89F80C2AD38383B329F9EF4589BF0E8A0C9996EC19E1DA539CFDEFB2BB0F3D9544392A06F765A74218B7DC34F38D230D1AFCF9130410A4B4FE038F7AC59B6B062EE2D2ACCD288606AD9AFDBE95D9572B78B54D26166C7817E6F72F7E6C55DD1576720E4AB99CC26722107F7C278BAC2D82FBD0A3B0E1793C2D8B498F90A9172D17244A4107D9274958FE078FA8A5A33087BF278383F439C0B41523E0E51A662A9F2822CBBB34EDA97F5398EAA12D52506C2EAAF6D4B75639EF0676F482A69DF0E8A9BDFBF6105E32B6FB3ADA2E29C62A0AA687820B4ED35C2418DB1A67A3A5B92DC61368585CF7F3B1B644A8137A52CA21DD982760CAB7FB111558ED0310E9FBA34E5480F4E707A2CEE74DC24AE5717C06DE2B509E4807824707505FFFC5DBFF798E8D85F758A94C2D3770674DFE03627457B2DF10628A31D44BD89D3435D93E4F9BC14D47E6D4B9BD3BB2287ADBCE1FA58495D9032A9A3ADCD56CCB116787E060EA431C1EA9E60A30B609AA9C66064017EA05BC16392992B7DFF62EF1046FC7E64F8F811CE50AAB40AC122CBD5119D3045ED0812F6E30EF6B6001285427B643E3C6FCB6390A9FE76B342A462994F2B9074B56A848538DE205C98BBBCC75DF6BF23CC1AF0B201E5A0618D4BC5035B9F71BCE9D3493A97FA47607D65865A5FF3FF17A7CE28C0E87A57FE951C8F804EADC21F161CCB5D1E66F1E4DBE92C69D4358E0CCC13A12DBE87C9B530579189EF2359A9DF5A8FDE00CB2B58EBD748B23F884626A66EA39847917995EADC1839BFEDCC24AB6BF22A5C247B6FABE8CF382DB48148915167BB47F505C184EC027C3AC741BB0F6676B0D0E7781E19FB8D4D630E71ED4843010198DB9B122CC301D432856B393632369FA1C99BA252F086E317229486C034F1960087ED4606288A7C89DB0EA0DE94700785322249E901897611913AA74F8BBF412639DDB639CBD1C41374A3EC66A87451D9E4127F7627DFDE4E1701D7FC9DE13DC7754952F659EBA7B1A861B8DFC78D1379274530B976C66F9CC4002563837C852D83B3F3BBFD892F14DBF64C976C924E3C656B69131EC17B7905507F78F073A7E509157215C988D490685F8AF23F64ED338915E72B518E4305C9CD44C219876456E87C0C59C5D7524C86CAA161C745364A12890064CA9061056F37ED1BD56B5B09B1423775BF0FCC898AB1BBC283B23DB6E91A3D749125992FF1BB598260DCFE428D2524050C1F545FFDA18A63B052C0C8CA4DF8C3BDE83EE5474395135FCA2B05157C25548B0804D1EDE"""), - TestUtils.hexDecode(""" -0692e4fa67413edeabd602bff25ccbfad2e3402aa7399d8a9f7d0d6d389532019b7d3e63229d12ade7d487f1cade7f9533fbe2eb22a810c94b814a923ea83d7bccbd975af424bf5535f235117afa08156650728d96283a92d6276e34f864c37f8c11674307d653060d8310c0c7bba86515e051c3b1193087df6b22648ee59d6bc7a8c1b509b71620e3f7b5a0aa445f628e15e0725fb49e757cfbfd3dc5fe92a627bee707e33537fced3489e58fa73b49cffb2df08cd45aabaaaa491e77cf205d5be4f86f5a8d4272a5513ccdedfcc210fba346322ffeef9e11dfece2cfb7b854eba1ab581cc533cc6335b2195a20dadb86fae9efea0ab0c7d17710f8b0d8a157272509803c3b49fde1063e9297920bf245fe6502d8bf0a9a1f064d5a58b30b5a14dda6698ae37127f8d867f9aea40e93da3f4af04b91caacd66031d03c0c7e229ebeec8b818f4c970acd5c4dc8e17a3ce618ca96f4ca29f46f5e4059becc5f16ee43df8ba2ee1706c41621da8530689b42136b8a62dab7c691e566b9d48a28b45af799af56bcba07bc6044b64253e9a80e9b5ee01e8af0ca627a84d1a2a7ca9b0659dd1a60b788e5f6538a8223973476e9466459fc4f20cf2d1dab3ab137c5cfab433c436e7f3a6a681f675358b6721dc2850ec7b43aafbda90d13254e4ace6016175bafc1bc28dbf29541639527f246f6c007f41ed1fe6c0329260ce2ecc19395489b5c39d66543c0609120449037f321db95a85be51f1d01a485939390c47b53d82741edd3a5febac17ae6a8a4ca45df32fa6875b4e907d544e529ad26f29b6f923e21acd7964fe739fc1864d72eabe0859ad5e98142ead24c91167fc072a2c2673c7c5bf6da83fc7d662283347388891ca575f275907d06bab987ee5081c2ec808c81c563c902203f8d525243e20b5963967bbbdfa2e8ca9ec8ed703d8dd66c29c8a550c4676044703bc93f969e35f77194412bfb20441bc5e89b5e3238b766940779217af090e0da162e0f95761f63e05a378d0424af4c899a0a68060d9d0e5a035f6ecadbd550961850ee9345111491140810e2eaeff08d8a817700ab4c148c95086ee0663c4261b3cd53f8ab5b5841ba8cb9be8c5ad146d8549f21750be69951fffcca492624e136ed58a5e81cfb01a2147cfc5ca07a0721a38adcd25fed771411c75a5f7ff37457cab19d866b2da0fc45bc77e122143800546bc49f44909042d96bfdc63ac60f09bf4a75e171ece95bfffdfa73b4e509750ec6579996d0c83d59afc88ce9af26715be98cc8e6d05a14188a0fac6af1e96fdebe8f10b994d50ae6e84be257e6392e78d70441bdc5de30a1a4a5cfc7d5637810651fd471e162df2a76571c6d3df3b227e89cebcfec352d0f1af41a29e993af22514960c64dffc72a9819a6092150bd440487108024f0243db54ea68881d1c99b529ab529ebca98ea690046b1e37f6f1110686f6d9a7a725aa115c5e9be4189eba063d28801ef85973d0e9eb15179cb64378b6a5304cce09c82864bfed361ffe1702a9ff8e51a214b584247b967e5bb7f64b955acf25bd1073179776d9c03790d46f828342b90ffa2a45081184c3be0caf7aaf6c354b698e9256421ea3688c6fc18132d4e8d956baf9b821e64a579b1462ed4e990259867899ebddb19a861b24c20c2b0a6c274a064e1d1db366a293673153752847a2a5acc23b573ce0975655b79fe1a1ccb347773e3b1c5bb3028a1508687d17f9bf86ebbecb3086db5ef2559be02a68f1cabb47eec1671e6d3d35b65371fd5487b413fee14691745d0eb260c9008f07b5ce629c6d748c452c3131225f8c7586d99b2122202860f6e73c7def4401919e02e18471d1fd874b7c728296648b5ab571c517dea55be9f9ba65ff2cb349576a76030789dec17102a375ef8d779f2f2ed17be8fc41b84b1ef69ed18cefe28122127f211ee1abaf2a4044a3b1ee653395141da50db99dd3f73f85b5c0158a74f6f9707c7f62beffd70c068db1d6ef686cad7bb859c98049935e73aa4ea76c3225d4f19b333a4290ed0d723c6192034618fe3214306536741e20b066a6b9190972f4c4722534bf760a07e8d3a45dfbc67dbb8a5874332a4fc0e0a0640ca3999b93d34e4d8731957465e213577bade1f9b371540dbba188674ea205db7b244c77b6a772caf69f8b46b7b05439a852232348ef6d437bf7c6c79a4c0520a8ead1f3c00de2a063eb5a1e162f4db1ee94f1fb94f56f62d951da29f6b3018485c4a5c2c5f8573691aa096d8cd2922b66c8b7fc828d49e92a3d648cfa8ef524199b4bf5a8f15693960c5f59862825ccdda554b17e9c35f7e6a24365508f5a23c6ae211e3db71740fa444f92159c8df59c4b073f362cdb658842466efde20e9ba0472e2f682ecb655961ba8ad7575e8b02320ab6fce9188321816968a15789977084409d89b487253c778ef1ea1a1f47c750e37138735bcd58f6956ab7c8dd1c8a7ad35067c0ba0940b3b091c362d3165007df94167f33e0c660cf02ee5d6ed90c8ab4655ed47655d810751dfb2f1e65c890ed24c976bba0b8a998102d660a05325261b38fdfc82ba300683df5d561f73a11fe6f06425d11ef4c6f32e6de2ee6081a9b772e07614866f54e63ccbf7b1d9a1c3701ccbd1d9087241d8e2987203dc798d9431b8ab1fde5ad788db13c2e996a1d21b1559cffe3f7132e1aa83acf6c517d8e8d719076a36c08b2c6afbe5d23dfb9c5272ffb2af2b8febd51946199b90f98e7d49358057fb881f4e8641e0524c3471c0f6bb4cf59bccc7dcf09ab2c2d8a783710c982a35e4512c30e1c19bbfeffd992884ade3dd2a90039ebef2c23ab98fdfaaf6ebf34ae7fcb7fe742798c50a49d740244e65c49b22144c05047061e592b32ab61733a73b55ae04c9f36273dcb2eeb4872e7b7d009d4a54b867613ca0f69c4e7756a48ba7f9539048d495a578b8a76cac198d77aeb6c3a7dd474390f91faea384c94cfd73486ec226319946fd829c3ced266ab11db84176c7f67502b6d50ddf46994d6bf748f118045457e3ad7192f0b03c2bcb2455d018bd0ab1306b473f3761fee60d941637c562cdcda0dd5d5e86af9e95bc22570c07c25d5bbc6f1ce04be9e7bce5f7f095afec8b7c4cd930f9bc106e85eb8620668b52c9d09897460b1c8d74febabd73ff9b730c291c28f1410b442d91c533383ac3f2f41f0bcfebc9121b00015d8c506b2183b7d183751636da9226b795eacb2a1223004ea8a18a805b272384ea239ab86b41c556591fbabb783a6f909d5a181f3563ff1f9abe58cc921c751f3340497d94b1b2c6ced1e3e4345e73879296bfd9dade021b25436d73a3caced5e2ea070824262b5d6877aabfc0e8ecf6fe0000000000000000000000000000000000000000000000000000000000000d172332""") - ), - - new SigGenTestCase( - TestUtils.hexDecode(""" -a15c38cf5d89e1912b7ecbd269ebc6ac156697942a3b2557f5cb631782ee2ebfc52465310ec4700da139935b04ecf37bdb69f0db1edb595256837cacbbfa9188a2a46e985e6b1f7342a1f663244570c6d67dcbcbbf4ea86cfbf98cfccb03d10c2848232ba97093e393ee4db23cdf7791f1adc46d9de05a91791d4702f9ac41bc5002645124910bc6404a1451e130285a025160a629084850d2c205d324401a963003452194488848b61101436ad2940911a36d04a90c1b05708986881a97051249291c22325a948dd1462c19b36d03c74148c08822377263082c6038450c28889bb60da240285130248002685186601ba46942266ec2b484d30206db041203301193183261c42519c2290b0152e4c08dcb2011d1889119a7450b2548cb222e49882c4aa664a13848099851e2026d54b2219c800959381122010924349053224220060859406009274ce1164dcc360cd1b810d94032c24662dca84d43122a11424c180122838811e014060349814830320b132e2285699244895a36504b241102954de2a0109ca6495ac00dd4264a511222049440d3460cca2229e3321108054581902d6036900c826cc8880843000c64384262326d1b408821842dcc264c1399089b48690b3970c1481282142613206252226208389112278c4ab02dd8c2604a240c53a20508c5241cb48514c869d2324a19318a59022459106c02c929e1264ec380009802125b16529844010919410c221098c69012108d20002cc0346e031091222131908020d9c22400278421a98820938804a4894446859c322d82287262940503094aa0c22c20820c22b5855aa42914850c20c680c09661db126221324a19a2694c12025a1291911629122171c0406a49340adaa6091929714bb405e1108e1a448524c420d1244164302c00432acb3024a18225cc0869520024d2186614846dd2b66811c311e22866093225e1b24902c14c131165420070a032715b848cc032281a2068da226a519641e32464882631124952e382910ca06411456c84b24498384923a66488b208e198088a364408288cd01401e41400d282318b00469bb24410432541c668cb4426212910a002260aa8450b262893b6444ab0005a4801e4444e81c830cb8490183931841820813285023951c01824914289c40406c1304054a831d4b61018998d1a368911b765e24465cc1650a41251dc0812e1c00c00b5650b1229c4284104c84588a271e3188cc48608001349d8368280406514b045ae75b458c51bf83c97926488b9319add26f6fdc0a6e6b427d7dba22425aea8bdae2838ce001237c886d3ff6d54cd7c7e3e6af667c824a63e53772c5ec84d83519391755e37b16b80fad2ed94725bdddc3486bafb38e521839fd4ded253cdaad925e61e613f1aab1a448212259009260fb80e0a7d0ffd726c7a40d462a1a3fe2f3e4717429bc8dfb40f332bd927d064ea025e002aa2210eed1a457ab68bc0248b68325537c328af312744d16cbe8ac0b1c9ac1a3a79afb3109aa934f2a21f45b0c5d6171ee1cf71db9940d186be0df7c9d8149aacf1f01d46ae77e41635d2f73202393f73e7b2d14ebd62662c94d65f1320f8802d9486388ecf6b6a93732646c8c043d39dc1b5efa33a72c1fe0bb345598724325d3f921694d0ffe115aca5347f73754d5fa7f601efbc5217827abcbb2ff39bf453398e896218f821cf5a0eaa60048e1329f0ba4db933a2d6aad7e1de6d011db3305a8d6a1893a55de3073a5e4cc381f74805d163f238e81b55cfcd3362b774a3ab1f99823abc8d9801c90d8597a8feb3be962b9552145401b81a4febf84a269bec2fc81e1e77aca7db60f18fe3e42eac782247cb617578863120284bd8874f798fc1c427cd2138a8b5b6fdee8a3b271ce23e45dcb71ab8e63040274338179f60729650a245fe491b25efad8b000b91cf551afeb7cd7ce185de74a2e79a57fbc10f9afa86a869a5261e555a39e814b72bb251277ad9fb91d8d1565b3b0929f043cc4ff692ff0b1dd92530904521a56d6d2916f1516b09d35cb7b03e5b40a1ce80a9077ca6c2159c8eb5b259d5edb6d800463fedf135748de6d2adf32eb6be0637d567ea71acf992512ba6493ce3f318bf7089cbb195526c4b01b43752de84247c38a7a26acc2de492fe300fd19759c47e87b4587e4a6f6c92c3cb78cdd20650ef3d2bbd33388129cc01ea69dcabfcad0bbcab9757cffab601b6058e0424036815cbbd337a7fdf4b5f10f345ef80b3f357dbccdad0c6661adedb7cdb49a796379face0861a1c3ded98b63042bcd670eb19484de9f7bb5219e48eb89011ef3ae9973de2c95c84f6cc92c09b84d32da39ea91b9990f1e5f39a9e0380769d5c0b6434d1a687d6eaa0c199ec2f297f47f160370e22bc8dbcb127ef9e40316fc5d6fe7ae17e0b4a5a606b3b717d2ed49cea5fb905615380ab861e051aa98b6cdba93b5687755ea3c94dca0dd3cf0a23a88b2e13126931afe60949c3fa2ee88b6f33ebdbb1dfe2c4a7b09d154d01edf95f93fa4adb187f8bcbfd736e02357f5bfff2c393ee27fbee56402ffb58aa8fd9cf0d51d6dadbea4ab97057ed0c7308eb93c7734cdd5c1bbdeb97e57ccdeba01a8c808403a4091f92c6f296cab71e159e71b7b7b0b38ace2c4129f8d2851a8ed353cb2eba0853e2d3b80f39646a6566ab1294eda5f39c211a130d6fd5fa66372c96cad36c4664fd5b6c43ace7913c4babfc343dc99b87d67e1d4644524e5f62573b44cfe62fb9718be0ebbfe9c2924c0dff234898c5378565bee676ec0cbe2b50abf191ed15f3125987af4e0d78a19e5208f1cbc8c73d8be34be57c373aade97ec18dbf4dbbfc06b976261cf9b1e0395997eb8773a15dab297f71afe40d8baec46a96143d8104b7385669f23d1497f99a525f72a278ae4ef39add1ac5ae5c92c1fad9473229779cfb9440a2412ff4ca5ed6c2abfbedd16bc9585c0900861464c8e489089102abb0e585352fff291fd6a52aaa187f4d977b6fe3d3429c9d46d79e21508e400732d318cfccebfa1f6f5fb0f2063179cf1df2bb59323efa12766e81a572ab221a06e5a043808d43a2275d9d51013f91a2825e084bf9dd5e1e3c2ddd5c149c0fb66f80b2c90dc09d132bf834156e605f33f0091983d600fea8cb5710414f60536a3f9efba209b3eb06b597a5eb6af3f80f92b12c9ad310dfd1d7a3e3cc23444542d351a3d4b6d08be61ff43756bcdadef51bd4aa335a174073ddc551b661ee1c211866a52bd0ca197c72078803325956d78dd38a9247676890f46a1a38630048d266e059df2b9051b17f8c453c532a818429296bd71c91c446142313e399d08447610e941a9bc7d225770a075a955d8ae027ae0bf880862ad81b3d2b6cdd9839a7bc9da8ecfd6c6d56140f0cdbc8fff13d8fdfbd8ba47d93fdd75df792e8428460523fdcfae6e4419f38e797bb06ddfa896576a4693bb8046bb27042f3899cb36da3f8650828b99b6945ffd6c7e31595ef679a1277be4e627abe37216515afa2b4599b7cff8d493601abf2bf09ae9df92a04d34881ed1efb5bfcd7a7e1afcc1e40b5716b3cd36d98c91730b795df899c5c8c26a7d74cfa8b1aa90c1648"""), - TestUtils.hexDecode(""" -22AA98C685E1552B525B4302C943037F668279C224B6270DCAF2B06C4F4AB1254C48DE253829FE6DFFA9CB6BB294F054711BAE3FBACFB900CFD1F0844E55D51EC6F697B998759B14C13392DDB6F7DEBA77FFC22468781CE402"""), - TestUtils.hexDecode(""" -5129dae7c620ef4c5d6b0e0f7b43acd806adc035cfb3901e162be14f2371bba72674649e2004b4d055ab533316dc520afa8c80e5285f40f7ea4ef876e68b0aa4a559ec2363032efe5fd5a1d5050be8221c24b23c403ccf71bde5410b7e5ded038255dfca9439992fddc4fddf96654c78098c84e0182d954e204510bc7e5635ac29cfef21042bd52dde771a500099c75311c8657c5fc5bf303b7769ce8c2de7548b388224e727505c42e6bb69d48d845d9a43e845e7305a098657385307ab23c6bdc70de07868ecc1470b98e2da98fde4636af76fddbde6af2b60b4f27e38d4a86bed60e6f995533261cf91a618c07df0f659561f61bbbd70dd2b020cb04ac1fb6ee1a31ee4f4ae5d0bc2af22d60701700a44f2e8d11b72f4d03b3a96e2fa491e6e61f8dfd3ca678e4eedaac1e6bf418cc4a34b24bddfce3975d84740f7fb92ac2dd7aea450f91bd6ced924f7204754026f649868ccb103100b79d3ab2fdd2f916a76a6212bc583f1f5e541dfbbfb10234681c42ad56a95331c90f5e8b3be82a5b82ed4292094d9d60569fa760628e082740bb2da0a14b2516dda632c007ae3089a2068d2ef48b3f713999a699ab180ca99d7c49c4a0f40b908dc51d9a17db286721f8541839d6acb5eaefcaba5b1ba21e5ace4be0924eb0246e4d195a6eea6e962bb07bef9001a23dc0be7497a1ac79da047ed45b4c38196100b7ce06f466df295655076d14308d94d55103d36799a0683573768bb6baac4a10bd3120e9d47d7798121ab46521d7de8d1c3cd9618347d8947c47676c547231e5be77153f02a3eccaa99a75230e45fd4c1e6a6f951d1a5e6c3be098caf4a16ea3ee88473b1a8d91c0886685409ba9a099bbc0438fedd280f459de3c9c57c92609a865add4cfe76eae9af088680f92a68ab78765f7ad0b95aadfc0a91e175f07ab1f0887b1f448530866f002fc089a63a2e2d33ba63ca1985737ab0b9a73d23af11420d62a8b619dfec0830cf62757ae7f0402a4c0f209d03ed8f1731db5079dc5671c19c5bef712d34479b7f879dbe694e1bfbabc9c05109c615be763dd9ff5ffba888f88b62128b09475527d12203ae67f1ee8da83678b8a4b7b16f7700f919874eaaca48c10cef50a0f447baa17dd19eda59a1f71ad1cdc88e91fd91424e8c668fc93690b9b5914db40ba677a3c71a6d2cd05f42321463c12d55de1a717f69c132dc35e3bddfc23064ee2183e175e1ead1d075c7c1115c8cab91677ad6b483d7151010a7314ad558eafc3128c2dd590aa4e32e8c86cf769ff58ca5f37ee3a4ca0c9f9b2c4a9cdf2a8ae52d1d09110245a8884ac52c597e97b0b0304ee706795abed33f2f1885973253da8728742b54d4e908536c93ee11c1cc36da21d8ed4956255c0a28262baf50ff4a8df767e71a2d920f53b25084ed2cd8069fd13c0d1ef81f6989c0e93609038e9c6174d2a9333b3676ba24886917f32b7316d45dc6e99497f813b599d0bacc432ede0584c654551d3217c63911654b21e0631a5f7abf66d48b2cebff62cbf41ded241a59816fa9ba99cb29a9d000873fff81c689ee95bb9fd31a31863e1bf08fae8b27169c7705344b7085c917bc4434c9bcbaa27423f634233f75b82ebc7adb307f6cc3310ba95478572820973732f4cd3d1f749b728605ffdf23472810d01f6f9580b3852a5c2c7be4f93615960541eb2dc4d5557dffa8646d916370f89e09947e4e14092073357283fff846bd6b83d81092639de3b6ee260770b21275491a6300c12d5ad261f19d8081c9a659bb3f45cff2dc6c04313c7f3fb1b2d4ca96a603259310628356cab1431bee201ef7181f0f9d35e13b6f89a3698a56c3fe08a76418b6ea10b70bb2c0649f7b506f4b15a2578902d6df4065d4c3e79ed26a0d965e97b5ccb47110cf3317b7d90abcc9c7567ad4f2c11c5ca6617e643ee55096894c793d18adcce74c19620b112ab80152984de200d4e4a6ee29ce266b47d662accbb42fc74e7e088138faeb06f32e469d019979cf0b55aec3f420f97029852379417498605cd513fae94c5a5bdf3eec29c54634b94c6a96b0087ef2c8b2e32ad49144a70d27026a5900f9bde658645190ad83583ce8d4a174bf3956f3a581d7e4ee013a4263172d09b3e888299a06a0dd4cdd7e2a118fd753791afd91e0acc9eb1e4d3322feb169e47ac2e9e3e47908f293cb7988387c956806bc4e5bb9f65a84cdf2df9376c2eaf3ebae6a9a710da2083af685a8de79e9e27143c6894a847aa9134cb184b7dc7028b664246dda558891bdbcff3af3a5e0ca8ed06c1402d31cb5afca6260f4cae55fb6a6781768e6a1fbeedaaaee620ec0b7b964a38bf46651de29e4ad7247359df1cf4e50e71f691b73092a2f75f4669a145ffc5a51d51187f42dba767d28a39800789c88752be0c0e0b5aa2aeb3737f1028db4fba59dfba974f9ed8734a57f1f2db29d14f708cb83fbea9e4889f6bfd6f09d714ffe825056215be601bb8b6168d787a6d17335b87986913ff6aee38ad38f571435195b439cd82930a3386ba6e304b72fb5cf04b1ad8d64d8334f5ce0d14718232c613cc12ac1341706f829fa50a5c3010f8d5daf04c3bfde5ba88fc873a2e018d274bcbe85a9559eb224f6c23df124263772aa1262d9932ab813f50317bd7d4a6b0cfc207d8dad53d193d7330c9330d9bf866047237df5baedc69ff546308d2547b5c7f9e0909ff97da474bd3075413b94cf97fe331201f2cb565438182f13acb95529fa6cbd18ef92dab1bd8522f332ab5f375fcfbe01a83e38eef6381a032f9adb60b59e5eb54786f5dff4f5e003b79c7e119663c38e7e9baa0199d3ba32235166936a850c57227b1a16561ee407f7bf09cf6671ce0d0ed0f9d7f916a0ff7f41d8adff8c42b8f4640f1488841cd3cc1e38918dcadd752318080b4f15e58dc7f79aedf3805e1cffc25bb01591f15f54155c59a798a8bb9d5247eeb5d9bbb3abfd65f0bb65f119dc05cc0105475fed4f006e61a1864a29b53770e5b3cae2fa13b5a0d1b05ab9db868a7b1349c9b31d1a1abc19250be50627e8f7283af7d12c57a1c110cbf4acaf5990621d5c04729d475a97cf21c5fb252f5f1514b8d3090cf6e4e22a0146fce697d88d0637b3a60e77b9cbf527c4269adebd5eaddf12633c53f1ff09d869a846d3121371aca8252a5ca1f4fb1b7afbbb3256e53a9f25a3dfbb3a95e9beb67711d27689a28aac998b3129861d9acc72122d43c300bd58d934bd9aaff2ebb55268b94fe7013aa8670a89b19e1cc5d201ce2e73f6bcd8649a18f8caf1af021d374570728690a6cff0f3fb04050a0e17344e7483879798adbfd2ec112325282a3b5d6d72868c95999da4a7c7cacf141a1e2c5e657d7f939ca1a4f3000000000000000000000000000000000000000d1d303d""") - ), - - new SigGenTestCase( - TestUtils.hexDecode(""" -85c8fae58f6c8a7690e2098cdcb1e487e83a1ff669b31724113a0d9f796a68c860945d21c640c54b863814c3ef5a180dca61d3cd000d610ac6b0e25ca8b73b33df1d991902efee947777975b942d55d9af67fa96b7e45dab6fd52248361f3197b26baf40426b4e05c81d1138e78a7c907e39f7c05d0f3870b4a0cc9ab408d0052298105b8040e3c028142926488888a2a4101b2081d14266a1404c11032e5c1864a10030dc144c012509588604c9200403152284204e99a4119392111ca66cdac0100a086a0c086ce326261398489418889ca8715b262d4090881b2944e238065a9891c1300944262643a888a04826da3070ca40464a8851481866da28468a346d1bc48599a4700c305110b60088266560465120180e59927091a685c346528996309430320a38118a94714b340454108904326a09944ca2c640942492509270c0926090366a403832098648c032801908646394291416685c822da2366d0428841cb2501c99218114041b0981c2104a9c02040ba05122236e1410045a304419460a10184ecaa470e2180d81022a04186122a241891828ccc82c04212d110186d3186880b8651c335211c34499a66903a50c840062d3a23043440602c56108357110234121c561502828e4480221281084c84d93948002a32521254c22b730e19048914065c4440408118e0290892407211820119b828ce3205299b00524c78821a61150c20d80a650110012cc262aa4244642126543000d8242288c38016124601b072d0143088c2450a018241b212ddb4032cc94412416504b14404306061ac54544b600e1404218b141220405432844d8c641930652018881c2a81124b405d39821211450db065211c26cd41621631884c0b06c9c366da1240913134558a00818409241222452280120838d0b22449344210910904392715bb02922252a04c38c8a10904c047264484e01952122994c0a2166d8326a211522019540611866a4a80022b70dcab00d64208a1c28841420891c18124934320a330a0420804332921b476c61800da2a80d14c8711c4844c3966512900c08093243a08910318062144c8b948d931648439684c206288ab810da202d1b384e4b364e4b2461da886d6424691c348e8b98115218859b2669d04800a2449089240e9302121b4765a3c8841432040c8808649020023428a2c2049b461294166113106559422258144d500408221401e11822d4b210dc482c1a064ecc900400210ce40632113530040620d8d109619eb9c8ab718f85d404caf02e2be1703a4b04070f4d1261a153069f796c9295b1f6c405c47034bfa4fdbf2840a939322858cee0056ea8d7ccbe8c58dfce601cbd113bf5e8213fa32a73f07430012ac8ceff89c87907f6101e21c8dd4617a83509cbec27c7be57f9394e067489755087407fa69791c3c2aebeebebbbf43e8345b772b451d213135a0572316f52008fe4ef5812bc0c1d78e7660986b337eb896324598b19de9d6d3f7a2d670223fdd4ad7f41e46ccae6955132bd34723dc8fcc37ca79b9b8111f1461731214a158ac65a2a2ea9cd5a856b6713a1e07107f6b11d38320d4e51c1144e91cfbc89dbf4fc56023da26530e7614ab1c7c9eb5e2491c1f2a0abcff2e4d4fd3c1e39b061d390a60b6adb103d1ff198e70f945018cce7af3c25e58935b340a94423171cf610c57ffa775172c0fd3d4fe30c33c894e8b634f435d47300751def4d8f20aba4b2ecf649e52ca40562cb7807e5f43718567fdf09e92d444d0bef10961e4141faba4ae1359c49c0426c6f05b89c93270b1cd8dfe77fa865940d5f2e33ff2aaea1da3165e3cc38ab8c3149079ff747edad263a45f5a0dd55de409b611c2da6fe5b0ce3740064e5c9dc65ed9facb892e970af44646287812611539813aac695a1e0466a12c6c0912c492270e9f19728c9d8b68dca842d462ad41d914f8acb729e37e43693c39db2057c457b12ea78e6c4cabfd0cf14089523a60a5a223b228f8c64163b003e6af0026a7cc947856bbbf38ba43226e4857bab84d143477a40bbe194ac92ab0bf2282fdee0798a5827e2d82662e5744333ae9fd9063310a1c5f77438789e7cfc96c3ae961cda792d572d07adfa814ea068df14782f5dcaf3173a5246250d0ee9b4fcf3b145f2eb3e3a4371228af90f7737053496307704db71ee0eed602ca596a994a7de34ccaaf15d987afad5318476b826051c482965ced549f49ff07fad9001ff081fd49d903e18cffc6c824d60613bc4e8433f3eefb0ec666ce7d8a0f8decc80139c77b18e60c2d8bcbcb4060cad940665f9cebb9537ef55c18fdd474da07b3333e0cc6144f9069fe6496da1f9c60eda3ae7ffaa851d518634f8e80fe1fed6ab797289ef2d36910a17e3e825f7fd91629c411b7747d4e64b751540321c1b83e5146da1cb94bed6c063e26522695bd167d0fa5c455c1d3b7544b1b3ae6b5a080bd140c2709caf4394207ff5a08ea14739af0199328f5ce29fe31314eb169c6569d0197570ba2cc9eb6519d70d451efd270ea6caec116f43c5295d6504422b0efc8e16740626239fd20b815af715ebfc8e552737f17fade233f9674ab47d35615518b17d2b5f8677245295d6d79520ca1bb2a4ef675fae5cf719c99e86af39879c576dd3092f6a13471b248b10e3d19ca8257a4f2b73ae373f37fbd7eb79b97e41820dd8d048bf77d6487576aa0984c399b8eb247a0a416a50f615ad80fab612b532a2126d47043abd20198c49894b9a265e87ec93b519793fc363f2a1028123bd72a25953e2402b7bb6912945cf8b540821e173c2a606c448707f3b7a6a2ed692cf87588e26e08a6667cf281638a1d6e3858d96563b29058988ee461cf1f1895cca095f116b7cb35cc1b49ea3f94189efb5ed82e1d52574d269b4370cc235a3edfd4ce0d4e945b3cc5f316740954be77796d54a12b1be196706639de8851fe42643a22ed1b8c640dfe5fbcc15b402c7ce42d4038be2a0f8fe5a340a5492cd65ee3af3a03ed1e25452663d195ac43d696eddd08d47a64c63fb8572edce217f894917f30035c5c8c1065a2ca39a73f7c3172e7c0b4387cbae9123437b0c55ce5401b4a965362ddc86b4ff3e3b433ab15cb2edabe5aedfb8b9bff2e4658c875755fdd0d0a615499ff59adae936f0f04e086f9adc29e47b7e4fa8b94828df077a73d8a3651a23efd8def526e1a8e0a8a8c1ea4abc5983ec20ee7c530269fb1f23554d79092c24c4bfbaa7bd60e271b4fff69f48d3ddd4ddf94ce3808135034cbc78a2cd31488a4a5e25a81bd41edc5999dc1fc4767c9f82144934eb0233044407becd09e0aa0e0d5b531c1c010ca35b97da6cb9709b78cc0d96499cf229862840bb1d03f561addbb3f8f0f1e6d5c8de369dff715e57d21cd095a316a640b6b077c4aa6149167f11412a42cac3da1a25464752e24e0d1047c361b2ee9b6e6ccc58a683cb681eb116df43c9133f4ad39d4377b38b89b2a1abd6505044860e8ddea6332e79db6436fbbcd7f94ea293dec7f46e6c8096a127db1bc7f65ef2ceeb372fc66c7d8ccdc777d3d88cd1d65d5110a9b197d17ff1f2bc8515206346825795cc3386c9723be137b2d2a9479d"""), - TestUtils.hexDecode(""" -0B0F604B53752973C4A72EF940C3FBA910AA9AF2916D673D69C4AE4DE92A237F271E84921C309B59B92E795BD26C5C015EC5176155DDAE8FA17D7BEFCEE3A23E0201669CC55A6F270CF0D03FFC09BBE4B47D318B6926808EBB49EC8B57A849896E76648D51117E8F518088D66B69D88E09D298186C10B5678EB8AE43E9C0A794C63CA9D597C4B74C959E9C1E8E0F46698CD64CFF3C0FC6174CFC51095E142DED9F16E5B2D3656555D2D42832280164E0C10C5817AE47ABACEE7C3BFD198A21BDD1C420F2EF0776E5EEFA46E8BCB49388FA6B937FD1FEB2BF09D5B9494A534F19BDE4E7BB8A5E4C558C2A166006B481A7C5865069A3DEA2B880AA503B5C020F045A4D9C3E5C590E4AD5375E74B732695A11164B5A57AA665922431498A9218CEB9ECD92700E92BD11E0A8140938C4FB9543FA5DE8EDADD1EDBDAAD11A6AEFF2EA409638B2C7AD546EFE390729982304F35D7F889C0CCC81D67F5A1D6201BC4BE8D1AD2D3CB85815CB9669B56F845148DA0DD2D6B5D7C4986DD3F10BDC78EAD8B4A88B7AE1FE11C634355F60A43A55C88B37954CDA71F4744C8E2B4D7F8D4A2BF60EF0C44CDC7F7059AC48A94B10279921709827A3E1E7A46DD857616E6B737CDFAB71CBD47639245E392DC116614CA3F099B8F2092AD667DAC43B8501DEA9876E5E0B98B41733DA63A2517A49C169A95E583F18F2E1DAEB4425E307509CC6B0B376827F0BAAFC2FB2ABD4E4151A8DBDCB8C22C78F5DFEF0DD1743B047E58537866795D67E35358020CF75F0D2B80287D62AECD6D34D18494D01B4412B1CFF279CA69C18A263E7B862F514A7A64BF192586ECD460D22DD2280373A66ED987635761C3CC34A5BF6A370F9F8B16F98808767A2D9A1517544D869E674980758B15BA7844027D3593432101FBC51FA4709F4D041BE9FF31DB9B7430F1D7F8E06C22C4BF3F8798D50C92641CDBF0B2C88E88666029FC985FD4E9FFDCD779C7F7600D02AE8D9E3CE6FF76F0B449C41BDB785BBAC9CF58ED7ED1525D7C7E885C0D46ADD0F7CC3B14394235B9176B69A222567E6533870EA540F4DED9A1D78F2CB89E6C1DEBE67249ED8F31C87499E24DAB0434FB9B40EA695499C76A1618A37B1AAA5309A914B6574209A61DE0633F086EE4F2455299C70B981532A23DC453939D223BA3A25122AD498795624C727E973C052E69AC40AD465DF55ADBB20FEEE76BF2906EFA7B0D9D5EAE860FE02500E2E0F4A21CABCF963D91262EAFEE814BDF9775874D656F8BDE11DA29327E3E7C7C95395D0DDF766CF34005CE86592F6787D1044E5CA1962C4DF2719308B2D6335FAC77DF46092CD3D5D228E381BD7E5FB4D2EC18B19E18E4748F662AB34C3F2C33877BF4A8D43A63F9B5DC75861AABB42D34EF37EF19CADBA110A3807D1699B247BEFE3D61AB84941ACB227C79CA05180FD3415D0E76EB31B4DD903D78553F2C22563F9B22BB876E81EDAECA4B8FB9415E2BD5AC32CC08775A20E8F90A1681C9957DFC330B6343E58F841906EE3562ADD6AA53FA1EC4AA2E894AFE769116E29AF49D0FBE2D8FEBA215E470ECEA81B258977A0FFCB17666953C29B2F70559DA00610398A08E0A17D69705707569D6484C4203C06B17439E9D4D9DB8456682A79659DAB332DDF45C67E527304013A422E46F2989BCF033DB143676A4EA720D0DD75584298CBAA765CBB0B09EF267D503F2782A427459FD2A83676DEA43C01D288429A82527A69B1EB19DD3BA1AB7428220BA74F79A81377F7ABBC027D96903AF6ADB4644E9F5CE676FC4D3ABD977D6438F4743476F77F3DA6E822AE61E0AD38549BD21E0FAC1C963F1D47F9E6BA6019591DE22BCEE5D5C9CBC4106A369C04BDF633F41EB1D6821B1F43194CC14B02B753584A659EA46C49B983F592C83BD959690845E872B471A38381CF3B2E8F4DC157D9A60FF56EC63B1C66D2227A069CEE7E48DB0E0D5991F96740D364DF89B08BA67098652958A14516534103ADD9E457E6AFC4DE1AF332EF3ECF6897B3DC8E5D6980FC5E5D829D4326F6023F48CFC9D0D787416EE61A0BA3CFF5E7C69BC83B18928AD277AABBDE271EABF8269701E526960460EEF521E83CF7A61A3CAABBEE1F1C99402EF55FD438753790CF56034AEA3292828AE858B2D3B9C8D77FF4545FAE7B4F2AE1EB17B8198F4846A8F4A105CE250F900969696E477B2C46AE786481BCDF85715BD270F9C29BECF4579F2DFFFF7750E375113E33ECABFC52E4DA5405849FE5D5F4A17C1F0984A1479D561943CD1120037EE821A2B57A12D7F1797E64E38A4B71E2FB10207ACECB96B3F3ADFF82EDCB633E388FCF11C8D105C1F6EDD41B553B4B559C3199745F3B0EB7326B867FD4CEDF4E9ABA1FD6A10E1494847FB5DC83C91F7A2DD351CD1AFDF95865701FDC658A41ACCA58E574B67929EEFEB371589374285148EB09157AA9A67F2FD54FCAFC1248F6D84951AB1A676637E9CB76C17C282DB53B1BEFAD8019F51B0400DC1CB012B97575ED81C129636C38998A2E6FC5AB7F0BF1FFDDB588BDE4590A7A0F879FFFC1183A3C6CFB341FB518D0786A6473FF9614877B1B722AF4B2E1E9B5E0DE7C3DB004EFA16F5CBF07870D7208A93A9FCE0EEB598CC54F04B1BAAA992C02BB2D27217AB20A3381EBEFA04CCB1F23E59E4B0DEC700E069DB7620E22235A4C5F54522D96ED4785ADBA7FF95F2A7DB212D3DD05E58C560E5ABD0EC238B7ED01E54ECACA7D32F7C2A3309A437E68C3AC7A9BC51025409A2A1ED05F8DB0EBB647FEFE6222D6F74DD8E4034580B675DEBA4BBFADEFFEECFF4771A0C1CB0ADCC6E9B050B85D230F6B288AC3FC24880CCBDF9C6A6976D46797B75B8532411FD89BE027CD8C81547B24B535825695A35BCDA4E2E0A3A6BCEDB73DD10DD847C4A0AAE059A07F56B0ADC0401026648BA469C534CDF6E2CAB8F581A7233D2F15BB35DC990EFBFE688F9B9AC5AA5C9B3E95DA7B0122947DA03AB9DB58090FF14B736B9CAC65F966206AE7C84B971D83944D8AB61589A28058E14193751B685058E632E32EF1E8C94BF005A3A2EC5EE2CE2FF6C05A67D87E56998E952E4557250E8AB5A979ECB28B0EE41DEE07F919E67670D9CC4077DB0D90ACCFE17CF6AE69DE0C9DBCD3D552A7FB37383574692A267B0A8BDCAF3532AB47887FCC94AEC3461A9257322095F1024C880273222295107864903F3DC8FB353FBE51C4D89F30FEAA5A570979A38B0B4AC9A4AB6B7169984C576BC4AD6DA1719CD0D5ABA03BCBF1336DE48CBBE167E4293DADDE3997061469F200A391646C8FE712EBE087B448F7A7DE437186D38A4CFBFC2919FC888487B15C60E93373D076DF6A60452E62E05256AA66BD1FB771CADB331661DB4BFA47581A4367069FA20E9C6229F79D6680125D0464F7CFDCA1F5C46688D5816CD90862FDABAE753E56BAA1369AC1AD3530630998CEB4545C4404C8B9A65D5A43443624D62DCEC989AA2CB8B85414E06AAE6BC4E219C5A3FDDF8FCC75381F6A0F73F54A7A2B5BA0F546235E71B233EC107900D8116CCD398FB14F32CEC310AC089D6BEC40255A6A877C30B05355544D115E8F85E428087A5F3670D596E31D25F676B3C6FF444AA0FFE5011AE62D6FFF86E615EBE80622BB646A318BC65950889616DEC254DB332649788C07E46CE590C2362EE66BB33BD43807A1336B94198BECE586CBBE3136B5CC809F24DB5BC3069E9C1FDFE53C6D1DE29DF48A9000A7E89D6862A773832DE2151423D9D11D722D923233137DB6F34F8DFA4EEC134BC9EF5A70424D895638D1B09D95D98CFA17308908D65AF00259DFB5ECFEAC55DD7FAAEEAFD4E94EFB36698D2315D795A93B8BA6A3CA93F6B79F2E599149BFBFC6F5C5742A83C886BDD4539BCC128F30B370FFABBE724AA3F3D571785AA6234FD2359FB3468A06A8E74918EE6E87CB29178900B49891F565A80BFF302BAFD0D5C2C123973BA7B9B425973CB3D7F2AFF3059D272A7CE611F5CDDB5AFF3E2B4024FDF0E01D7AD1C63FB47D9BA986C341030B3E5C6CD3CDC6A3DF9D6901E76D31C141C37619F5BB316209FAF8428AF19236DD426D70EC81E77309D5D9AC33CF3AACC0259A19F91E4579AE49EEBA41CF79B9499CD1211AF1E6DCDC70383A35E0ABF7B53A1203AADCD3AE638862D35EC4E441100E8CDEC7F0E6D22845F6CDCDA801111C4C7F261189C7D67B981101C40F21D33D05E336F1C7443560238C72B34E47758927E37F972247F4457EA60B2546F6B5B7A91B151E8B3800CC1748587E0D5421A43648BBC5D87C591B01C229C8104CA87C0B7F0770ECABD1E2A858147B62F607A86E1C71EF73C036B18C01CA5C1BA8242BC4BB7414FC90C0A8372F860F2EE51DCC1E457135776C377F940400AC5309112E6742617FC226EDDF51E95CAB40CAB58CAE1E662DD78C6E253B373BE970129193DAC7DAE372CBEA847248C2E69273B7CFEE70BEE59DECF64126D44BACAB5F2813CFEE1EF89AA3FD6D030319CDCE94FA86E4E64998266082F8BF74877038ED888C16907A8DF99BB53809E54520E4B5B6AD44849A33EC3FA44A7B179350DB07524823FE8384413F0A7E1936D8CAAAFE1052C462778B36AB8A9A14BCCC0319CF6EE2AFF01EF5077A10BC0FD0DF76D9B806481BAD1F49EA013942F38BFE52FB194EF8ACB283B1462BFFE4AC618D6FEE7E25130EC71D68C81A9532A16520075EBC1E9C3FCDF5FFCC150F3815E8647F34DAA814935D0E1AB68EC6A1B14FC7566415CC11E0C14A9693B8711DE2D3F78EBC468269BC851D2ACDFF5E8A6388B73E33F20C0C7621C6B644649AB088DC191418292A698EFA4871224232A7788EFA2D69F9F9FBE80FB8E6B0106405F6406D00A6D6185EB521372CEDF51C2E0876C7A86A90F1F5DCC0EB3187DF8BC62736663F713A1D403665BD5AEFD6BCD3413FC63CD68B3C5C7FDE3AC4164FC3737C2703AAC85E6ECEB29E34A6ED70D4178402814B5207ED2AE12E9DE009D0DE6A0BABCBC4ED41D5C28B1943C4B61D8B1DBF4395F5BACE1E47ECF0EB9E21F9E7F663EAC3788E935A1AF73B19714ED91BCCCDBEDAF1C74155CF235A58485BCDFEA58A929ED1E959DC99345C36109E42A14438466B1F9E728801BCADD16B2D8F762E4BB8B3F01E531339DE79634F43117DF5C585D7D2FB4A5D3E82BC25FD92BB1298AC79211B3866CA1019666AFCB10BBEE1AB63263F2823A86DD3EC57E8632C9F4975155A01F22859EBC400F5A3B8302ADAA5892A320487AD077B144392528F100F0A222DDCE5636AD5962AC6D62A2382167EA977743CAA6BA2F140655DFDEF168BD620C73A47A8831DFD66DC6F2A9F47E0724081681BE62FD15C74846980683B729AF1757203F457FF12925B6B7BC81775A9E5C53862B07D4B93CB2E9FA896AF58D258384115F1C63779E4189832C29C8B142DFF30C00DCAD2328A63C92CD1E42B2A8D2E18542BA3A81686452C83AFD5F6955A708CC1DAE500718C6DB89ADCBEBF119C4707B931E685BAC00AA60E3B5F9F42FDA6EA90F5C77295E84A3AB05D69212C5368E24F18F43B450181884D7AE8BBC61E1603FDEB13797F9620AD6C2B863C495821F7F726BD5801A3D5A36F4609B595B7653799B3794E4A60090D71F5DE1AA5F0CF562F7E722C55AFB676395ED988A491A34B462B2D18AF517569531308B8190F0148CFAD463802AC62C6CB289FC0C95C207AADF82AA7399E0476B774D9B876829ED91EA3E5C40B504370D266B7B3C72DDE2CCB7F3AB8E820ECB5715289451D352D83DB67EEA889EBF9E8B012C8265376C841BAF6EDA4067A400D4C6FB00539F3839A8D0B29906F9923B9244132282E38242257C339A0D0BA8F05F75D41ADA51E29E33BF65F78981F04F397BD5F9580376A8D1C552363D6BE90EC83C2AF748CBB7783D6B26098C641777A260F5F60A712C7A7D1CE681CA1FF969B8F25B90F9A2B03F71E06A848DF3C5C8571C5626D5A1F123DD14A9F90B3958A7EFB3FD522C7E83F897CBA80B95099F1705E1CB22C7E91DB644880F7DAB480B29FC0F8E1D0ADBAA123F1E1FE36835ABEC924531065354B77DC1082DD690B316A7BF104140F6316C46E81E777F56EECE625EA030C1FFBA3A4D40745E77129230A69D76C226A80A8CD31720B08D9207F22F8F3068C169B41E7136F94B73047377A8AC0987490E4DA2B7619A760E3B61369BF762FA9A3ADCB014CFD0644AB1FE6D8D3EFBFEC893E98289DA93AE19D8DE41AB33FD717200B6949AD21B3290C77D5B1FA44EEC7D0C6A9978D50B40DF77823FF2613BC80D0E11DC2B790B332D5267851B6315AC08D0A2D6FC0A8F93DCD20DA6054894F84C88CE254057CD2FE36693F868D812DD1D978897597840CB336223F8A8EEA9C15AC05D3E40333391680C4F4CD5C2F600CAA684BF09EFC8A9B71E6883E9353C22B379BB6ED8ED83A2468287121207D9ABF61D2DD5116D3B163F262BD3D57A23EF2E6154BF6EEC1DF88B961C4505F7CFD2E23E0E0D245A9418292A5AE6E60F3852D78D19E1EACBE9F42A522FA57554308A1D01E31DDCFB7C38534F7B48E0384AAB4B81A93681ECE4C55BEB089092E757A4633B2F30BA83E470B3ABDEDF9135DF22E2B29CCD0893C54C329DA1B16C2FE4221F1C7EBF6B3D6DE84EA1DA57392762FD9C64C0771966B0E1FA9A6E286C23128DF317F704237B97A339A623C985BFD6A0C60DE48EBDD73A0610A22B02D0978E626B50171FC8390B80F37E5E536CC184259D4ECFFA958DEE1A27CF3D2EFC9B218809909B19D573EF86087A1C9BE161C54DD1279E022F98030669FC93A7BF03FB101A3FB5321F654D2B40EF8298844806BB66EC32F7AB3BC7BED2AA7F22AF20759B12A0E3F82D3C3A141F393DE746D5A0D91F32D8249F0DB0FE37D27E49795C648EC6D96E352115FE4F10D1F56C39FF9140E3E87F13AF3C6480D6150E1B7B4AE614A577D6E81694C19E468761039E970335FDE9945F6119F6ADC184C9F2A434C681D593F34D258F2A8847E02DA5EA2605A007B25031DCCBA8A8C50C77411D197E742D4B3994471AE84E2B612B09B2BBAA38C5E71C22A8E3DD1F284A681DDD45E962F9D061846EDB9713D4F925A9DAC0E32D2A4496F68C68448EDFA87FDE3ECD47411AF5DA95D8C48D5CED988AFD72BCB7A81896EB1496F468D4664A58EC3874BC6FF6A85692790BB405592DFAF53CBAC93884A842EB2D3DE9619843919CD9D68AD89DC7A84BE54C406B8208428066011807D722C2B34D4A279EE43BDEB967360D9BAE50F654B2A06B576B803544DCDDAD670CF8D2D7723929842C6AFC4093BBFBB75D1F5E03682500AA0A34FC66CE4409D08C726552ED5ABB0C646E89B35A659C67F6F398D6BE39D9725BB0322D458DE2A62E46B62013F2BAE5E60C3D41975C6A4C6231F4B0EA2827329279459840911891B0111FB4B1FE99FBB482FED56C7BFBA15882CE5E2FA2C73E0B682EADEE6F68E4E1A9CD92FDC2CF30902453A16622AAB1273407B985FA4B7DB40D87812F2A10183464F8173D22D5603C44586B107B4B82E94DD80E87AD49E9C0FAB5C3330B74E89F742CA1A5940F0F329F56DFD40C6869D0BA8CA412AF9C5116ADBB3C22080F93142C7778D52C4D75F1EABE13FE50877C26D7DB429E991506ECF1DDF30A00F9E0B355306B889F41BBFD1B4D27B67952E4A0B53D1BF8B2E84497F00826D84A913F02649D5145383163F3C3F586EDAD06F518B64D9B300C4540A67593B9F3358FF2A22AC4BD7E7B9AEE507D184E039ECA3BBA0B5C584D3359D7121BCCE01691E11C120925A7D8B100751E8ADE99D3676C7355BA4BE451920BC7D2AD6E8EF0A9693F16FBB570122FE5F5FFBDFA490B3C84809ACD898FC0F807C77937C7CEB6F03308D3E9C657F80730EF3A1CEC6959850FAA6C158F23B23D28ED53BD77531F1012DC1753CE1AD6E0A629E14BCCE9D56B74E09AD6EEC9DC4A5C92049D48AE21222AF706B1C4DE65AA814AEF5B7E1EDF2D8A9C5B98853A17199DDC3233C5583B95756F5A9C175FF7D0891010F5D36A268ED5C9F58433A69185931E11BCBEEECAA240C2C5A4ADB4E770109F3F16CFAA37AF98E1228FFA7C584B13F850FED0187FB836E0A01B19CF700849EFF09BE1A57DE41CE1D52EA6F182E0DDDF741DBD2150113B10CC3D9E44917E0FD9717D6D361A88060E202039AAD8F31E4E6FBB4D7FD1BB5D6DC20C3D83F23D120EC98FF4912F3D9AB18D8EECBD7EFD1CF9B19081B38CD959660E8C63A539939D0CEDA897F5ECDFDEE16ECA492B216BEA35A167178F4A0FB76175D160FE2EF97BD6BA0E296922CE60D91FCBB3343ADF477F8A92AEB56A471B0711CAC45DA8EEBD21FE83FA68EB74C8502C81C65506C92C4A3F19ECDC2B7A5AB47704DDFB2E8D5AE620CA0D67197699677EDA3FC4FB821BFFB5F2DB03D4DDEC0BEB13EF84EC372A5C56C1E712C8D23D1A2DB1BA077645C85689CA2258E9B1B807DCC6394680B72938E1B61AC3E8A5B9E84BB4B58CE5C8C2246A604C05701C026185CFB872BA78CEE33EAFD0486A22C6D5CF9264EC134DD79548F3CF5FAA67D8B1FE74F6AF7B897AB0A0D8CABD5E1B2829CFE66D58CE00E68C6F23FC35397FBBF96D2E63825C96BC3CEB22FCF9CA46C93538F8DF566145D06207533627B665E39DD284F4275051229F3CCE9E9E62EDDFA55BB2AB1D1D8E8E6145B3E38F35F90B89C15FE799EC14F7E415FCE4EFA72615EAD26C10C1FFA4FDBA2EE04C4845489C21BE45C478D8B2116C84AAC21B48BD4181FC28C7C21AC9CF95D8B04C0D817C8ED8083D9CF8B81213AA2E3B8BBF4AD66A7AFDCDC4C420945F5B3E8C8AEC5C4F98005A0CE1B3283F5FC0FCF8567A150E12639CA85D298CE8E4F9E0C53817D3009284A5A0BD5D3A07234AF751AD059E301076946DECFED43DB1176A2BBA4B8A571299FDE4AA3574B6C189A721674E004F259B00B26EF5AA90794FD622040B80CA6C5E9FBD44B3DB21290353878F4D8D87496E374B05E6A5B25742A885569DBA2501367EF4C549BD5CE6169914A7F1D311D52CCFBE2091F0DB436506F210C137C2180B89626F52B4192C67ED06C1F9175E44B9468E6FC2208A98DE577962D9B4C31D5B0DCF4017DB1BBB2F80512C89B9AADE69DBD584452D25CAC97A4A7E6F48BCB909907B93F5B8108EDAD38CF7FB541328C5E8AB867DDCADD6A1B5083869E68EBC785C80ACD260C715624360F2F3D78FC1B2A464FE0525059A3D5E04BCCD72D23BC680CF7B25C5CD2AD6A0BB8366DB24B671D5BB3C12554D37C7A662AF9B9DB61DC6C7DE288DF1976DE08743426CDD30AFFDA05A8390A8F3A4A94D7CCD33BDB229E32850A77B2256CC595BE515F9E6854463966D4DB7A946276F594AD4BDF0B9C59D4D38E211A4465AEE023CE6C062FDF4123ACDED834F672C1A724BC17D44DE9632A588E7EAA77F3183E09D2ED55099BB1AC8198C96EC7B1635139980D5CA4B8B3102375A2E08BC3BC754D9FE659C3FA403218BC8C00FA87A0FA6F096E336865DDF02BB05049CDC9680E99C4F567ACD25AA7CC76C182A8DFC174BF6FAAF4D2553A4207922C1EA10CA8DA3E35DFBBFB5F6919FD4088A3A8E48358CEF25576A3A6447980F1C716EB58E755196A672C378F6615E54E9A16CEBA33CEA918768961C244A561164B61754F679856575DDCB32C70447BB738E84CA590CB523C6553F13EAC77461A58A7D4E1CC1E36E7BC5E85860B0E6B67C70D398AC0BABE1F42426D9E7F12B5E362BF3BDBAC42C572730C5F4EEA957FD3F17050625BA9D9938380249290AAF31BAC"""), - TestUtils.hexDecode(""" -d90e5ad6ce804eb56c37cc30b96369f19a67ee324697634f7a40b3d150ba7891f9d8e5a7499781b5ef8f462ce1626eba1213bdf47ea40203aa7b9f6632a02c172826d96683de98ef1fbd163f817d6b4c71ed7fc9ec3a2db3d0bc692f94812d69ddfa81c15292b507d7aa3642b100472acdd9db20f19b60d98e10f1f47fd8f1498cc618a00b8c23ddf109957b78ebb9f5a7d6167fa907f52e312fb333b224c2e1b9b45ffe6027a90efea98d854ab6c6de67a5f24ee28d917caf0014774770989a4816f39fef30dc70b7e068bb306ab404611620b9dcfd40e1cc72400e398cfa342a616fbd5eb075d340d9f1d095b54d01d190b055f21d4de73ccebaec652f982535919e8ec7df3ce42f6e0807252f88d4fae025c68e5dfcd9ac0af5af610608011c630beab1b1bc760c550e79696333b34eab93fa7afc68e900686d1828bfe2bdb57332a9dcb84c66f12638a1ca4ab413efb847078b79610c51ae1cd81fac71319f8e43d356baba173c9775f9dd2569c3699a2cd2e9accc5ff725bc951b6c007e7d7b16b5f3efbde405d7d945dd1fb38724c52958427cc14d7a1f913c2c911fbc50e61a1aea400383561c78d32a38677ee62b201067c6744500f27135fd789e6adbafcd841a2796bedebe47059a8917f5eddc09eedf7aa6187f7f9e91e3893a3870b307a47da4366f767045390e1df69909d50e57ce6b2656a9f9eea5222cb8a05142c09ce230dc49edd7c4107241a4f317577c135a656071335408b809a18588f7dba155bff5acab476e99e62b0249e362d75ac201772552865f91eda373f722d19eb4e4f66c94627667af033c4d4f8e6eacdbb2a6abf47c931527c66da42f8ac3bc1a9c38e88a9d862beb1785ef9e1edcc3aac6477fcb78bea88b5a7796bc6e3e33ff1e0ca1fa73e66307e409365ccc8cf5a0cdba2bc96a7150d030b1349b15469ba21c7d53c641402776d61fca08d0a6268b43c063f51f110b8708251030cf393eed4898e2fc4f9654c05e700ca3e9d9b68274556f88c61c35860579ccbbfbf3dc367a88b076a4618772cac1c225069ed77168bc9e50737d2502d6b102a8904cb3118489e39c31507203175b35a295980cce3f9653330307583e3cbe2ec1d6e5578db4e5fed4bceb20922036891dd58b00e0e98a408f2212c5cebc7faaee235162bcfe6e482d4d1ca012078aa78bc9001a021c14e2ce86e484ad41ddae6c256f05cbbd64d99d20ca4fd0fa65d3565bd749689ded6c835d1370b047dbf1da76cb99f43ce660654725a40f7e8dc99716bd12bc3b3cc140eac2d230ee9177c8766e3cdd8d83948c98ac97b28826918a8835b5b563e887fa2ae18fd47d2c56e7a213d92533f05bb608baa68518ffcbb15e6847a776029809450ff9c0d4fa422fee078fefb04e860f5edc713412436e836f873bca3515842f70841f400db22e21c7a9c1ae25727a39e7e00e29abf256cfd8817115303a40c61577ce6e914b8c6e9481165f554be7a58c22c6a66266222ec80f1af4c6455301cbd80f5cb42d69f524d9a121699eca6d78bfc4db7bebdd8d03f83a638882aba3967f377be4f54295205b8f284a341796b4a00ce517e41ad2ac1d1dec2189a702b957a4d5d67fa1625341266585a220f0c276e339c29f58b13227021b6631cc37701899f0d7a761e13220ac0c39b5f98c688571915c38f8d0a23811d11cea0ff0e319e2bb06ff31990e00aa254e671f350bb9be4a5c78a992ea5de9276b0c542e2544d6a9a2e0339805ab40a9066352e2cf864a102406c4a11268b0ea22d029bdf694cd2ae75d9184920a9a707ab649a8f422ce4a85fd30aadcc07d3dde5b3b753668a303267aa1e43c81617b6aff5c7cdfcdb66eae646146903cf84a014c696473d0c52e19fc5da06bafc475ebbc367cd775676175b4268b42132f2959349a39e73ed553fbb50c8b213e4ae9d8682b837a3d8d938d4a4cfa72b564a39f5137afaaa442b562ff09bbb5c2faa2197f227979a9cf580dcbf01a07da6239f709fa91185e1a0d0847d77a50a4825fc0c2a6dc7140de2d4789b1fb4587c2e9b24f33d11728071548ea967622a1b97af44b51b2300c2c87d1f05b8d0e710a2ea5e123e479717cda447c0d4cc2ccfe753e6da45c38f568a8c2a82418420fa5de3fe08e196f2e2c6691b7774f4d4351c37e974721d4c505a6ba037969034627d05014a543e96956cc991e583abc9125aac8324f46e71345811f7ed8553bab0d166cd8bfe2fc21aa96c1ac168b40c61aaa7ff5461cd2c1339e8ac3c54cb1a8abf0ca4e7edd9e9842a01a91eeb6f3702be5e81936d53f11ae7d191cc6b8afbbf1f78dec898a0c30df889f43a8cfa8ce1d2a324c15b501a0ace8076b26334fcf03bb3db377d285a812f3ad76c0ecd7aa3b76f9072e40b272d514fad2d661d168b00c2b27ed394d4cffbbe38ffd1e7b84bfac69b4fca99b8f316471fd37678e4501f16ae1b2acb472c065aad5b482cc893fba258f29a90e1faa8f4c5235f136b25d1e451f20784e6b761dbe4fa68a41285baa9634f7d87807c407a9e7be6e483f3f224367caeba42f0df19b5dce47630396ec6ac6ff1b5c23e02f599cad3ef117ff74d7331facf763c39ea70c2071087774ef8a2ff268f27d06b96e50bd52eb5ab55a9f5530339abe6f07d5a27f64aa8015b5d2a768452f8ca82484113420464d06d7c61ec25c89a422b788f3bae8e79c0020fc93122f53356a9e678087f80b1938e42fbee9efab604f959b7f4d8c52d900d71b24c39a1cac0831c22907ab3348ad20bd6818023a72266983678edad084a13ee07196fddeb52c79bfb925e3ef4bae2ac564b04956c0097800546e965687584c2738a2009b0caa15183ba1b6966488fdcca6937bffdd9cd6f51424a83cb6324d2c845dbcc9237bde7126516ea59d36cf2b63ce239db57c01bce472886eff29ca612510ca318398aae4618b8d6fd9f6c6e8cceb4b3dbe5d059038b9a6b81e07f3599cb1febf3b0dae4eb9d5e3b6a3e11b24aef1377cd941f94a56f7c7f1fd85807d9d97ea0aace9d94516dd7ee271880f4a7bd18b4266c510e16f95aead24a9d3202ef331028b0f4233023aef2d18aefcb5dc66eea08013463c008b86faf617fcb6929a2bb78ee0459788792c9e3b5d3cf92371f4555c0955bc746264cf6f56edcd8bc8d044c170610fe76edf0e875f9d6d12eceeafd955e0130805963455a348ce41788cea9e2601decc02006907f5e092fa70d2f0f21945a5f24edc734da33efef7efeb22c8b142d86a47d9d5c13f93258eaa396e3ce55b8f6ce736a5010a347b7f9298babcc6d7e4fb03192d4e57daeaf7fd03041d262d47676d8b8c93b0b6b7bfe4e9f9fc0a161e3368a1c7cce7f200000000000000000000000000000000000000000000000000000000000d162933""") - ), - - new SigGenTestCase( - TestUtils.hexDecode(""" -c298f170b4286195747d986e0de1fbb602feb53b5f242a12bfa2b7602b22358a8a23b61c155fe3630218b5ef74b2273071172cee1ff382fb09b779728674dba788475bd8daffacda50631973d3a038d986fa56e33293538d828f48d4292fae5487dff146e3e3ff99d2ceefe847f17e0274f2e9edc0c3b7a6b184d2c7d771510259180c02294d08c021e1128c01b9004906315b180d1929411895259b3285082964e310414c920c4b9611c380101aa86d1cb12c611286a498699a385019018de13882d0b8401c340a824689a21640612886022028d3166d1c328a18b06de0383164b46588487243069202900858226e181428da4640e2c4694118859a044e0301041bb4411235011195415a962499380e04c72110458523824101a929519029082064932669a2102160360e0c860112312c44a28c0b2272e3280ac3962cd1844514482a4cc26d04a1110c834c8a026d43b83113890113c60d49461014408a129725d8369020b325138728a4a44904814d1a324edab810248590c8406423c22849c265d1068de3865104a2805198298a126964084604b07043346519c1916204080a27608a144e1b2270120731c4a808a0968ce3884d2210682231481ac49180a80c582031c2120adbb4441b82641a94080aa5659b46711b15445bb81113a360203660443608a02432d922318c22054138605312220aa700ca441290946d5c405223264588b80864c4251144240b051244200a09c4101b938993261118c08d9008241b364660022c18060e5018864b40051888418c806800152610c30c91162dd1360e0b491014c18da44212a4844d22193164a04503b70c212690032661922862201106434471da324890389258b260d32028d096240c074610a36413c24494888c0b328a4b320a9ca691dc284240220d23b671e3121200a16004938c5c3288c1469121870511912d8a285114354012b86c4200460a350489a49164048d001405cc266143a82d2048061a184d0c056ac2a06d9914710c26251b33218b144ec932685a9221134541042770c2227213b909db0001010485008000c33640d2882924355122982da1322e1a280021246cd8a451903464d8144263260d9a080ad220111031258914890a1951cc043209028d11392151b428dc3628a406119ba6009194110c912913206e5030850b10121428419a04450b1871082581c22601183090dcc661d04089e2400a23044190a64401116093166090360e14859108368403414d7fe04cc3486ee59a1d7e5ceeac111381d6bf881ab59d8eba528410c1f10133a1aac55b4e0c69407bca0aa1efa29ed38ae018ac2f892be5d6f4d6099421cbe1328b07913fb0eff2be86b6785500416f14777de98d5129d4bbdc1e7d0c2dd161c3b53568ec0710fb80ff1407927b82261dbc6a301a5ab780b88d080d7e8a75e5253fa666e6499718ed9135d2658235755a107f617dbadd6ebeb40906bf2c29dfedf24ca3667029f642770fe012ace1dd503c33e0e033fb90e0e8598870a92cf3b467d667f6747570da2c86a328b1b4c769f4bd99a90a46000018a6a8126b61b51f9b77d66d91704c5431a2c5e4a7b680f053e7e1f5505d74af6a79ec08e7de4d45fed1888c790e2473e716c7b1cbd1fe9944fb56fa502b5685e75bf23ae5ffcc4d5a525b91575fe8baa856a445d7005a2cc81d0442e4edc3fc19e4f5bebabe21a6c1f2520c38d1827874261b5e802514b5df1816510f894eb6d5c493c82ee8f3d2e7b159da2022586525548037e078ee6a1ab31803b0595f0ebf07870051aeb5582702d9755b98cd30ad128e455c15a05f48ef20448f395af79a5127c4a9c4b04c29764ebaa3116b9fd10bb6138750eaf6a300d7f3294522fc92e2e95644d2fc35222a08a51e49a53ca180cdfceeebd5f6cf0625862770b338246533d35d31c78395206145f88cf17e80c13ae5b9f3aacac15d526e9561e5608dedf8d2163b9b283bad1a58d08b14a201bb0fd91fb659296bf847ab47a85cc58f5a8e9c9a5c132cabe71fe3bfbd899a60fb98b84d962607689c1295470c23df93f60ba2162dee0893230ca5bcb4dfb2ee08ababf98992e27ff92d5569cdbd77dbaa44dd2fd21e8b398525a5ea3f2632a581e7d94675a2b51148afc18413c9e39b489a6155f089cd1ea205e9b650be0f1d3befd1d8189fe94793965cbc0b118913a1b5e4de66d969317c2fe4f4c289070c663db3684b54d8b5c29d84cf1ca9b77794ed6171c945e42e808ec0709d2d284e5e022495c7bb67f215c023f97a0f248ddb6061c7f68cb0c6f688f785cfd352021ad700d410968f389a17261bd1cedf8be5b623fab823d5a27e67e68894d533742375ecd6d41f124a39fe2e3e548f3c041b61179ae7961c248a05e7ae1b3023890203c95b73e70c65413a8f2d97272dddee2445220cb6f1f69e5d47f9f8e6f2feb116d688f7ffb9afae3a6a7b7335fdcdf6c1b2f28ce98e1ee76ed2b0303f242cdbca4091abaa25275e98faca3b16d3293f165d5e653faf20d6afa94ca6f899008e31aeac9ded97911c1fbbc3de8ac9e16b20bc91a13706b427aab96699f46e5815add64be24cb3484e20fcc9b113c8da4be3b0f39dd183a483f8f6f233a3b7d41008ea66c1b0fdd111847e0abdb4dc1a73c22500b39035d78048b2a7b1b537f4009656cf7a2744737bc7066f99d7b23d0d109a2e9e679742edd3d89ef423c5c57bd2947fef985898dc986cbe3ce2e9d57dca7d4fd7d5095728822d687f22a3d7d291856451a5aaff706b4a7f68f36a753da02562133be2e3a30e0f5ea8fe18b2602ce263c6065aaf15719d8d45166216d37bbb46915da50aab9a0f7900784e7547a0c90658d5af3d8f4c88e5790eabfe578976c8157fa0fb6db133394c7f16e79b6854900fdd9b6ad0b35a877e336abb0c484c8c258d165c83fb72595978f7b2c01b05a34826202cb73d88f5e8cc879e9994be5b3eb47b336287d7c3c036e5666afa557c834ef222a0e8768827c6d56d315a61630106a4ffa250e3bfe1de6a6cfc311d3f3e48165d8fea2afcb14247c2da102e88d726f4865bd848d87c01dd6fed84e0623d564bfbe8bb90963d6bdacf36df337f00afa83b1eeb5309cd6335e4156d307a28ae3dc791210b482e9a0504895dcede6dc951c3c7ec8098de79a51741eadef5fc2800ee410bcdc2999ef9e38e33dc3bf0107af5d32236f26c31d1ddf62b6ab6628a5bc4136d9bcf62ab95ddacabd6dbd3afddf7556e83931035a6e737915f1f8dcc217e247402745af979538c28f91de1375056f0e369c648482877518ccc1c976e21abb3c8ff30853d5967655a0f7d4ab3fa1de5736d80024b34f940aa744bb427a2350e72e2abad49cb6a91a066efabd87d286da00d9c731d8348d4b094e089da1938c74185df1390646ce73c0687e63a417c0681cc4438ea446fe36496fdf5a808a8354237f4838b51182dd9f062ab6143985524f01ed273db2dfde919865c1a5d82c67c1feee76609fa9634e0056b7803dad0015a27445028e5e87e439f820042888b489b0de499cc3ba6d5aba0260a0cf24f718b013b72918909283fdd28025c011d0abe811e6f484d58b27dccf5b5fe"""), - TestUtils.hexDecode(""" -0C39B65F4C2094AC626652CD33CFE44EDB2667CF722443514CAB443DC398A8EA009277BE397E1C1E7ADCD1B24376AF0F19EA50E56C90D683F8EFDE693F0F8834199544E2DEFE392B0BD46048A83C412A14834C4BCDC180457456BC72AA28F2DB247AEE84A1C49266361DA7EDD54BD9B562889131EAADAE071AE5A671646F49B2C1359382F1A3B2A6B437F87CC99A2A1BC821E1F3DBB311B8FCDF28546A479E2F9970870066A2D6447B6CE4FB65ABE7423910B9039EE3234836F924C8E82E1299335E27B0DD642B812480D6FEFC47B121A710827DE1D18DC12064649224FBC4526AE14317CC8E53BC8E9BD42BA444AD9B8B48C3AC807D7A7675F43E3021BA1DF9AC7A42A9E23D696BBD03FB5C4702B55F95854C41F470CDAD8A255436F910C089F71C2E59A44221D78AB81D4E2B059CC92A3841E1431415DAD4E6EB0315F423DA512661E4CCE098D6678F560A4BA19475296A2A1DEB12AF5900FA3A3C188867E0C268EFBF7AC53455552DF4F36E16D50E23048C7DD4E64341E6DCAA0036EE045B82C42121B0B779B5E7FF032F549536ABFB702B1CE4EAA5E389A077F47B1B55595D4888A4C1D17F4E21706779C9CDE25DD1261C8B4761A40B69E2F22F069A264E79CDFD36F307D117FC737D88F50EC67CD07D8FA269CF265A7E7CAC93E97BC29EF95C88904AB2DB61C8865A6EBB23871576DBABC83920AA015D47E8CE699A9E57E139AB7D233C577B46C9C314D084A1674A152D87D2A3D8A5D9ABCDA22E212B8C9A2BF25D8AD22AA3627E6C12C684AD2BE917F094263982D396364F4DE0BAFAB2DB89997DAF8B7E3AA953C055776FDC29F8AE5C28D4071534A9A2E9090CD3F723D3E381A2ADA6D9463FC49B3C6D2B76803F5C21D8DDCE965D2C472389D2BEFF448F2D81EDEF1C851A863AF66B64417BCC2CBBC70C18875055D171BE32C06081362FFF7DE8F8A23B076839602E2368CEEB79E4EA53F42F440D167A902A23ED53E6691AD3332DF5B0160EBC3B5C9567CF619BE2201447EA500332ABDEA9B849C3A395F596F2C96ACD9AF8313E453277B9F4234874E791E9DCFF0C9D9DFA8FA9474C026DD34E5CF3AA10CAB1FD23EA5DA0D0A66E520096C6116944F2E5747A974BF55428A3D2475F6276490AADA25220F2F2111892DB9E9C75A5401BADBF69F31B77535044DC50B1E93849F19C0B6C5184F1B14F68960F9F469805F3843198AC68E51619F3D712A34279AEA27BE4357A99C44C456BD2D9319147285680922B98DBC4D6D2860515D1371D2141C7A1E76EEF8586AFC973713EB89C1F09A84AC064BB7644625224FF1F7316B9DD1091CEB151D1A040F7E60F202728F7862589E7F1FA32D39653383F90C67D96D9949967AF234592903CBB968E0D979B92B5C69D09EF4E767741F1F6E361DCFC8D751CB8C3BAAC4CC393D63F71AA1488491CA06CC20B0BF54C5C225B6F0825677C2C40A395E1B7322288A815E59AD2999D61FE09C95828CE18B2997AEDCED56CA8BCDA4343B1E948256AC5EBDA23A8E6D7102A4474CE23567084547F2ADD9DE77483398D81A9A9C7A573D7EDAF99536D31C3588BB649EFE1495CEDED788EBBFD5775842D91DAAA2F9BE08D63B06DB35E72CD0EE5DBF45DF9B0CA682BD944A733D6875A62F8C53A3FA9337F13429FACB288C73220C29285B2D87DF2CB1A54631AF3D0035C1F3B26A5EDD07760A63576A395827F3D5F9B03D9E47A9E1E6A271021942648B8424234080492BBC56C692C769B5DF32A75F7403C88469E54432A37A895E3CAD3AB110089ACF534A0D78C2083CFE149A2D0A5055EF9F4C943CBE1FD393292518CECFC57E4FFC4D07A563A30528A6A3540636A3BE770B7CF03F5004D7C6F8ADA08DEAAED0422AC0C0C8D7515C9F8BF44195D6DC30D9B3036DA007A910BD05DF06B032812CE8393AE2777D717A691D07E860C1EDA60F6DE31F0787097D0D483E3A51CA7997646503738CDBAEBCC21AE4B984B668FB4020C139D9F581EBACB7BE263A33955DD68C9ED9BD2DD6C0A7BD049972B624CB7E787DE7184023F33EC0A1539C4679D6B4677FB971D763BE17D989FDF8C0AC4E0B5A6CB40A49B5464610A110EBEE9A21BB0D6A2F043015EB2C8820DD966A13EFD18D32367834D41E8673E997B2803638A710580CA08DDB4D90E4E8EE584BCA2FB853A122274142130A1ABCDF7DA6C0056689195099CC3382AF6987BA47EE294353674E7295ACC1C070F1D8E4107AA7189F20CC818F1D86F6D646CEE911B304E2FECD5A14CF5F36331AA86E10C319C96E52996D4CC12810AD7C1DD1DBDFDC78DF029BFDE9E8F9B1FC7D9DA99FBB0304A8129EC58A82177EECB7330E715BB3C0B4482923C7B1EC0D1823FF643014C7D08A8F2D9F9090B0F83663AFC5E601E5FBE1DDBE678B9D93C5A23F564B8A4DD29C8D19106747959E72AFA4B16B879E3C6E7F79A212A144F9AAF665253F1360ACF7DF37642270656583E06FAC85389A3AD76E69BC2735B1C3E13B80CCBD298EE25C29F9F5C275AAD83BA0E7C47526253BB3125EBDF5CCD6E1C4F9D9CD4891167BB4E4D2AA644D5D362C6F790E2776BDBAF8D96DC3A543C72ED46E431FABD737B4BF0F4B32E12E0520E60401CCEBBB40180985948045C58B0017C3D8797E433A2E2C64B9679EC7409D59B3992053EEF2ACD7B152E5F564196876EA0A31CB6ED47F2455BBEE6827D96C6B99E46F3DF1FA21F593E842B26E83D843118F6833BC273E12C7224E00E840B0041544893C6C8A06523DEDE2ACE7365693BCC6A8D7DD81B01310CBB8084C5FD3868539F8B5179519CA6745B56C4A5EEE8F2A8A60CBC7453E1E0990D176446D97F34A2D0BD5C5712E2D82601D0B9FC9A3F2420C65E4532DB3810FBE3635B2AC3A84415535FE41208B907EB3E97AD63DDC4FD694127EF1E948801B5CF651119CE17BEAE3396C098A86548B67DDABADCEEDF60F57D2941815778AC14F78C78516F84C5F9749B433DB97A9283A94697419CF94248B6819D9310324977D47A133AE9F1FC141B56D6302817761BBD52B4A1EF808E0AC761426C99E0504ACB6B552F9550D55DE787C12A0409A9F9EE3674617D15E229AAA98BBF4FE49CDC81DA3AD110645132B332B6D2AA38B35320925135BDD225053D6594E78389909E596C63B85DCA8B3F6C3233A31A1F8F3E900E49DF83F649E592979C9CA4BE65E7D6D1F23A7744626972D52B07B7B89CD90238A5E871666F4CA6DAFCBF34FE15983AEA5BB7F9917736F7BA46F342F0C08F56D19AB9569FD23288EBCBEE7B5924B8C86EF77748F3AA9CF2FB884398F83772C9771958B6DD063162A3AAA42E6A3280FEDEEB7A628A07702950975CD135D6338FF959ADDA2296B3E85A024F63D4ED8A5859786E2BC76C2325F37B4D91EE8B64F30E781BF48ADA774C1641CFAD2D63A59E294B5D99C94108154E38B499E3CA2A29AF7CC77A8BB3A3B712376CD081715EA715305C18B51470D5F3A6A82E9189848311511E8B0ABACF856312AE3916FBBCF6664523684D3C7ACE08D2345A3907C9C07183CB3E68C5EC3899A95430E278A72701E2355A4AF606DD8F8750F7F3682FB84290B2BE23BED99CA06D5E54190A5558C927C369C00C512342EFFC41618CA6F8FE6E3A38D1714FC44BF5679C1A49CD8BC8B28499602E277DC8832F738225920709799DE6961E0B4EC12397E7891AA772627F66F494AF719C55D056DCBF10E8E3DDF1B6C1BB2F0B2FA61949D1CA7D4E1F60EF836B086FF8C03A5916A14EB2670AF56264D7390761E6EB6F638D6FACF56B72A48F271ADE4541C8EFC91D15F69E0AA6B97EC0E9C0C3EF169E4A4DB1C1AF04762B98ECBD0DC374224D98FDF7788435BC154E1FB06C970A914C34DE52678F61ECC1969A2C5B1FF4D82E2C80CB543B4B7C9DB541229CC50CC6C448DC029CA24ECE635233C401D3715671BC75785DCFD929377AF5B65EC43EF45A9B00CC766695A4A5DE9A2E6582F7936B9FE7DBBA6762C41453683146F4ACFD809847F866DDF559972FE0C093EE7C9FAB3CAB0BC2BF8DA19466A96BBF2DD4859E2D1CE122A3CF16AAAA9A4708F72BBEBE285E1B794B2B9C7A699B36F39F033277E8B7BEAC3BC70A572556EE5C070A309D9D0BC35F4B6E55ECC91CE9AD273B0098F64E1327C85CCAEBBE67E8A118669653495D2FA09C29C6FCDF870905B2C8BE0DF806C29D5E7AFACDAC5F89116A3474D2229C76E649F99EB9EC71A2C229764A477853D68C39B8F0BF4378993AE2B26E814A337CFC103760CE92FB564E3A3E4546996CC4D8B6BE069E99861DA9C731B543BFDC006FBDE3B33D2C8C4A3F5789466122616C98F52E5E4BA239E0C3758C5BDD3BAED8809F67A70504BA061409A9D87A499236230EF0F1985DA0D765E9B7F733A154E8300490F458847A89E7C6BBEB7A9ECA7B6CBFFC3124DEDC1093C02C808DA1CDCFF5237745C5FFF51F3F15CF746D3397916A45990070490CA74A55F34EA4BA9EB73A281F123035C005BF6C7B30852665860ED13A2B5808F81435A77A8504B58CBA45559BD3BAA663A571F108685E414FC4DBF8033075E30CD6FCD9B893DA32F7C8D5D971D5EB417F1201B00F65DEF4EEED3B55B7FC7E6194B72A861439B865558157E65D4C2F8A1A93F48192099B375D111370F830B34EAF3225A16006D4749494B9AB9D3B05015E34866A4A2D94B9588A8DE8AD4CF90F2CF422634E8DBFA0FE3FAF27C3F3C2EAF9C1BDF23FDF43D196732E1FA6D2B343BB7D9F5F26FFC31B26C64A8EFE2B2D86AA34BB618FB58CCB54486211A8E66648CEAE52F07A6C1EB5234DA7CCAA971AF984D6050D1A81F10E6D19CC44B5E668CE92F4251924B25DAF41D5E381C3FAE4208D18F710B5F93CF3C776A3D81C608B06CE6BC68FB8A8117CE7BA065675B88510F2E8A440EC363A5983DDC1352E446A482C593A490AD6093258E447EF52BFD189ACD11C87A8B75F08B5D166C1DA69602EAA5916474131E20F704DF84C3FEF2AE99F9B9E8F7315A143A07C7AEDE5797F503086DF7DA971244A61909C4AFB00842FBF4C3A59B991B58AD6C0B8667C449F0D97F34CC41FE935D9F55821299F780359E2F631858617437D4AFE67DE4A1AA382B93CC3FF596726F0D1C071FD0E00883E9E03811FC659495AF2A62B45DA079A66552F2928B6A25C6416F8DECF723623764441E5E581F9B2E36479A1B6CB3DE9B090E3343277CD7F84E80219793CAED4945DF782C4B72B498A62A1F5362745662F711A7E47CB816EC7069D10CA8314845AB0C9FC326C5BCA0E2AFFB4E6948522F8CD9C8DC008855E592AEF1F8239748916878ABC493E33CCFFDB86CC2ADB99B6251F493F0D2A0BE56D133B66395AA695F6298F7F4BAB41420CA9B8CCEDF2719590287928CF6BB3A506D6678B814076B7A774BE9B7029DF9F4719AAC1D012BBD49EBCA6AF124D0AB5C5FFA92B4A895CB76B88DEA9C7105136D78B76D92079A5B001B214DDF7E140861D86ACC260B72ABEF2CB3A75C2BC87B39A9D9052D4283B71C10AE275474E82A5FEA1654EC3ECD468DE4A015CEB67BAE3275C2C79863E2883D46FAE351F0908F42825DC7D9FAE0FC7171791FCAB10E16F3F027E5043AACBDB1F05FCD2B3EC7F6F46AD6DCCD6F9E6A6AC702451194788D14261219F794EA195F2B3778654BB373C68AB4333E224D161A1F89FE440BD8E968B518EEA28E81B89E04FF1A85B879E4B54650FA8DD1322D14B4A87"""), - TestUtils.hexDecode(""" -c2112c791ee26987cafdde1bc02fbb99d5b97ad71d4c75cc36cda559ba853a351b3088a5727856774fb3a100640034901b886b9aad882c879f7f7a50090b1b4372ef71a124563aaa22ed2b227f76c4c5ad691499766556691ac72d3ed717eb83c06951bc8ba4c8829b225aca7eddd999e9e6e9cfca939ba21d2f7f79c750f43719c520b344252a283cc677fcf1dc27a4dfb396541c97d7e948ab873640d1a1a0d941d2677878360eb2b703f727a00cff03547f5516d5e18b07d904e3d978a905c83b45a2a58f407a5778d6e6da955705f0e55931fb31a1b1be5196b6e80574b8e37022d4e7778bce58a817aeee7ce13c07196dfd6c00a6604e40f3d12a46c11bc6295788be5bcb2a39db2bd64780b966530496a23f9e60ab9c7a4a48a5cfc3b1f657e00aeb99eaf8ae38e723cd14191f927ebd7944da428584b23da5ada543d3c071cfe95910aecd65f7be88aa6c7bfb6e52ec3c925fcb0fa4b09d7612a8b19a4156f44d07c77eb229edc08d78b52ddb7bb3e42e95faa1b013d4861ce5166fbd0d0822baef9bb5d1f41956be5cd1efef4bd3f92beb656957c0ba51dfd4d186e4804b71e91bca6f3341ca585f0c48c3cd496a1f1736f513650fcae2379bd1d127641f1a92c0c394d2c02301d29116b3245ccfcb6ae3b55b29503a49fe6357d3f027a20c30528abe22623c53c73970090b12d994f1a69d5a9877ef15f3475cd1b9d58cc38a0289e12a09ff756c7e93bd675b2354d78ec79492051751db9b3f35a58eac539d4c6efb259de9383d5eea913c98a6daa6173b113f8d7bac440e1bc4652d1645b96c4e3ae6697c9e6e7a1332d27f28704b850cccf469f829a6aee604e0906d1b84fe104303cb9e187a19b9ef212dd334f134cdf6256dcdd39e91283e6d7f3f808fa5cebe6263fba31f766bd86fb271a524042d3b42b9d1e7729c00c6e4104eea77934fb44fbf7b22ad80eba63fcf1ac416429df3c012afd4f42984b8006e5ab52b94fca1f54fe91ddd2ba4f8366cf74597dc4c2fb1554c20ca28ca4262888d70f342b55916f6eb5a2e6df5a9d0299f2c15ca37f5cd688792a5c255e2f684035770cf4a8894b750f1f97f9c226f9c451ce0b5701a4486b9feabdd379ad31f1164706a137aa487a25c088882c282b5f67599f8f9488b3c1b0540cdd48ad57754d760880478b686914cc7cbb3f478baf3742382749edb287e867d5863fc40a5f57805d1a7006a2b45046698ce63bf85fde10d9171a618a10da3b20d97052fa9416e56ebbfc9b1cbacaafdbfdfecf18d23df346f6838d90d2f0a45aa650d08be2360ad8b3259541f86946fa047ba2cf05e9542e67307dff451a0bea83f3acd2a328f0e9a7c870dcb1b3ef6a387c208f5128951b4115aa4f58193844d54113a5d13cc6e58cc210cc4865613db00c6c515720de072a9fbc60dfb50f48fc9ee71072e14a2380b62d644dd49c7c8f5b30233434f56ebb4c00bc1106f2f7b89d6f4076480fd24857efaecb3a3921a3f9d9bb84353792bbc017ec91775660c21cc6b7c2c5b629258fe1655afda4bde38fb66d9f5b90e0f70419d06b38de8bf050e7278cc02b9b7d762dcd32245c9776da3fe15af5bde873bbfd1d84e8083a06ae1d030a7d32e9a50be599ed816e47b54ec7b686f5e8c55c8edb7d7f34302f343ae7027234205c8d3943244f91ea9c2e6f2f33fb56af3a0ccc1c101608275ffd7a18201a0cf3291320e8c1e397684c604dcb23953aac9cbd65fb8fa615dfe77dd2b7033195030b57e005e28f14b316e63c6a62d81fee131d3ae71734e90e3ca43c6516996fe169bc279e3b398e8ef8929760da3389b29c0e7139a2d889403b823b3361c310ab668167eed34f3ff6e32542619d7d5298bdf4c9e7b4849f0310f386faee38f5e94f5455ebbfce87a34fa93b808d5eac6a62b1fdc84d3895d8c78e211a7074c78262c24c5153234882a4bc043703d997a1b8ea707712ed46f6fb654758634d1591ee3d79804c8417ace22343bce4d0754f4e72e2f518bdcdff3bad1313b974f7f2b7100e6fdbf2fcc34f5eccddf570905659ace5cecd78ceb88f7fffa03bcdb71a77f975f3d13146422c765a228063cd9cc92f0031b8ba6796025ecd4caa8bab5c48b0e6f164739150ac00bbfba4ce69cd212debadd620242fd5610f3fab75e7a0eb587e4ccdd010fac040d8c0b71673f6a6165b188fb59293138048805ffaa283b9539b947efc6382c929295769bf9d5e434b9eac6d1b9ff9ac26c0a1d1f0efa3108401e4f522579e1bd504a64d1359e44fa59f4f33ac4cf3e7508aab3388cd5be219937185ef7459b9c565034c8d4920d5fc62080db0f0930630d14c285ca11e360705f8ca5786e394842230636241a461966252d634cba8f68e0fc398b4298f4ecc907f5a1fd9795e427e6de785d7bc87130d986b286afcc646723010b329e8cadbafe1a9ee23f8010fa6ae67d1bf950c5f0e6fd53d31ad52ca81dfc5225f61de691d868130bf71d6428474215c9d5236a796c29f983064a2c9f40e69efd090ba55c47313f13b52b5d9edb7206ceb0eaf57198f32a722f9a60400bf550d5ecbdb0e460c791c44e56a1301f6f6bf0d9c1ff04ef6d238c060bc10e75114f7d055b5c3c0ac2961ff42c1145a8505e5d6c53389f04b20d2cbdc56759b861c803897be3eebf932a4877b1c4a0b63c96ef9369445e48f4b0ac34bf1799075db6dbb7d18d28f15f58152b0e2e618fb4551a85f5d1613a0a908a2edbc40e4d7e9683ebf5f9f8879e415e070a8eb52c71ee5451f95f0d351c3013e160d55c1207883c8e6fc20a4aef495c4194a7bfc8afee6af3b82bbd0a32aeab5023169d0361a4449af7a19318d063e4f2ed690b28f5d0786bd6ce5f72b9a6e411d878abe616767fdae52cdac529eb07074ec518723f8f870666211bd427b5253a67e40a318563a8b2d8916a746fc47e3ce26103c437e07db67ef057bae6a953614ee7acd16532d0485ad02b4bec1b84302e1e28c41e508eac18f33f76c150c3142e1c383c28ed902dc79922749842efc4c91c75754ea5e0678a117612dfc7ea07025cfe2e4213780734c4f18e191cbd815619b41b0f2e9965499ae19666c4ea34dc1af69dd60dbbe78c6f462a20699b58f50682e9602e7f16580149797067d0ed1b0b36099a0c5732d64d1efc1f370d4c71a6e77c5d319571c3d9274444db155b11286edbb625b77d1294d6dce64ad7fe58a7808b7c9edf7699bbc0e0342dc74158ae419c01b64c07bafb6452f131bd0f889cc40419d3dfd9c7c4418a37763218498c29f19a0b0d2b3e404b525d707c8cb9ecedfd22303a597091a3c3cfd1f8fd1d252641799a9bb3c4c5c9cedee10e172b2c33393c5054777f9eb5d9e0efff000000000000000000000000000000000000000000000f1b293a""") - ), - - new SigGenTestCase( - TestUtils.hexDecode(""" -53a902d7abe3103058efce7d2beeea878d48063b6dc8aad68420073c43fa51732003aed7006824b025934e1c8fc76d0afe681d830c45802205474b5de6388748ac11a6112123d1cc78db7b24bc040fdd3d546fe3bab7663bd5ef49eeef652e200b8f9745383522cf74a481e2b63b4f55fd245f2e9648a24eb158069b1a0a29759b0686e184310130408ca61062344a01b04954b068932848c834408c804912a5200bc9298b00509a120ecbc86808a62d10254a5208450c842924336510a069043809c04444a0902d98102e22a95120332a24000cd9166ea3c86924401203380ae4426d82146a98a88550185201b6485b068ed9a889002391d94292dc900c19222048968421b50cd88411c2966022274813928918c8480846505b1651a4b26ca08804013960d18870491251c0080a8b086422024ec2a865d3b24c1b492204190290044a21b92882a800c000860822058a32258c00661202601b4200044104d1344683c00023382800218d24858d8090400a057052946c242200e2a628123904da362adb106961481144468e833049d8a45021a46d5884092023860ca849d002001bb22118146a49240921398c0129240c42848bb064120632c3322a2386254a02520304299b305183108c14267062460ae39409a11411a00002c3b6099c0845032509084932038200e12200c43492232621918685d224245b003123b04d0c218622c04d0b2665db309108a708dbc07108358d08b4848aa069a0282519318221332a1a284603a40091340a91022842126410466004922819b47058b89101b340092000a39465241392e10229d3a0219a364d14880d132762c9446aa1842183a40111284a21200890b82093300d082562031001e2b44c4226005994000cc14c01302142b64d19c26490a08d1b328e91302e93308243104844c05059084d01488cd2b20108978d9a1209123751d0b6809890810ac104e100400b02261011492132249c4832d426904816648b488c93944c42982d10c14c02a64cda1248ca26602004861228301bb269c3b4694130229344105b442042304021293149268c44060402992c20a780d3488a0927218c068dcc202084362823916958a08ca1b60960b660c84884a33221c80408ca960954b811949209842208c9c670a4c42093222e20a849a308609130605812919c884590006d821001d0b431a344501ab48501024911476050022e63266241362ed4362611b360d002461130451141701341681296092d2abc12b905d68c3f7eb17d160fa397ade12d639bf6fed96b90ff181d3b3cab8c3014eaf7e666aca774de4a4756fe41f540a66a61d7c48de0e5efb6b64dc7495416c50c7d9ceebbfa166e65aa83dee366a6f946173e87c14d85056fe473eafe0ea81226f568e81c6b2fb2406e2c7a7dac0dd4e79efb77adf9721a4803b56d5363e263da9f7915921778fdc9d7b441ca49f0f196db87362a7243ad8b2a2b292e1fcc34d91bb8b985b6d9a3c324cde93ff97b2515ddc90b1e089af7431d8756414ad15ef8a383aa4ccae41c56ff103ea19f4461ae307c511854db39ffd0b97ffdd773b6dc6ef6bcfc62cc46eca01364a7b10c1189e98e34a360aa1e28d4a0fbb329fcf318d382699e990d88304a96a1b520acabf3acafd5c2a8dd28d22a956486a1df040e35d9d1b6b66d261f4813b9785561d1e32f7b62b703d066c151a6795744ae6fe287d75defb3cf9622a6a98753bdd47854b12c3d919d603f2bdf846dc2200500c13caf8357ccc9b2a194d55777ffc9ae29395d9cce2ba921eb07ba57fcad946459d3131cf270e7eb9f2bc13769d7534f3b5fee9abf73b4923d635b1d40b4a953b9f8847574bfef1adc4c79d12b21316ded675e4c02b043c2a4c6c7ed17e0dd68b0be4d60dd4431e96f290477b3a058ff1dc4d3d0fb547dd2510a442b72dae5b3fd6a20fc10f31c60414c7187e6ee85e3c1c0349d15d161a339a91271823f3870188b75b5fd628a2b89da504bc6ef6bd9e15bafd49726722c90a50505fd44ec7704e9c6dd0c1ee6fed3802086d724f23bc11d0f1bb0604add497d4cbc2671c9a9c941a19eb3345a90f611a45f7faaefc88c5e9dd65c736285f4429d8c57048d59d88b395b39c517db477486b7b5f32cd9b3286d59a70762ff2bce191355ddfc1846698bded592107d99825bb6e74fe914eeaf61632d68cfe952adc627054ba70606086ee16e9d07de9645183a853a71656ae4143e2b52e1b72161150ebbd2a80c071b8f68ff67ac7b78b8df1792298ea58e6e6a538d0f73b58edeea526ab1be7d51d3b77919697dabf7de38165b016f5baed1c6379aeb31ad94e20c70b38fb04b15ee8d3f53d6a75e65072fb160177b8abc26024e74e6f620b62b321105cc65ae44d4d309137da386c493428556ccf43a53c1878621d2f4e77fe84eedba5f26f4b9eeaa151dc292f9ee1000612c64d71756523627dae08762c121feab8b81576bde8fe3a3ed682741cb5ada7b7d9037abc35552024e074957df2e48e361ae2a8e707a5f16072d9144ca4339f2f211ef6ae0a81fd4e261e61bac97a47e52ee08a8883947c3be9bf942f4fd625ab2765f0a6f9f50734bdf1f8f185d73d62902ea45ffed411540e745c9f61adbe829f7b46a453473746de0440b29ad93e17c967d767a486eface4ffaece84f9697674ab4b4b136702c93c5da872a8d4a5aa2bbb095e0734d3a7fabc5c800fa77ec325d6ef7875a57617300e938b13d7aa4e9bd41f253560a3a46f479dcc0a72c0923d25551e90f80c34a89fb9a0fa0c2947f50ba0526c61dd4795f72080881ae7a9fbbc0543c895e12bb1d6ba8a486f53d12fc694c5ed63fdf7c32a5cf8f096a96b5a0f679f1fd12367600db4b9ae01d2b3cf4e54240a85cd4f36367967646e4c0edcd6c6f81d674a571fa135221bd48d26744a02c9d1e0368dc772d8f391b985f76a91e657cc970a2acf2671c5df8b9f226b49df5db806b2123fa1e4ea83c5bdcfc2d1eaa64814ec5872b339cdbf4db240148982ca77e3b411bb02f798a22e08d7fd49a1bfdad6839d511c9a8bf2f28c6b32b32f13370f2e7270ac2c84919f0a7522f0aa53c3cdf3059e7beefa7c98bd446e79213520f2ccf91948607365d020a25b27b01b2e8304dea9a42bb111ac822d33e3bbc3c106f21a5ed8cd0c39856dca0649f458ec122a00bce59b1be66281ffeb07080e5e746c3c2ba813307207b5066dae808b944c30b4b8a039ee85a54a32c11ebb0c06f148983ea8d684d434e6200a3f713eb713804780ef113823f759c72227f85e474fa90091a9804241a647cb32778d0bd71bef5f59d55dfe18efa62ad701312b023a920eb53e92b486af3d14471b1f0bc706841328d34883c1717f94244002317dc6e60bdecc68396c016fe647c0f9bd146472660a67fd251171ff4a5e4b4a5a76b2ef0ec2d107449200e5a4bd600946213cbf10f1e8ee23cd3c34857acae9d592cdbcd1fe17f2c61e8e3dd60086bd3c79aad928e34d13c263f49b099d0ab3afd734821399207902b2bab437ca6aa478151473147ca0605a34bf9be2b5284d4484a842386dc7bdf0c15aaba8a043fc571839d78b09be8f37ef34cb980"""), - TestUtils.hexDecode(""" -214BC54C508E63F77B261DC59588A87CF95C233C22A339E7158C47931C1EFEF775EB3C91A32C56E888214F9F68D7CD2525B23F695871CF5EDC6979A677EC19CBC5859C63ADCE2E38C67CAEF20116508F33BE8035E9C47D124EEA5FD1651D64371451B6B96601E4A6E8292ED6841E483C3ADFC3DB242D1D7B3F036492741661F45232104A528B6FF79AA4630740BD16B37CD3E7C711B76A259C0845D6F87E4A4B306E939AD1C41022A7D5938E52B98485D95D11BE629263E6CDE20F63AE16CC2E32B6C1C442EF108D92495A759D3707AB6CF3ECC5AD7C02F133D689E252A26C014A31C65A65F079C622BE3B648496BC57C462051B17175FF81126B5BBB5324CCEAEDE0B5A8ECC0D710F04DC0C751318E8913F149E701AE0568B5426736288CAFECAB1779C7F4E96D9007635F76DEB4D379918447F30167F257B8BA825A50EE845FC4AF7C34AB200D5BF45B5F0405BE2347ACC814BCDC648C274C24F8024561FB66676534F1FC8041B63114679D9F4E8CB0BCD7BC4C54FBB4F9A178B4FCE64E705BF8FE42826EE01F691479A8815E2DA00111DE40B5CDE464A9F7A3D21BE9562FD9A5C5CB3F4F9E8F0D8D8A20B9A5AC9D7394AE4316181621B43D8220FDEDACE345234E3DFBA134BF54E458DBEF98923C1891CFB8DC9B5317E3B16C740EF373666969C95BD1C53F435D7ADE792FF9E310A191246154064D0E8F20032AF4823A335D88D5C2A943CD4CF313CF2999E237F6EC50F63936D0FF3F2C729FAF0232671C94785B67E0CF71A7CA5B32434579711EDF155D5BAEDEBBB8F0C6922AEB9798356714931AF1070C49BCA507E289F005BE9D8B46AA67CE2137935C7EFD192E4CC24DBC434B381E9A15CFC529D0064F057FC3AB592869E5F1AA5FCB299B2CCC0ED6750E318F6FC969E6A3A08059788102CCE79BC92804B1D08F3BA30492054DB6401EA251191BED1B8CD35DEA3A653D5D546D2EE8D31C2D88D6275D6C7B463D449DDAF586D5E57FFBC07ED5558D87F7DCA82E4ADF49EB9135A578468907BD8A6228EB723241D58BAF3C78C46451D2F11CA0552A05A85620001D376C6194AC6494E337388EA49821C233F32579FBAE6D11E9DB257C426D99516A16DA63A7BFA261F2B012CEE4EAF7C5C16C6331B79A26E79B1421371E574505F61D699C6DF33EA734ED14129608260B1233C387638F7ED3A34866D656D74F06C2B8D70AE60A0994F3D6C1267DCA2001EA781E5D6E17BECD284F967788227E060381ECC60A10832091319F225C972349BFEF08D4DD5298BF7EE11B693AAAC682F91DCDA113EFE0F35CFBAFF6C73DAE43B8C1124EB57713C122F0A5FB03D02C4128565FFAEADC0AC23DBE5BF123CBA024DC2F3956EBEEE95918B87D2EB22EB1A8ECC3B267528A62F2280E3DAEC02C89A01F5829B5891914DAC"""), - TestUtils.hexDecode(""" -8ec19a12690fcc4af18b44a46b33caf661ff986315472e2fb9cbf0db6b11f596b5d540572ff4b722d39e5685205ae44f62645ecb6a4f319b1dff9c685f6bc65a311cdd61204bc23da3dbb96f71ecb3922ac19580212e57c121abe10baca724b0acec03dbb6de182f1bf5090131eb5ced5b8cede5444055d33838272afbf8a9d9752c0536f5b544dfd0f20d4994638157e64ff51ea35539244dfad50261f282ee2fbd5fe3b90607a4b2590cc24e67911927ada6cf9b03fd482df572e6cc7441b6129677f3d3d0c0f5e7212bbc652bf53140630bb0e3236d09943796ef92e7916a2c4fcde8c9af522d9661feb6dacacce83e14a6384afaface04e3c8c0febc6306445b84df88cd91f34235c7351048c0d75b6039a102bb0ef30f6e5fae78718be6412db19dbf7536e42b0e5efd950e764c6a80f70839d356f55d607ef58eb366a840706be8f79e8e2ba251063336c819ea3fc60ad76665cd7fc8ad9e404847e0a8ccd5aadf3fc36dd091972959e3de4a5c49bf799c97fe4ac5e993fccd03994e6afd1562a564b111c52860f564e1b335664d57de6fffe5cc93885bc34ac7d278dd28efb850f3e67e810285f47e170243454ac65a18807dca131c99be1f85e34c1c6c3bd3c1f2a13c0341ca961d871e92a2353d813c06396dd29b835971551cdd4d7fffce4d32facc1026b05ce3ac795d54db67983c5bf4aa269cce8470e535bb2555096769215d3df109e2e21b6ffeb6b7461481b80d4894300400851118abb4253b9b86c774522d544dc6c6c2a3c75ce8fb5c3ff2564b9a696ad05b228b8effdf6f54506e2afd2c284d3a988857e4aa22d9d90feef71eceb135f7d6e9462c7302acde68bbc9a813521293d515e8f36aa5ea94a7727837aca76c6fcab11013eb18921091002701166c586abac8f20770e6df05bc682a19c65dcbecc86bca8c85c9175d5f0fba67b33a383987e7483366793ba7b35942b3627a33c23a9172807b578b536fd0faa8c3d9f3d90b6bad5d2b582634b44f9ea81f3cde12ebcf48999d1da8651cbc89e87e0cc049c4d1efbe3eb625ef4e09c2f879ac1eb7e20ef58544332a50953643b02a73308cd481d0582b4edec16c4f31f8ad1ee6d3575ed3e318a8df9a0bf81eaf7bfc720268c1955033bd16fc652cf68ac5289488532665c4b584fcff68aa04b1d4ee55556973eff4d8713b2c3bb6dfe6614b9e6138ce9799ad65d824159e1cfc1519a741cce18ad822de048f19e01d40287494822393bd6d321b8ec3cfe0f402aabdf03743ed8343d442871a6a56821596144f9005f72f5bb36841975970caf6df22724959ff6c8b57049c88176f61bb1b08543d03a7c872b87ff2fb7a66ac64954feec8343f99dc5a84ef8c207033bb837bdeb64c5d4674014ec3ee792303ce5690f2d47d176037ba7ad21b8d4fa2b83d6bafce3cff48e12e12066be8ec16bb2127a26516afba6a87a1f7951ad2ba40b76a800e2c27aad75f883343ca988862a6dc4e481faea5a6dccc8fefcc79f4970bb831fc514cb993624cb7eab874af102ce5e06dbaf57d37cad159541791afb1a47f9c838db9168b27290633e0cef4446d8765ab5e70c7995d437d1128c0a3b0d5c6da7bb7b3e450574018687549eabb5122a89ebda3de0763497658f160fdf054042465eb25174609f26f4755a50d2df918dfec074aedfdf151645b73461d3eab7234aabe1d19ae9896029b57b44b90654666a2e8847d1aaab3b3525952eeb5f0f8cdbc8e3e54ebbf6be367d689e7140596ba674ba940baa5b9637c685f1a1228acd893478365ce039a0a67155eabc02ccfe8f7731d8ccf754cbfa512e604682bb1be083feb424114da3d7243498be28857f19468e5667f59625902b9cd228c366b684154a47acc23b03ff98dfe0c2d02502f6c5e7a5dd212722f5c06793b86d43494003e88818db45102e790ed30f20eac90be73df9b92f5064827fd43c9be4423f61c23dd661a6fd9856f41a2f65127d555e509919b17b0be2e27bb45b07e39482877651ab5e4222875a988a9f97a6dbf9cdccad27576426927153dc4310583c9bd8cf6fb5d50a2d2956986c7bfac0f552693355d8ce9c4dbf4dc5fd6523cf4d32ff62b4e8d9e281eca16ac706b3b737c0d2c977ce4cd4bb41e5e1e2cc16e63ee0c408713ce2831e68e271b52a86c2b8bd7a9d0fba9706a55a5b62ef3eb8a29c793f7a66e182ba4ea249a90ca8988c00396c2d858e3ad362076a97ebfe8d9870a339c0a12bf997b66ff5367b4591c8b0deff659c133e4f97740802a73fb1cc6bdb46b3f9cb31086efe81f62bc087786d1e984773aa976ac597537ff1b1e84991be89df4c1ec1e29a2d72c2dbc5449af5bb95090d1159d6b80e2c5936db148aecac22d39803cead75e78a05731f382b09b51b9a9b79ca9d5bb51b78e591bde312625e52b4ab6eaca92e95edde3baa07b8d12588c7bcd8c2ca4a7e6e5a776eca1168694da493e96fccfa6f68e25cd4d441a111d8de31a0914e19900b218ae50f21ae0659f8f8dbd7f301a061b80add0697f6201ffb0d8c6d42e3926dfd98897d967e928802c9ea3cc2d3c3b9e36b1a29e95fed603f46d990db7034d53159e5a5cd7a72f08e451b5d7dcbe0437a2f20ba5cb69046e218cd3a7b491d1eb47fbb22e2a3b103396bc7273c218bd0eac9f272e6d01a7ded0595b02694981cba45020c10aad67735d5772078099136786401282c850448fbf27e71c1233e5a992a47cda05c1946c6f3cc6cec3899dbd435a1d016b3c771153f44e46bf55fa7fb3c39d8fd1bc14244fb70d4a5b8823b39e449e4d5237e0d99e49e88a85813efd60296b8bdd24d27725f993850b2f66825b9c469f212d6ea131ad96a089350cb76f434e1d2054fc083571f857a36a93f0e6f5fb80ab74f9bef3c5bb7df3f47885f3d136acea283085b4080dbaa5b555faeee52948e6a5e0b0d7c202fd036108998704022d7361ec72a89ca5008f48d11814e8420b453ec202cd6ddbbdbfeaa03ebfbba50c508c5c1a81f6f4367a9f817c39613713c6ce439cca013e1b645854e10256f48ed38c50a7e4a76d01102782d433e612ece1aecc1f48ce45b1da41962c89e811e26895a4a953c38efb620d2285c05a99c27d8e02ff419924c99daad70827ba815c68b0165fd7c4b6ca77d3db1a61f8f95d2c5e93ed860f90abc418791dcd1f95f29f4a45a8bb637889c16c7bbea2ed4a87eb11d4c2d8a7ddc6a68d1f83b82f0d206ddaf76f796c21e0ba9dc3179e85dae4d7b3fa40da3c65c0d499b38362e179e8306b1361f3212b0df9001f325a747b808991969ea2a9b5c5d5def00b0f3139587d8890989ba5bfcbdde2e3e4e7eaf8fb162326354a53f0f2fb080c1c25474f5355627b868a9fa3babfca00000000000000000000000000000012273041""") - ), - - new SigGenTestCase( - TestUtils.hexDecode(""" -8786af4f2617911e937b31037e66d478136009c090bf4a971bc2f286aa31c252c1374f612e7f68634201e3eb5857631d0bdb0c10237831abfde8ec3a0707d79a6823ed6d5b5dd176c813b4473c92173db04935e42a920636592188cd4cbd733894485d415a6b7c095e7edb84998ed6f8ac81b9d8d7d3463d3d5c9934c1fa9484e2428a5902529bc47011258853205284080ae14412ccb60c49068c5142424a366e49305182b08c63362e0bc505e31841cc188d63b26d4a484e10306c8aa62d08256ad82030c916299b006d914052c0b66044b88493407112294042488da2048eda08841a098600265204092004c89024902c09a4284000801c173284942823362a20104690c62811c9640b064601304e21122d4906894c926822036cdb8880884282891689e0c248e4b431c02650daa0040c9211d1008020c86453160618024c10a92103466de2a448d8486a8ab66c09c584dc44224848011b07315046081800205832212082288b1092d246499208491c184aa03889a3b204120845429228011641d8b0011ba5515482614a22312126691c39004a86280ba62c40027221308484284ac818241bc41103836403086d99266210254644b669d0827108c15114952c23868824a30c233900d8442de0086482280dd1b68141b888c842641b896521988924b43010b16963209020114118828dc18670c42811e31442c0146ce340424a2670ca00456424615492250200251097001a3084121912800206521650ca180903c9250a454090160c13350200056424891152362220012d1ac110d4388ac39420232329203710d3428ec9864900078c88206118240201a1510433491c9751c42232d894281a3851534292cb2691d9325008226e6482601139069b3651c010010188804882600c089048360e198830d8008890401020c72c59c85108942d18b20ccca66d09b125d89820a136888c96098c308adb466923202d94a68c8b8061e3b6110c225101a025c116889cb865423030c0026212b0241cc68c102609e4306221a45122371060b63003156982b200e402085102329b081113346edc366811104d4b9041d900915aa42594920cc21246c8322104433160822dd1106642200644024edbb6605ca66cc220208b182a0202069b804460a0008c282dc446012046088248804b201151966059304801956461a80949a26023b52413976421468c033431e21009c024680bb34514a8090b048a93006e5a8471528004c0228499828470c8d8a0fcee58e3fef7ec257174ae39ec4d8e78a56f35e87a388ecd2a2e145f77b6a83b61d87437335cc858b8d74ba922ddefe22c434bc8c82ae545a194a19d67c7e3b857b2f2d42a70ddd90ca9503eb7da05bfea7e9dcc9f02158982bec07ca961fd8e288e07683c9ae97a5cc8ddc6e8356ab44827626a4930c683df67aa55162947ae38c88681231901927e8dc6a6f5c318fb8dafde698796c11e799cdd13e24cb6eab09209c71108f0920e5c9282f7b5d5585cf1cd70feabff9a98786ab90daeac9040bc2243737993dcb7a1338fa8baefc0bb6f9aed2511275dc008b8de75bfba4747999f032d4fb676a5b8344eb4d6ca29aab4d36fd99def5baee9a6920129e1d15d2a227352940b7d4129401c22578c2126078e85ab4ec15874047fb3ad53c9a7e9e92e30fc059d92316cc1c992bfc3171455639d6262cef30745958c3ea541df6ab9414b326b7edbabc29e0ceb6e4435c49eb07564a08cb611d30ca9603de65327ecccd20a8207fbf4c89d2914233180dcd25cd5b6325e23d591af9618ae1ec1f33908983e686456de3c6d030991ff03e1e3fd43402e723ae17c9793fd8203e041dc8ced303127161e296b73213242958552eed804e0c74b8c2d1f72043dbe02e0bb984a533647bd7b8625ee85119ad3ceec74444c87ccecf99a11ce5a382cb7b20b4c1610e9f12fc6ba5887bacb9c6e46d4fe49c86c61337c18a93da4d33a7cbdb0a609935643ec3b561a7d797261f61d085abba60874eed0f97fed77609f13d56a60edb328a8b7f3c93f270ee0e96f752713549a0dd055f07e36c1fbea98fa85be51e9cfaca9531cce28c563b67dee766383fef8c3b1fb56592f936f164fbeb09ffe4ba44da30af06a2995803f64cd90ec912507446624e13377b83046da93f373373b5f8b62249f477206f0ded335be688d9494503bada0e7bbd80cc14def6934a159030e50ca9a2d08cd6b529669a5ea6e92884dfd515f58d3e2e2969c6732a8d28a30951929c9afe0db0c41a13dd7d817514f3aaf2e8bed5b6b5d7c5cdb8587a51dd78204669979c845ba412072b925cc78c8041b7c35b9b9c2784e70329103dd53bb4b42d97fa5e4ad73363aba999152b37079f64cbfa9d4fcc48280e355b4c12df212cf806ee7e4c060c5eabbc2ea493ebaef3f3363539f2a19413b19c6c64a8fba77047b4c43531cb0510abe7c9f476c35fc8cb5a5cc1b883847f9938e8a48a913fff14ce6f4d04e1314b39acc919602a2d013a8c59fcbec8955b1ccc236eb4b03e304cc0440eb5444d91eff5f9f2fc8c08984eef85fd550b76948f2a48368a6cc84bbda74510f9132539f75abc6992a0423645cba1ccdae50d78e10a2291144c814bc056963f8cfeca4cc81adf3f2629b0b687adc55dc86ec6af5e390307b89821b6999cc62067ea0aea384cfc8be76e55d1c893e306b2f2812c6793bfe8945b7d121e3e760f4dc7fac172f5b398d066bda33ca46a35e0a24562e7516e645ac2e00be09dcfd531c39955be696ff7eaaf7192c50f3d1601dc2fe47f9ce3ef9084edbda8ea81a4fedb37eb2aa3869cd78aa1b1a3293317f748f8406fd83f26c581d5f139b9145e1538fa71bc30b8f9e3116592cff2b1ffb8288d87ae9af70330e57929dcc8982c7320cc7f48041fad10522d96851112d6bc80e71133000d125aec57bccf6bf96bcf0d08b557c67fc33a8fb627f4fdf768c83692aa8b5b6baae585b404f3863e3cbd13c1ec105c699124fc569edc3c68da55146e52ff0c0fa831003a13c50509597a361613fb6eb30d881eaa4c7371eb6ee2dac3527577b8dd404ac55ecd3c11ed984c2c62cff35b1c5833eed91c4fce2684e694ac53e7a669d560b631a898c38d40d99f112c58c3ead838ae8461d5c1cc6e3103890b3650563eeaaa1bcd0c4808809fc9814fd8364e4b81152ef67a90a2bb6932c59a2833e89f2749959e49ead34556b430855913928fa26bd6a3fe74571519a2c2352e27023ba2ce62da49dd02441218c2f7f492dd465fb496bca836af0fe47e96ab5cd04f6e3d27d61b2c3a1ca3b7a45681456c427a1f752c7b8dd540ecadf8621f125bd910fc755d349a00e64a20063ccb3d2c27d2808c86ca8d80d6edee233ea88f6a4cb1484670fa62e7fca366ec6c1bbb227f2db5a2ab9f68f541353eaadfdce5fab49dcace06203cd43db0617530c109a3c9b8885a972c7db25d489cd816e98da33f2b742333fe88a839de2e364346fb47af793b639997a0e2c6b5293c14c97964faa65656e6f624b36a7dd00afc5cecc8b9bb5a1c79525f0fbdd568c4acd72678ed26013d3d6aed9696e4272dc1293d224b83893a83184966c25a3"""), - TestUtils.hexDecode(""" -E742D452F392CD3CE405908EB380CB0225A4725065AFCB0C91C5E4823471376E6424AB24D57FC4265B24DEF6CA73E28FE20468B6E26BCC9267AAD2B7B82960C3FB5A01960FAE078D5A54BB324232B6647C9DAB943533C865BABBD3DC0D1E7A1756212980D75F2C8E999DE9ABD1874E3A86DFD53340B6E424DAD9F53C3CA02B44FF8DB9906D3D4352D0EC4B1A57A33FAFF7107D38637AA410B196BD1BB1FD7AE4B7414E1037454A031839AEE4C796BA98F4A739B785E3854E9EF0D5B7415C8B7ED012B0123C335730C7021CE8C94200874EFE783D7C4BF768538A448E76120635217727C81D08976CE4B5027D4BD9D9E27E4BCA4791ADF6F8DACD1BD3A03BE5CA7F68C2A2247FD3184609EB7243D2366E5EE4C95CDD869DE41A4B47F021DE76CF27464F814837C648A7A7CE2F91104322BE3CB1160A0D10CFE90ADAEBC87BBF14387C8387F4F5AA10FBD469ED5587EEF537106CE0F3AF4CABCD4476F248C21D119523B680067B332A1CA4C657B9DE1360FD23ADE58C5538EFFC8902281FC7B5C12C22CC69E7EB18E5F6F8352B9E4935D06C96BAFD834934618D9E6B1F60292352D064A0EEAE80F7B721312FC1B6C58D68A96351431A8626CC117BE9DFA33A1625BAECF12CB1DE33BEDAD584A91546DC767D0E59764FDE3FC29052CCE23ED28CA5DA4507933C0A7702D9A1225A48B71FDE5D27B12FDFF16AC2802E3629E10D5FFC2FCC6135243A9E2F3E3867BAA0C0F0C77BAEEF9DCFBC723C7A2BCEDA39B53B415BC21A397F9A8C4DC580EC512DE4EE4E0870DF1C4FBABF4906E0CFB08863AF2A89949F8E0FF9385ACA3F588E05781C49DC563EE9E0C5D6FA512932B7F5568C1E0FF1C9492ECAA5465ABFE125B511723998C4071481BF1C53DECD59B440931AAC640D9F78B1B40EE46AC0A8FD18B4C8AADD734B0F03F02CAF6A7BFE3DAF100703BDFADA7DBB50ACE3D40A05AE6E87CEDC0B08C44796D7A63E8B5BC95D97E3EF706E1684E791D3B3A2BAE1E7A92FB70A33D896219E80751A41E16B506FF266C4BCB4346578BAA7732CA745BCB01988AADBCBBCC45C9FA3A5D38F3F8E04005AE777910032D992D5EF9DF2C0422548A980707050CAD9DE56BCE60EF74EAA4465EDE96B055999F81A2C9596A2B35C8AB3CBDDE9D26AED44527DEB9A2AF3BF6A853FA51DCCD913876A43DA3E0E2C5B42571101B7B930840B0AB64419E1043CF56AA3C2FEF5B39CB582971A5776F8FA9696CD9F67E9290E483E9BD1698E961E849A513608C3F20FF678EBE0C778C2A6DC1FD3AFFF89D646A1AB85F005AA14A0635E92191CD41A6A46CC283D2FCABACD2FA07B7E2FF97D17B36E0B222D39DC1EB61BAB8146F147579D02A87DA08AB4ACCEB32AE1C8CBBB0EE0D90A642BB76DEF4AC8C7E477888159824349EB075DF0BED236DA9B2826E67EFF220AC84AC99BE6EEB0DA904887E3A84E5208AF49BB31EAA1552EC79E5BA02458106B5A31D0AC8AF392A63947911400FE78F6C94B3F8E6B7C3B98F6548E7894EA22215C87E121441C53EED726AE26394C825517EF8A477A6DF33B5315C8DEE16ACCE76ECA60835390E65392B9FC5EB88EADBF336FE361D190ECBD0B35B22A6FE6A8D48466B5E70BB6C5FA515CD8672BFE70054038C5893E514E23B16C39198B37B06B21275C2994EDF7F9F921B320B39E29444E3D621F52C9FCE19049D403AFBF1C047C8B065543BF43A25817533A33DE6C866FE9D8A73B2CF7277CA0E8D78F4F104C5CE6FE2025992E26E49D4C49F0798278216453C00C78EA7BAC2BEE71E5273FA46044B4B5578EEBC2A9E42025A8A3526B11CEFFCFF47191109C56AE105CD70A04C3F4EC43E49346203347319D8986D15B3C4A49F02C02994D8798499DAF1E0ADB81A9AC79FE8EB55ABE2BD18EBE18A9E5F35D2F66B38CAD6F6EEBD29AEE054C05D6F0B5326CC5B86BB0FC7CDA720838593238A2FB24E0CC36DB193FB7FA66573B064497F771DB1D965953477FC28989AEA2CC004640524A6DE8270E8A5B12BFF87B3F63FBB7DA25337EE34E6E4EB45DE9A39BC9B95ED37A6A404ED2970F9C79A7C2953420732C496B855F19BBBC8ABCBABE1D26D5BA828EB060D7280046AB93979E0BF90B6F1C07CA70833BEC83DB41684F1842A23417B3BBA0A33D7AF7BAEEC14C9C96FDF30BD201C05AEC6D3D2F539D511FBB356DDF333409EC16411DC7255DF0791BD67892880A4DB082684BBCA8B7E55B421C17DF3B68720E907C1620B142C3382AE6E738F8943CD214A847A6439A682D62CF0AE8961B5F020E7126C5DD6258CA0E8F5711E5472A4C05ADFA9A6B8180B741F382090CD1C781F7CC7F23E041800F42B228C351AA21E4D916BA5D9C56CF8E9507065D729B7C3653A8BB062C0463BF0B97F13A1016BE4851F5A489081A2AB3D2AC2744008BA734ED38DA10F372D97EA0C278C709A23ABD4B07E91ACF6A6F2DB9AF7806820381845FFBDC4BD30A503A0F74F37748E3624BB2AA478210072FCA83AD1A43ACE9F2943AC1AB6CEDED67938AF921FF34F2DAD4F224EF7498BC450A67CA383A9DDA333073286A22B85570A11FE03F55119794BBE8B81EDF1966BCA5E363C15E8E8673C94E3396C9AEC28D110408DA5561296E2928C6C111A4826309F119E5456675AAF935A17E80C0BD82A9CAC2627D6FAEBEC9A928D33980A86ACDB35686306B57D466864A0320F21751FB0041BA0F4F1660774A519D3ADB304438C1709711B982EA84D1B193D026081A4663AE69C5E12C3E4A683FB356DCA618191B29290C5DB4AA6A069C3B8D61C8B7FDA779E1F34A5F62EB7DF5C563ECF1200D3FF499DD06C2BF44A2B4254318BC402EA3A047FDB3570EB40630CF1DF84D1E2BDF5449A1F65A9DEF76954B5814691C4C12BEB10A1C006189968F37A4B236D9EE0D39AC340852EC54AA64FE15E1A4433ED48153D23B2B648C8852F3E3AE485474AB2DFD58A7F0CE6691ED36818DEADC8973E6ED06AB841B0A915425D7B87E41E1E68B00BE2EB725C287FE575736F6E1AD2AAC61F02A3A00ABEB2C0FCDB35564E8446C776E980636D5D61740AB2F0736A021D82C1D66864E5DFA98C4648CFBD9C7AA865F6C97038656C9C8767898FB43B0919BC98C1D0F6FA4D90F711E5D009D4C8FD8A773B7C73CEA654A2CD52A276C6CB62265294869A052FA1634D3EDEBA1F69DA09F0568F9D2F6C511F6BD6169BA0DE25F09FFF63AED2FDD0F6D89BD01FC5B088D3EE5344FCCC0215B6436987D6167A0F2D5EA47A984DC86D45534BAF35129488F3BC2D05BFFB84A51A87A1774033244277D0F2B45EA43500F4034081711CAD67BAA9CB0A58E1D01013032EDD5EBC7095D4BCCBD28A5F32BEB685F7901BA7A839650023B0C908FF33B37D038162FB96EBA35C2919560267EE5A94035825938D168481D8E59813E20DD611E4E23D8D42C9DE1D2398CE3CCB3DE5CBC4BB16D555985F411EB5B56508C6F4E75621304DBA2F4F1A2D8B2BEC5793478E5AA0DAE6F52C43253FE7BC91D3FBA84F8525D002CC307CAFA20BF198BD8F28CB579960A1168A1D26340C8E26CEF1261F23E97B806E9F27BB51F16102527721BE0E8B930A1ACC38F0A63EA1F3FBCEA1031E441FEF4D3746EAA37B7D4F8AB354D5F079E56FF4446333C8B8B7B589CB36DF40EBC5A75D2237F3FB874E7E0FF1B96DE43BCF229DE1FED3FB6D01752B3271E1F98D4134114911BFAC8351E3186E90DA3DE2E7FBBD305C822FE6F06ED1D4774D7A66DCA0CBF740DC277C62FA641ECAFBCBE359A28FEC48D62E1D3B6215392C0F8DB601E35A6CBD978567E806168A9F5B4915A80DE405038C4A370D898ED6441F727985037A040163F14DA78378931D3B96BA486958AE8902C98BE75BD0AED53CFB609923C63615917EF0BC6D07CD183192DE3854133F701B9D4B499F958064ADAABF4080C4A019DF1E5B98C8CA265E031B8CEC355C8FFC3BE16DC3D01533ED17C9769365D023CE7F0384D40F7B6179612B5EC382982E244E2510B4831F2D53F26B142A33877961EF1F845370CE115CA5F0D2FD6926482BF3BA1AEF3212DDF36705A210D8076A4428C7F9CAC411DE590452C761028469947BEC31ADCBA229D8EA58755F2715AF6D51E581D2CAC4182557E6815BFBB84BDC54C9368764CC29AA9AB49EEC37364F85AEB3295E60CE6DB2639669F55CC49D7934BC8566AB5E207B33F29128868BCBC1DBDE1089317088EA3FE1D595376DAD3BDD156802F82B63CF4C5ADEF9A89D94493BA152F9F07A9E9CBF8D821F1D6CD602EC49B61AC4F7633EC810F3D01D4867B1F0F3021D70897593303CFA6B5A3BD0303AEC32105F854C3DBED373760DDEC9B9E8EC4AFDAD00FF2E5A05A0113522024B86F1AEE6F250AE3BF0AF1E6FB7DFA8E04E3F9D5C876731D9C33460FDC13CDCDD433B45A6BF17E98638C264DEDAC262BB03714E020F4576DCA85DFEEBD6D70E557DF9321A8AAC519C419CA20E33DA37C22047D4CF925AD67545D04300A42B22DAC098A912848302D830E06CE5BACCACEB6E9316F9B1DEEE271BC6AD9D74927CAE725CCAD0C596653731869E8071E23BF"""), - TestUtils.hexDecode(""" -a99a8d52ee69a69d91581ac798a7b34cc594801ad2f15e8769de6761048ad79b7dfebfc6f97cb7694d14fc315c879de9029b2b5331f64ae72e36833d3e5bf3c4ab64b8ad225d7b17a146f4d15f05ff72a7ce975e6558d11e3dd0e24c5b8d81ecbf96c732ddc2af021f62ff48719eb70ecef5e65a3acd389afe3ebf1fd6bc218dacffe07c78ed1ea343b603e61d5af9f6399153572549b29f88139d08ac0899ef084a847ec0fa58d0ee3856dff6262fb2355873cfa1426eb3f80ab52d3f6cfac2bae2a1abb12a68e6476f7593f5e5694d541d7d09b02a39832450c80eb785fd1cc13b441a96f22910a886aaf3ff61df7ff9f079cebeeeee218495f5307da9ce916bd86698560f758896675af604a3bfc2721e8e3dd4bd6664950d7e8575a09d439ff54086efa2405dd362f03c6df688120573884b46e45970e65934b5baa1255d6344fb115ffb51aa25b1bcdee1020e754bcce521ef28bf26d7bdfa498a5a182ec8d202d7dd0c0926b71c12eb74ab4b541c822f399bb4f4a50411ff28784930e8c9a6e77afa420a958528d4848f6255067d19496a23b39b21b572158178fe1e4749b3292133ecedc0db2038fe2eac7ad1fe02f426af8391988e46bdc8b621e2c17704360decaf8d6ed08ca825b1b3b8ff95024f174949c7a6f9d8a4a079f2fab1fa0132c01f09b7f7abe7d6aadf9c53d58a97d270a1f9065b295b5c524f3bfa0de09ae02ea5b98ce4403418af601e5cc876b4f0c95ecb7c1b8bb2f72448f721d81c13cefb99106251d4f37e47dc57d9449b405a132d25a2f08ddd8dc77f0eb905d6f6eb0d0cce96b95068d669286c02f1cefdade77b3dbadfa7cb912c62279d0a4530cc5c52941b19de495e2a2a3713537b584b2f7b76e3952ead9ca20b7bc9bf26bd36176521f4347cc8b3c2553d37ee02066258dadf33306a2743917287c09ab07cef7bc4435d582e3cc2fe79c272d719f133e6e5ff1341cfc139257d5a7eb146327c03e897b9668567b6cd9fcb74711e73df074ee139a57229879b903e55a04c5c9fe9b6cf669998444b93963f85ac7176a3f021d7c9409d7ee827de8a11cdc431521c96ed22fa6f13759eb03687d997a25a9bd60800f3f534b3e9c9dba97206b7c2f326b34a087be1798866d1914e59c8eb2c77414be030f8dc270c6ab76a6e1515fc70ce50c497364fc55f0ee4f49d3d22a08c6b9348042d904ec2f8862ccf5ee0b3d22d2f1a99579d35a916748ef608406883c53f18ef4caeddcd780e4a44c872bf2dca063aa11cc715e23cd996e4e3874463a1b4711bbcdc2418e4df10667930cbc7af5ed9b629ed452c240e02b58ef61ee4f1429a6d9aa57471781887f2e1890e70f7589f8d8b4e5ad223ba9d0f73d3ec74d8249b82596c8ec733881fdd0c96d2455ff5e340298a5a6fc91cbbc1ea5a8a3908f6da6ccbec88756874de1518602557d2df30505dbdd6d59469a6f2bfd240aeab1099c350d6730892585c577936181bc9f7fa6ef3dbb0c1d39a082b1a35a86899cf26261927d52b373120225752792f02cd2f196b5540121c3f9c0fab27b44b9462f6396195e21f2e1f736095554de7221f3c9ba23b72b480852c86b179c0e4778441c3c5242d4feb9851165dad83804c7ce5d534dcf918d27ab36ea1faa48149307b95cc3bf51a6bca256f115e3c618b9787a21941b58ce52abe359eb1a5a19aaf67dd56950a6d0179637ed0ea5421b899325ba05a26771b9449ba0de0b3e674d62398e30363d1d885f424dbbc200af85c87d28ae8a3054d82d4be0196188089d180acc7197f07033cca984e20732e9029e832268ea405cadb00dd002e3506e621d3fa7b023454329abe1a48f7dc35730f5f352c25694eb2a0650f9505866d9013e8b88b19b0c5dc12ce799ce8de35caa4b6552f399f8a7b06bf1e5bea54092b504d9ce81fc3fa2a40dd9ba5a2b8711d02dc46ecc222b14655b151499f4b537260b6595a89703ff56ff4c976a4592dd53d12b6fa9a4a775acba17a1b3dcc5ec0a4e03db9c9402ef6380e62d7f76aacd613a482d31cc17a7ae99311a01916a3abffc336959a491995183f531ca9ed0af40131a28da068038649639155bd12b9d3a06238cd3c4b754905b56dcd52cd213a2ea369623f32ac7877e6150d0f5ee25de926829beda4ef67cd3c4323042aaf3deecaa4d404426f234fca778826dd3f29b007d369ff1a0af66ccbbcf20d9f33565b7ed745c160cbc5242c683588a67223d81409d77611cdce68a0478bc50422da24632852862319f20b446917557588d19d8add012137959e6791aa7ae19597a8a2f875bb8b78b17d6f5d5b10c1996414ffa08e698c7789343487a62a98474a39cac820ecb1a855dc825d1d7bb9c302f9945b4ef5ecf2e85d22fdb7f440018181ce3c71fd8a6493c7e0ac2d38ae115a018a3583eb45abb5542e66cf77587ae2e1da41ef8b98b2c2616f6b62d3e2c7e467955b0ab3431d1f5ab617adf90334d87b2c01e450c5750347c1c98fd4fd4109f13482e11e2a6ebc4a362d26c6ac9e4d112d18c1e90726a2042ea3d5543c33d32ac108dcc34999db8488895315f18fc0d359714eb6c10b0dd405f6baf03c0c7a3b89d6ec2593c317e359488ab2a1e85a722b2ccfeafcdca2e22718a17363634036af5aadae7bbe6f48ea36ae216b827aee084696c7094dfb6e4fa563b51cb1fe41f8e72db7cd527c363bb00bf8d22896f438ba637bb7fe64054d69b628254a4cdce5ad92f753cee7889c460af2fc4cb10ff6458bca2547193ee76e816a39880f48fd2e246b66efb3056cffc0d233a86307e13e7fe87e4b4c8408cf7bdcea51d189dda4c4cb4fa44b222e4d0ed51a18abf77b49fa0280dea06852e864431c1b4473e876e2fe4f00d423aaffac81b95f186467e409583252662a0761a63ac3511058b4b0028d0ad1b760994c98fd7ae64bbbcf8e615e416bf0c1a594c0fdc46f760d5dc394497cecbdbf06d7db93d2a711756a3534f7550dafa01954f291bbbb511b652b032eb00b804d654698127e2ef480c53f47efb10c949f50168b1d888c62c9bbc422dcd07ea4005d751dc31d374357c10af8991adba9e139e75e3367bd18c7e1ac9753b2241960999e6a0ab795c475f5a330baba955dd34fdeadc193d9a6ea7015b44a04d0d5fea544c140c2a419c86f89ea54e4cc2ed8830938b171514a189e5517949c94ab77a5e9521a38560f3bc4e389c7fcb0b49da3f037ad53f75a85c0fff2c43945bb3d3ad65a197c6db5fa9fe3c78293a2a499ab553af3756ddcca3892133c1ee40a7b73bd19262b33364c575e7492a5b0bcbfcacdcfe4e9ec0e264b4d52576c727d9a9da3a7d0d4e3fbff2137789499a3a5b6bac5d4d7dee0fe0317192e4144484d60626f767a7d8c99aab4bee60000000000000014263549""") - ), - - new SigGenTestCase( - TestUtils.hexDecode(""" -194345a0607b1df8fd01f58d30010604261e15d712806f9fb99d3dd6afc994a9dbdb0934a7bee40434598e9fad7e0c7914ed8f127b35ffc7d25d5431d9b6f7d85c5015968ebf6bd70ee835d8da55ad1b9a9147db756e7ac35cc3fefbb3a83586e27cd96dc334a6ddad65f8e4c907bf243d46949290f68bd7ca9a3979131629b66028008c9850a33229e3b841a03244c8a20d4b183251a8209084115c1608cc9611d916095cc6040aa76c14b54822054113a2510c178492b82cdb12408a082d141481114300089090c482418a322258104d4036260c0446c9488c40903199488989286e59c48c1c464608b7010b234d99286c9246010c2765d48860e2a091dbb01002067108348e03466803c52904c84101224553089118022ec90665e2006111021108258d63102482c009920652d324820b361198b40418b7851b184ac2083192426c24448819926821286c59b22c03033184b00091b6059102086000060c3491d1324e18c4094c923009456261b07061102818328200a92de08869cb12848b944c04190840048cd1087054306019197108810848c6841aa94952c0010c442151a0602009516088312243059c0486431629d2064e494420d4484523b64823288d9a367214a39088b04101a4095bc46413276ed8c465103450448010db908d5912480ba54824a18cc0366dc48690d3c48cccc82c1ac62c09c684c80489621451e1044e022704e2124514916c893288e0c480899249e2204408966c4c402da1884dd1145040140409b25024a805043752202369e02225c1464000178da2b291a41646201832d2066a21942484006a43c00420c349d48011132168a2380d4a4848e2c889d1a065c40849083909802480d0a269a39625092204c13805803844090471c0920c24300ad8126623a5310008501b814819446c13b61110a80cc0b871123885819671089669cba46c0c8525489211e096090a2640481644240322d0c851d81452c3128a9aa0611a414d11334a9424520c062e81141263984810417298460d0ba64c98b81024a76d5040320b427083b8044c88050349116382214ca2014a2445e3922020c76d22238a59b849cb0250100946a2484e624490c920228134018c088224b78c03a20524862404178a1101464046880b460e8b8640a3b6514b240d24443104082d22a265da98645240059c824ca21640ca266843006d41c6519046449b82405b226020155048044c59a41163888944826c5bb40124914c23366cf182345ebc795b4629109448f210245d70b278c08f9ba6a8fe4367262321945042fd365c70fd042e81b3c244cd92fee3289626e175cd20642852cfdc1e72a16d4537f85c1dbc25d69bb8dad510dc259e5d7ba1575ac940431a237806900b8fbedf88594c69ea597d4b3dec2328796b644604e63855770dec3d439ede08c27e01950b3bdead4a0b546bd0e6bd2b6b62f10335f9356dfed825fad33fe0a81c0dffef21effa8960cf65c22282ab77d66a351e4e1c56a4318abdfc6e20229b14a0d3e8de682c50e9f26c9bab44ec000a8d78dbf63d5bbada80089e6c3a300eca7949f554511f647060e23bbdbe9cf77d68ed3cdac0ea0b491768eafd65ba35cc29194a1e0349fa2ab09c920c2cb87199cce638a15010f3b235e7f46357b5ca7372b6e1cc172ff2df92179062b47f78a977040418fb79a4dd9a48dfd7024727376e254a64822002e7060d297a9d081ca39f148e1c472cec5c34c39e84526dfe3ef6153d21720266de887bab12a0f37fd0a79f8402e1fe9f2c149789b25057cad2d4073bb54d56982ec23c541cd3e6f7727ecac5d075344402ec3400401be314b4b4428f0d7d619bb2b8c3d0b35ee824ff079a3431acbb8b644dd841c92cfa8610aa302da74f2f8c91ec5b91a3b19c10a5d3bbd92b5dd1112630cbc606e0ba22db2b71f6b3f24aa171ab2efa4de7151e1fc879fbcb5828f232083d055507930e7bfd54f34aecaadf28a4d0a3220abd4a7c03b32e635223f963337ff7f048d7465116fd149bb0d1ecd112f32f38de619b50544593e1b23f661a56f6abec97211194f03c03697c4b5a8ca1ae309629a6737347f23307aee2886ee24b46f8ed8d0f44680a0e9d2af553cd154a2c2812a8132da51773d20c7128057c5db127b271a2453d7e5bb72ed1012dc88f37687da5e721b6848cecda1984df797100dc57a7ddb8d751b9e16c3755f85ad8adada51b3f13a08c93701214cc26b33b5e763f9bf8c3e793cf224f03df1aaa58e95333015904f2da7526482856560022bbea43626953a375dbf8d0fd6aecd506d6e9e6fed3ea6cd2313f57be0c0939a82b95e9151f9453029bd4223dfc55f8f609ed52d78d114373d6a0ae370f5a28e0ed6d29dce7f2b7f00a02eeb31b76ab98c432873705a43ed9194f5ed014874b019116b63c9408673cc4812594b682098c42c69b70e2e7b29c2ce0fde2a19190bc5a36de97c3d6ffa1bca253f2344ac9c0373f0604b0d08377469f38e7ffe86bdc130838452a1f790efde6f8aff903c837b0416507dc69c61d39c2009f4913c0750f4b3c16efdadbf755401c455d9e4d3169323414251e6c80257d75870e4e274a2e7b042ff8b6b80270b27d999669002e811308211cd7c74f566080f3cf591656810fe1ce9ca2af33825c9526531c34ea29f13327990e42b45595153ecff4489c1c25b6b5a565432ccdb880534189485903b4b3c05504e8b8ae71eacd12c57cedd28d0116254c725d79529d17451ec12e05d1e468effe2641f5d7268c9ab0db2663505d65ec2c02959937c95d3a531a2fa91f99bbf527c4effb4607f140fe0a0b33cad4fedd87e5702eef7933eb05bbd42c853f022144ed5886ff31ff633f8a5f8f88ab32c925deeb8d12e72de7e92c5db2c4a7b32fde5a7a5a381a631ac547aa3287183371f6d81ebf5432cfb0d93ea3e8fa981bdeba4f5e81d60ac6ece3d26ab9a12b311b21685bbb9917acef5d43c9e4dee2e98811d6866f008b159ca3e43e849d9097d8c74d1ee28b8c6700fe5c2175cdd004f9a4e6b7f25fcb61f562f38b0b3a82693052f023ddaf9c88950a379a0651b23791722f4600d6bafe33b364a0c66495d9f360cc66b80df56eff38261835ebaaf3ec8ef799b54030c9abbc0ad6ba83a366533683a9db29170e074eee296efaa38fe782064a0aec2bef0be52c780c16981bc8c6bcf748c109349e7e659ad14e6c8ce6d35ac6f1cbaa938b39e869444aa08643134e5871d2676d11d205441406e378c26dd1afbb2fea274c5b718d4ac16c077d6e15bc0dad0b3d9dc81e2a1c9089130eaf417bc50fe35e8724bc420ffa1f761f6cd83bdb0bfaa6d0f399026c6146ae4d5d580f4cf490a464461a430d8f40c60f4aab01fab0e35ce12b0337253c54ff1db1f11165b315565be66ce094fc289e6d4b72189d4551df40c6c86878185db87cefdedaf24be22922046674805df74111c3cfb89351e92c01d207253841afced4c5daff0df1864d8e22bcf81c17565f2226d3ae2cd929c234f376205a6962e024ff08a3f00bc71a3d39d67fb67cb94e9f3d7ef78a5d8a7b86585eb8999af3b054d5523b9e4a4d944c7d195d41c286eb95197808"""), - TestUtils.hexDecode(""" -7EBAAFA6D04129716131907EAD0832AD490D09E97D865B4AFC5D6B0FFF4EDE6A52E961ED88DB60A325AFF2675DFCD6A87984884AFB8680DFA7378130E44F205398ED7B83B1AC32D2580570FD6603827E8E4F5E20A27758CE6D1299BAADB8A895AD586BDF7B64F8D7A52BC15455EEF240F22FE98CE4CEAC03CDF7E8A983D7FD1A59C5EC594474AE77DC43EE4E7B25C556BC1D91ABD2015B99B1AF5329DCD41B93793D791A44AF5D83DABB8E40675EB32120C57D9E6B7757D3E03008A2F788336B8355AD2E47E61B39BBFC2229D53BC9BA514BB20F3F9EE9266BC0015FE81980FDE5637B3018046DD3D4BC3D549EC394E190F1BB788619CFFF86C532B4B9F0F6F951C0ED691C59AB0CC438290E9D6FEC9E75BA4FDF12D2BED2CD988AC411310BFECBDAC48A61099CE0D0CE4B44EC9C97108A44E5C5EEC1D3154B4E72B8397CDB0F7D15AA358076E25B7F3EA1E6E80A214051C440EC4189137610450144641B1E71B5334F0DDCE9D5CA30274E0237E45B4D92D7D458ED9142CC23871E56411382CE40D9CA4358B417261C2E7E845637FD2E9B4357E7EA5F4A8076A7C2F40FF1F8AFABA5393512F690EABEBFB73811B974E57C2D473AC22E747A0EDD39E99FD6E5D3668F3DCA1C795CE27D1A155ED9595EAF9061CAF5C55F3EE97056AF6ED90E05D41E90926F69044746230C990118E4D0BE4C12F7A4AA0464F8FFA7CF64C07FEF171B2E43A917AAC2880675F929583E9040BA6FEEC8262002613AA91A2B8D4DBC1D36F23FA9248A2D3ADB1DC5AD669EA219D35DB17C9C25095AD7673445E59DA6CB2260C8FA57639D6BEC8AEE307BD9C96EEF00C93318DF7DFEED970DC1F61AC5C94D4086300D91199C90C95C1A24F7F1E4292A60AB67F30BA990D58C71002D3548A412276DBEF3984FAB312723880ED479080EEE2B636ADC75AD4423A6E0C5CEB7EDE528F871FAF21855C3164469B9EEB47B6D37CFE4222DCD0B9867B00BEE12C27590DD77C24FE640DDD34E9138E70D15F52E94F3874447CA5CEB48573ACFECA3554E2B76CEE4E31060BF132CED8AB953F0A280F7916810A107AB5BA66047FFF0003B1CF13BFEB77526265B98E54E76B891A89F3AC0ECDF71406674865A0936BC57F87B64424BFC8FDC41E471D951077C32B5AF960457E97CA05F3C378D94B60A9735E9EDCAA96E413FA391AA687FD07D9D021B1014CDF241E5460DB08D3B336DEB4CF0AACEA57E4DC6C464F698CFC2AD10CA72C102A25787E0B89249F63406A39A2A792B2DE04710C41DB36B55D2FA789004E593DECE9865771D8B16B5436A792FBAC9934852B1F55D518F9A07CFA56BCF488D61AE355D63BDC27DDED6A56154B8BA3AFA3EC9C01D6593C83C315527F5FC61BB169723346AB4075D09701789268EC1F02EC4A1CD8A5F2584E29F126B1ACBEEF660CBEF16A8E9FF9C0B542042EA76684F9D70F2E3F3C18606ADCB1D695112B129B301008EDD5E6121A8948E1165D350FF09647DCCF4A1F8605ACC750A0AA8319A6685153A7672B31A3DE785EB22E1D223D6271282AC18AEC83C760190799F082D7FB0F238F627271BE62AE5A36A34D65B5DEEAA12D6B14B59BD0C619D8D9A44238AEF1FF83C30118039E834F7716CD59E138E2ABEC2921D9FA92F6808A760031B2157103FD2EAE988AD6CA4F350F488261409FE91B5667A9A2EF1E226B8BFEDDEDB84ECF993E9A71220E0253D2C4B918C5521C7953FDFA00D50A32879FC0A68D2AAD13EE181DD47DB9E3D715574CB3D566BDF30209297B01A666DD7DBC5464F913599086AA2FC6C8541592CEFFA067B287EEDBF4C9B9D6CB23CE1DEED628935CB2D6B5CEFF3BC442B2BCBBEFE4AECFC455A3A64FA117CFD9289FC27E6289750005877DBF64CD562E2E7D1C99830F5AE63C70685B3898D420862A8C4569F2CFDF564EEF4F94FC34CDFEDED8854855F3A4E52C612258DB5EE4D702BBA98B450D070264FF86A440129DA2C126978DAB3341C4079A66F9C23445C5938FA799E78F157656208BA7C7BC7F936AF49D11148856BA55910A6A736D32E0974E50BFA608975E37AC0601FDA7551204EA66F524DD03F44F5DA28EED5D126C32794F1CCE747DC1E9B1FE287CA607F81FE7C795C96569E66B2F3413DA810035D472B7F5AF74F9CC70306A8EC36F1383617D0FFD92F6DEFA7EFE91C840EDF24430B197802979752FD55A8CA85FD8D4FCE774F1CCC540F77C02E16F1494DF170CD8BA57A86BFB086349D53E8A62E1DBDE03369757EADB0E985A038B31DCBEF513D4FF9A3BA6E8338EDCECA7C3E9417F9E133BC399F2EC0C72E60E809F79D55FE1A917CBE28FEF19D6D08A43F74DF496EA9305072C90AE3BA0D21A1AC0BF040920D3F5B8703C12A32A6864382E9CEE8D00CF4F93830623E76197F7F52309824B08B8E0D5DAF5662A36981D50880FD3A8D73D24430A1CB201A9D0BDE656593B37B8EC47F235B5CA251249A04507DDB81F8E5E4E5E414B3750AB168BA51A8873E6ED153E302F61F7159B658E316D6D183575D87ECA30185CF72C67543CDB658AA07B1DB220032DF80D287E769E3253C80F43570AA538EEF49F45316E176F1F9411F3C085257C6B8C708DA7B924B792389A7EC34C7F778E6100333E8B9FAE75A4D1A32E306AEE36D29FC6823399FF37CDD0D11C8D03F14740342B736C4EFB5302C141A86C857309A70BD74DB6C7C29C839F8D86F2A136F67A0FB3A3749542A9DD8D4A062672C75B67D3BDC3FA6B56F3E79008AEF8D8E04CC7781B23D0DAED64CFD1A91DBBAA2C9C4E765FE2FDFE6E8533848E51FA027B86AB05A0530F15C1B7B6BBB268F09A7865E202B1645F8B4267CB1A49A2929410823AA9B834101E9EFFEAAF6E406639AF7D2710E60A84B6205339B0719E05BC6724FC2892A017AF86D80D361A7FEE8C284CB84F5F09B90CAADD49CFD396E6AC36052F5CCC8E7667CC762A9F173F837A231D57584A3BB19671B8B71907E415A1672475ADFA11998F94F28B00903AC551E651A3F9485DC0ABA3297E561E0B5A5786BAD9EC8169CBD706AFA60AE764BFE01EC514623BAC6C4100F707C5E8A02F4B0D6265502AE4170AC3EF95B49ED1A2BAEF56F63D5667C9FC0AF4C0A8648FB6AC5444EC8A1FAF4715027AC9F5987735D1AF7C55AF4C838FE9FC84FF71F929758DD52E2BD4A34237350642C0E641B6710A66C9C1EA1D9BDA80198FCC56D45D67C3511BAC0971AC9B6166633B1713A969B8DBC3CF60FCD6998137AD713EA3ADA84169D49FBB7F5CDE362ABEB0B71D022D9ACE7FF48C9EC1A7E0C72B564FD2C620272A482941443838D0506E2294B760AC9DED5404D3C4D2898315D3E3A82D2E944D537817B9901AFEC343B95F2844CDC4AAC3836E7713739F4201B95C42FB7C99AF8667628C1B60115BCB185754148B3C7226DF14B6DE1AB4C6043329B176C9DB9B1D73B3814FEB89E84A4C91C84993752B7AD30CC707A71339E8A277A5586BA85CD090F799A6B75523A62C6DF1549D787BD8722D1F26BC2C150D6A38951F3014B83DE665B21F5D9D97F2237333CC10A4114796D56D13D643364306E7445F475729602A11F8BEB002BDDF30E579E26F2BE4AE87DC666974E24FEF2462120B6CD8E79D65A2E80542A9240D4EE1F616326AA528E2A1282EF49F0312174B67D40FFCB1370BAC5D1444D75FBFFB6B0887F4573A8C4622082E1FE349B2C73CDC92592F684769FA7D7CE6FB5AEADF38023E51DA4EE3EDB10368442B218919341FAFB22EE80DA96A52434B184D499A4C49317C62F6D6DC9EC1413D01A1CC3DC8853444E52718798EA158A12B72AF023079E5E76F41AE685494E947618C4AB3036ECDC74F7A043230A0BE116F2B617818A2C94C54CFAC964C73BEF969591A3CB2B7DC9CFAC7B4F9B64AB70BD7FAEC138E42908BC90D6ADFFBC88EF473CA8CE7BC960C4B3EFFCAB92E8259CFAFA85EDB7832B3E630D6D2CF031B8CB570E38C101A56B426C654464228D152ABCC6DEB888DFFD7FFDA974E60CCC2AF7531F38A813E263D9B20DCCB50229E7D8F379F81A280CEB90B64BA3657F1E50381B468D0A6608A4B5E107C4736FB4CAA10FF3045C05453EE12A9FB0B79845E077803C69CDCBF7CCF7D6FE6067ED152F67023CAA6095D1748414580232007AB3426FB2889E1BCDDDBA539A2D79CA523A2CD1B1314C87502909DA849BA9B11F9104772BBA27410018348832B0BFDA4F09AF02B351927F2B6D29D9CA9F330266EC035908C9D4023CDF2343B177F57903D37AB89D0F9E23EB0C4100BC6421235CE5FF2729C2ADCAC24D1151757D8C6D6DE53DEBC38FE866142D1BB593974F4D3198C03DE4625F41BE3D488575B25007C2D5970BB152BC1C23E48A88036C070BD38604C5844E4205F1EF3D7FAC0B4B9FB51F229BA322D3355E458C27685130FCBDF591C0520626E5703A2E85871A62AF0CF2DA3468C401644656CCAB33B2402074C59A0EBB57928F548B5FA4871A8B2AF0BFD9A871A5C257044C17E4967B70D0DFB59F1345526FE59B4BD92A1C06B15E3A6226A4821FD614D8DF612A3D2DDB2DB67BAA3878C68C16645CC747BA9B366677541171A9264B89EE18D9D169D341629393C5526C28B24CD4CFCACEA9C42DB2B1CAFD7F906FC17CCE16612B1261E62E2A700CE74DE73174D3A1E06AA31AA05044EC324F026CD39F7B13399D9D86EEB53A6DE84914719EE31AFFEB630F3D8F08B4FFB10016209C13BA2158ECCB4B74BF04EFA73222554FF5EC49709F7F8DC1D40005E91245F3A5E2A00B9F64678B2D8A9E6BF1D011900D9D12F7F3BB023D1E5985BF78F8D6132AF5C0B9C330F361EDE00473DC9EE7469478FEC02670E8659B643B92C5546C32FE7B0AD816A5080B5E3867DC209EA15AEB4B14E42AD58F34CED65ECB3B519A54BC25117EF8D392A85C2895B5A4B73CF93077E360A828570FFA02ABA84D6534F3EE0C935D97D1D1CFABBC0D82E48937797FAB31704588605082A950CAA23D6569AB793FDC31BBA561E729E80979DAB84ACD4EE6B2CFE06D2EE8C4183D33B9F894C6865D9CD405C7665E0150B2B649159BE684839BD12CF0091614E1F821046238DC9F538F769FCE51E9B8DEC0E98442CABD3A4296F1D4331A16D33CA356B11E3DC13937F814D3D6281A746F054606DC52B737AA40422471139867624CC8E9C559BD25C7C6D7F902677A84BA63E8CB817820048C1C0ADB6288000EF2163B51ADD4D758D1C87FFD574354B41CA5AC72228A7E9E9E75BE9DB18FED47C32E3C561C972A67D50A560017BE794AB9BB6B50CFC43D2F6D57E8D73CAD6227C896BCD18E0D7087F57C365FB9EBF5864DFA4A13B6B5DD7FFFCB648C1E1FE40B6A10EC0C45C74504CF2105AD443DFAD1E306F720B9CC37B4A30198D3123FA9FB2A7A9DB3BDD98D441B03E0EE6A8180989E76CBC71B0E8607C3A9E5D20B6008B010702FC5D59847AFCE122F3FD4FB5D89D3A3331AEFB96B593F724C04885B574A43B5EAC70B543BD191BB818768C67A10AD6E2D62AA4C65FA373A19116AD86A4F9A97064E0C0BF80106DE6654B4A3945983B7DDF3AAF1E14A04F6D3035542B0F710352AFC20FEC78B61D8548B9669F10B3D6E531AD07A84C493264DD49759D95A6AFDBEA5AED1C7D7D2AE6D2FB6747151CB6A5C2F9C1AF5CEDBD9CDE8D5993ACF080A0008BABC759A9DF035C648609E610F226ED128E2656A057862246B65C70774B68F54D68073393B85110285FB463DFE394D9DA0AE85985FD6882EF5B11FAEF2BAC18F9D9D9B5CBF0F80AE7AC4418EA658D68B14BAC135452DF271DD3348BC338BC6C789ED95D5C5625762E4CAC6514866613E6D533AB9814B7C337260BF16716478401689F4079644DF4F734281C16164D19C4ABA20ACCCDC517EF42C19A5B1CAA4658C27B61902ABF88EFF0795D2C971608B0570E016CA0568CCA3F7B38FD3DF5608154A33C1F0D70C2AD0EBB134A8F475A8BBEC8408D3B9B0BFE8A6F10FD6C979B13C3EC73F191B788A79B4D07AC45172950689584C909247DC8A4CDD686186DEA16676851B8A7C311439149B1A963B0CC60E5395B56ADF27C25A51BB4A2FB19E14CE66B6D11781E89B3EC22CB854A12D46970D1A009AAD071C479D9C731770D666CDF0BCC381A3D328542F6371FC6F5FF7C4D3BB06186C048B2A3774EAAA3CCBA1342927B498F2195213326C9E393153BC8846AFE2120B8FF4A455B59AF6E65BC0CE9CA3502BE73D74B6CD12A760A9E0E0D26BD105FD993DD879539CD666CF2025DACD481A122627594CAD7C4FE30948412C1C6A160C358E16B6B67653418A22321DF5B1A9EA0DFC3C82DE3B8CB0F48EEFA7DD6188023D1B8B7632270E63AA38873A2C4472F9EF1E8DA56D5328C00548DDC4D9FD79115C5F6168AA98099BA1AAD606FB92F8D253C9A55773E5629E84350F3BC3B00D803E83CC2516C6C29476018ACFF2ACF61584A175E67EB8952885772E6C2D7F9C2B79C8B2F2A77C73C8B0230F080DE716B2A13DBA5FDC8648F17573A2898E72B8850997B6085F98523F00516DC7A90B9C2701BDDFE505A6C330D1118AFABC731A1DEAB813AA0E17708122C0069FB61A02FF6D5EFDA990A23E1D42C520CF1975FF06F123E1AC0B0A86FE666F8843C406F5F1E1A36FBB7A0B41CC641EB49416D6F0AB03CAA6AC0CE3A3DD1977B4D16EA33CF75A37A6092003D097D0ED8FAEE89F761B40F7E600FD502887AD90BE4BA311B9F4CD9D348DF230A2EACBA3FC356B506ED8C357E228970A948FC4983AC3ED9C3ACC22FBFF56783A73231F7E0B91DFED20E754ACE7DDDDDCEFCCF3ACC76554C269D634DC228B38C284AA35C00487D7873C8CFE8E8657726FA845863719FCE5A9E32406E2191B791F76DA035A4C862176040DA9AC0F37E66FB84DF89CAAAE9D8804824725FEDB95E5380DC66CC72BBCA1E131E6B785EA2B2B4A05BDAE01B22C3D47CA85092802A8EAC42E963A62307476FCF94ED7EBE5538A8C6F28A6C65914CF48299D3BA2B89B3008D29CD874B79A72AB840815827566E50627C2C332B1BC60060BF2FDA320FB040FD14D52CA59B24E325B5783BA1BDA3B27415C9DBDAA01562466322706CDCD0307C3305DB08D2663C57F6D3307E1C73832F8CA712402C7402EFEE0F1BD77CDA08F5F6582540D34F1B2809F84EB2F540558EF9ED46D5C636C45856AE57FD9E4650359635BE72028D1CD37CD876E0DC598E360CAA1DCD1F9F2BB4CA27CDE012980080E91B1C7376622907BA6674F1EB9E80148E6A959EC74950A2B934D42B84D739F1DA528F5C6E1C90A238E5167041D4E9AE5352B74C89DAE368778A90170461ECC0D6B6C6C53CE36745A72F79AAA1C82D494BD89D719800A89127BC3FD55247C1A29FB8387F1E3576E0C45F4D327C0B24A75FE25EC6147C890F25E50AB3C43B94F451E5B5D67F8D3BAAAEA1FE211FCE8622600400F73C1398459EA7FC59D02582C2806D01023D84BB50E99AE9ACC217B7223EDAD956FE155152E7F35B2AEE1535885EC048C6E0C50D395B0F1C9D767048E9D2DA7F15BDE192C923F1C74ACE06600628602D1B0189FCADE0873880EE8544AF3E29314E2B5DF87BEB5A50ED72FDC093800B12CB2F870304289A73A65D7E2384EF3A388EA9F0013B2B5C92149E2538542D95FF020A23E976A7DB3E2C9913D87D6EFF12BB51EE298F1D2CFF18FDBAEF56B70CBA35EB9273F1E58A6CD38F1E682A759FDF8D8BFF60E7CBEA948E25DF0114BEBD4AF13E4E0D4E7C9EAAC2C5F579A1AB14E7FECF9E13F20DF873F8D0E090905D32C8F8C0033F5D8E9F1B9FF17EE04FE3656EB66F5E4777B60B047DAB9BDD883EAC31A6455D1719CB475D1715CA0D12762F94AE78CF3C8EE90E55E71D0AA4EBA6216A0E81566F7813E7759BED30860BF22178407783B9A8AAC30CB4D53AF140E33A47ABD60F33EE700C323277E751E5B32B221E4B9815FDCD400DC544DF845619FD733F164937144FC3D89D8186F8B898418459811B3E66796DE51D1373B248A9B3B9609FEA374784A33989FE9F5BB26D2148F7282E09C35E13295D90BBC7795DD72CDD4955E9D148BC779AEE9C7992BB85D8EAFD102FD690F2C679CB7003FC4E182678320738361C361747F49AC6149CF4CDA4B80581844F5EE4818BF61750047C35A4B10697892A80F07E946F357574527FD2D0187873BCE78EC99062C70CB4ABB72A104A770CD7ADBD20894E7BCE2874E45302DC0BCB9645EF28136F36E7B179BD003D5DFA68A572BEEBD40EB9AC1F9228C74A788671BBF4781AA31C7F8699813F32EA8B60414C3ECB894DC7B01E50924482E5C068F0BCA79BAD9F469770FBFCB3942D1A3E54250E87B3693329479217514A8D7B734D256C5D28EF854FC3F234BC671F5225B1DCC20E590D8E5D09C07B22EF0A89A5B863C2E652CC0B1623579541C63CE9C2C4F66BC43323D7000BBF2923F5B8A76933FAF950D2172C1D90F522301D9A0C22F470EB8673CDA0A1B494FD7EE9AC1B4597B2DBC26FEE33A08CDF91E3C59BA4F93E02D010FE3F1C1FCD694F05B7A8FD32D8E7CBC2934A25C481D9C58FED7E0AF3AAB527D6DEF43D53756F0C95B2B58A426F7F61D09F4FBE55D9AF053B92818ED9FEF1CB41FB5CA23AC85B0241900F73971558116C5809F565F71333713EF5BE87B0AC95364C9FAA80DBB9EA84B5A5790D20343141093F86942817D195ED8DF4A2DFC7F7090CA3DB46A92AABEEAE2D7DD8B9110F23A89E4FA7B5A1DA27D643BB879888A2238E221E2F67D9DF58E73C46023FB7E999059D3B81FB753B2AD333207873831AE42FAD8092AA04C0E4103B1CE0DCBD6B06CC2F0AB37CD1D10EC4C83428CDEF84041D12BF9ABEA5C80050A853CC73FFF3076BEE68078737F6EF483F486215118C640790D0CFB4C6E5243691FB73B1294E0D3A494A4A538B94FDD2746193D9FEA24C1C04F5B20D2D40B638CB932C35D953A9D31260B76DA878FD52EDED058D1DEFD9CE214D14C3112FAB00B7F2DC88F7EBCF79EEB1C9C8607D6919B8D32CC8416E2B981C141198DD9884DC3927EB0192B6361AB556EB3977E5E242E5E26BA60BD42892F46F3F2DF684D0D9FB41BE42C04F0C248938AC79F110075B42181DAE62801DF76AAB50AEDABF4361C0EC597F31245B0390CE2629DB933E450E09DD39E6A1B644B0FF672B52ACE2AF52780D3F6505551F52045028C4DEE6D1C6A34BCD5E95E9DE1BCE849643BD07E0E6FAF8B27504F859D73BDFC07FD2034595AAD85A9DD9AA5B3A72346D6F3C4B21C4CFFAD8247C8CAF0DD9A708E11450502BF3C28EEEDCB0E1D32D3EF1A3F6237E34C0E4D0222F496839B7374EBB7D786973E85392AA8FF2A9901D076DD4C65635286276698DD4388F867D1ED18650FEDA9B03C80A3B5BD0AB3A62A45ABECFD55898BDAFBA58137D4BE29EEE8B3B3D1C4467B63DBA1EFEF2C81CDE7CFB101B1E65084A0E92955690C8CDE6F93E23FD79B76DB475CD24DD92A7504510F8DC3B22EBCD0288B4E479F8DD835297B196531D2DC759364306EB6780FEF31C9E34142B55988F81312B310093F77CB89C6E819A7CD3450D0790CB7B5E33A3E5E51DF05A3BFEF63320CFF072D450D71E7239AB24E4D83A8E8E501A5BDBB041219E15517B15EEE237836672A761D36D11EC973BAF65320B368906392E2689A9936752563172B3A5ADD90066E01EB394C77E40D57553B883F446C42EBB9CCB47FA56816B06AAEB62C21C8F57F926420AB7C1D5E97E73F024C259011CD585C23D30F99D22197B569D67BF5965887AECF553A9B48DCA0C418778AAD65D4843221B8217D2D61BA5A46C4F9FF5B00B78CFA8B6496007A1444503DFB8D7CDE7A63D5D7F54EE5823A33EB3A155C20F0011304068CE0385A09170606FF6895A6955C211AEF5D13BB93866C9CF00A911A4A50A59133113A9C7DC53409097808A6D0DC44A7776B41A7A43818C77CB51F3E20107F080F6682D90399853104B8F3AC4DE8521048B22BCA58B5F7B5EB3E3503F638C1FD24568F23EC8C59A3359A5C9CED0305B1B81677E20EA35F9E896E665D3CBBCB6155E1B0539A0B26BF95396DB8548124519B71BEC19A17DFD4AA2A2E134BEFDCA352B01E1255A12377D811FAED7809C9B881B24C185F1D1273F405F5BE82FED08F26E6C11D39A604E88A1EDFAC8AD3DA9FE8B1111C7E038A14CE58B9598AAE96B7BE84C153A9B26993CECB1CE931E0CBAD5F7F6C18B68E14E83A6BCFA33AD2B3A707118D56803A1E55CAC8AA93EBC47F9EFB"""), - TestUtils.hexDecode(""" -551742a530ae4d15d68f1e222c8865e6fa59541a5e4b6e137197b52a5cb84548c099c3328b28865c34e90095e8959c65f68d8e4ef9e9cab97590736dac647c93cdec474c3e6d1c934e2eea593479349b6e56b95dc356cab1e2a2a7a94dd6490d9a186879ab75f16e0bb792863a7a8a19ed88d74d22f7c17f3b55b4d6440fffd4c24d814d3c09cd80b3d3d137882439f628337061253522775d68c1072b8df9403ff65679d24b06f1a2779ed76ca3ce153c264a06cf04948eece4f06243f22898bc815a90344479a8edbee87d0c5473474b1b588006f6dce5be82c7bcc2db7b50fab4c2cf06eefed93110aa634f6691e9b757aa8a01ca52912040a3ca6cd6f9c596eedc0a9d49f1bbee32eceb2374336f07e74b425d6a894f8c3e49a255068d08ddff453dff688f9c74a2be872e2a205018fb3e0149113ce438a7b83e60f536ac616d748fb2c590f3ec7e4c81629a4fbd993ced51995432cb8b3778f7d4e375fa54c9511e8e97323ac021b7cb2184bcce98f87a2712740ea1bf33670c4a718b475b31249ddc1a9c2b216efa7b5bc01f792cdcbd07f3e7719f71b81c3a31d8cfb7dc07efa06e0740743c9bc515c0983c845b1c7b2cfe7745c8d0e6967156cd36e88c8e3eaeb3c96ede6f94a53eb05abbd3ce8abb9f4d2c350969a8d5fdd673188cf5f8da51704b7390d8de842a18f5d900da6f0de22b9b4836947acd4d49de53e6bf96295c3f89a01070fa3742ca5070b56afd534fd4bcc280bfa5233ba58e3bcc46cdcefb5a07904ead0092cc088e8ef1de2ae418a8f977dbba6b23a634b93abf5135504ec8adae1647042210be6e6e0c9b333c3f1d0dc906ea63eca4697823fa06cbaf999ffa6894353d0b886bc89b6d8b80d88a80b570aabd37e8bfebb692a61ef6e344b4bc5d10a4d4d7aa2b2c47935ce37c1f2143be5df3d55f9a947c1d7244d80a74e92822a7e178229d703ed770a3a2e8e07cd465d6b4fda758867bf09dcbf050203796ca9a6926196f13d8a5d034f566522954999ab327307189e0791866385a3eede8b8485d6c673ca69452d0a7ed6a32142b74115cd39c797e48f38111b309a3b5a122fff1c8afbfa7eac2dcac8cf225c971b88a49e845447ccfc634341e2eeb214ab57de15ec8de38300871207d8bf98a4b9a44642679a67fc1792a46bc051cbdceb15b4355f56233ea87dd6613afa535b333104292e946ac29b73d04be3b83a0a6afd275fc02d99fa0a0b1796275b45aee6fbf801f5394fd5bb2670d18bba553e533d39d0e66ff194a7555bd23ce14ecc97ebd99facaaeb8a0d0e088d2b9bebbc48b4fe32da39a310e28150936dc5e86bab264baed9721beec5a6ab21db810f1bf539d4e6283b7a382984595eabb42b21aef0a1186d66c988132b0fcd17ebf0bf9347d64e334e165d1e8107f6b49403d77516f55e973469ec6d3ca2ecfa2df3c7a82d08ce5875e4a0997ab9c4189e1b4c37b5567fa7731d6981d96e9fdc35abe9ae1a4ab30c5b329cc617a2f92cb91109738a7a41da00c48eeefd6e003d3e25de538bf85d83a4610c0f86e7af160703666e6fb525122ecbacd13242679cb02298777001fa2ae853ec73eb581229400c93408644bd64cac57854113aff1fff6855e2632e1e47bd145865a142c9ca2000b2595fd4edc7a4b4cced9dd87a596a9e245c25fc87a91d676fa0b02a237f895df9dbf2eb099a60fadc4b8829bbf7aaf94d1fdd10dc560244f0d6f5394318497eeac7cceef0bfd8316914f766396d9a5a7cf907866f85ac6e188133614490e1031dbb8abb003b2fe2995a28fac84d07dde5987a981101087606d6b4d4fc1bf7b3cf56f667ffdfc28adfefe6dfce01579859b662a189306cb048bb4b8d66fa9861e83fb28c325b89abd6838e71e5ebeead3e014f40b48a36f1d468a4a24954f571f4972afdce0d6f9dfea1cb500b6212bbac96e7a3193691eb0823a48e6f49b63eb4b571dc1b60654b6a882d84ec4a10b5faff8c0e71bf1548578a8bb4b772a9dbd1a76792e4186ccaf692a5cfeed5414be448da61b1abed7d58acf60c60022d6f87f25b291c226bd22c9445d15e2dabcdebc6fc91d780493865f4dfe420932d9a106e81f254d97b91d00efba45517edea7c8dbf369a32c9d04a5d141d3427c68b19f189af86b3e2fa8ff622a14947d4a5c4dcd12d3e12c714b32075dd9a9c35e8edd715901559efabebda589fd123d0a7ad33bb67f353bd01c4ef51b26a187986edf0ad892b4c71b2ceace37f103dfa8e933bc422a2799dce9b7ff3de92b578e065b79a8e7d4c028002f5b667886bb783bef181f4040c5b03050f9ce2b9cda0787ce21675222dfe20c40640a37058910069a0cc037ce13a2bada74027901a186b5f194792105708877eecf678aba0436c2dc304e8fc040996e488f764f3d0f52056edc69b5a6e901bb0dcc75acb8acc9f22249961cc5df3d10992a32d724699120a264cddf1450504feb09d82b0181e0148f7ea9ba61e99bcaadef0912e1c545ba9b97a93c9cf5a8c29d3ef2a2608a32684b30ee7d43e6006e81c37b636616e736a019e26079d3025b1c5a3997fd9021634627964a01786891218711daf4812cda28892fd4803dc5ab334f18355cae65eb68924ea9fae67b74ade42b96ebd43010dbd0536f7224fff388433de015721b73c60d4dfbe1101100efe6e69965fcbc8eb442a233654b94f79ac0dd967612fafff60141e1fb714a3e88147072c2b44ac434421eb5295a9ea7752abfd6dfe4e10760f0f1e6e486172d8d4b092e043d085c800a58f5c6882e37099f21565a04ff5c12ad4d716b30164d8951f6cfa56c93388fad772ac2fcbb80276a235fb4369f01c77266f2286b61510eebeccf4a610f995c850b2ca952c27875801b692f8c1ebb61758c44f97ca4628837ab1f6807b57ba56c1b2e39e1a002dc724f06a3fb1510f18b37b0b48dfc21d453ec3a576fcd3302ce89f313ff2aa895f0103e11b3c01291c112a4d9b5f67b48767dbbceb8e1a0393dc8fa7b0b7304a02e30612cee891cad631778726124860518fae5a1b162aac95a6a3aca66e1dfaded70547e4d934bb01034038a23f63e2695f554cda78d42808c750ea5dd3c7c34e74fefaa93a91ca66a472f2c1f8a1de3c6e876fb7721105685639cf82ee003704637125e9177cfd964acec7bc1474ecbb0283e317a03696bcff64e4bf6e58e3893c7fe4d41886690b29c2d6f32ce57ca25559c3739e14af58af1d96f581e469f146d727ed4ff89425f4be0f5384ccfd5941f6c859d6d532126dcf4529564be166d880b4d5b5c617173778197afc8d3dddfec020c17373d494a5461676c7b8c99a3eef2f3f52c2d304160696c7a7e8384919a9da1a7a9ddff071016172229405d707cadbedbdfec000000000000000000000010233645""") - ), - - new SigGenTestCase( - TestUtils.hexDecode(""" -d7910e2ff97acc1d1ab59e023ffe199ab92906dfd6ab2e463731ae484d0393ed5e0870cc0eddc5d81acbe1f76adac417fbc11eb77d0c7e4921068792f54c5aa194aa933197110060309ab597bd1c5ce33101ab6e50fe871d4ec627437694d6df728d21ccfda87d828ac5950e846a311e48103071ae5b66f3155d87e68c0a77d70c964008122590b029e1346d60820c40480c0c428421424a1c364d90a06dc1004c4016895b940c94108d5bb820ca420ca44208e32248024722e2202dd4c444da18814a806c54167208126591a2500a012a082284d442284ca86814098c5808281a830188b88c0a076683344662268c21122890b04891204059422dca96650ac44c1a426e02a38d021944d826208b107111024103a44823906c64021049844803c9499c326d82c04da100651897214a3685e3844cd4464e8148651c430d1bb1901b067121434e0a864453c46cc4466d10a2848ca46d0a022d19c76113c311d4188011879124086e422221c1904850369022a40411396043b08001c904134146013188d1248e91408401110e903682e2a2459810661b858902a50cc044650920494820318c388dc488001c08611c07225136068c466994360e0c200622096599346a5c8824d4180c63961024c79153c428c204815b948913212049922ce2822518c12d12994558a881990871e33432da442dd2342518274d622630981248a2805064a491d8a0480a25511a03458a30865b848d9b8850a1b69008112a1226441b9324a2146124107023a20c08233004b16403490a9ab86519a105199464943249482441d2b025d008891aa629d0a48491940989284044266041182858124ce440828348251113694b908552366663342e1119281bb2010b327209364e020142e32066232661a3248a20910820989144b6311a30020b994810836809290a0431300c954c50808091306501c325c83241a014044b444ac80852c22649c2128a18054c14097213092edba60de4220d0b2751109760dc1466a2c45189b26994384982200e84466dc4848dcc206908130ad2a44152b0092380210c121209820ca282314a282c21c7850827248a062c2195648326668c2031522020e42250c3324153180613836400c121d912808a94414ab065e4a809232190c2060013362e59128d238930081968c0040281048ae1206a0a290400466c0b3885e2486d48380e0a412e1b932422234993a8655a3824d4800c2042512199090c302aa2a8211b471111c38414b90dd546a07aa699e317ddc7e720d95e02563ac6dfed69d7b6f0091060c20f3dd65d9ae0463516f8ddac070d5c8f9cfc446f7a279b2b6b10329e69194903eb9ce9aea7b23784d6a267b62edc162970ef7b885ecd1babfe34b1eef17cece401a53b3c0a48c906a35020632709159c48bad06c7c1845ac966e4bb4c549ea4ded612acd9369a8c8852688718548f41f7c36a22325ec219b94e3ae3186b97508fb004848f1eab5f4510322b634d92bb5ca846ce8b691b2b0e242a522a745089f29253a5b3f812a054e2a4403ea7da12597bc66261bb6e2ad226e91d543fb40dba3f1dc7abe57858ad77c083c1c775108b1f2779147808d9cfc0eb56b76e129525cbc143124e7ab4fe9dc1ec8f9ef61e37de3d7fd0ae9a1980360ad141453b8be2e1b845b9f6ba64533f532420ea769fbfbaa4036b7956e971a9f71d32c0854aeb911069f2486ec8a52e575d53fa0f4bd6b87c3d6bf364f1531a3531b04db09f0b2344640cb3123a05eb8edc7c23474114c3663897e3022d3c1c49e44ee6aa0da201b6d7480b0a4fe496eb3d1abb932e7b246ca9fcee9ca2de6daf873f24a6928d3e1e42ce415d205fa4d0e7c44d29e728b845dc0d6b3719c171b5aed9d539f94328a23ff125fd5a4c048d6b70084ff3a96d5433807cd011ea4886669c2875184d644d88e9224cd2c78c3a6c5450082aba8d25c86d3a183bbca15394a965fed396568c0a11557c87b8bf7f797be047a844593267ea7b81fea58cc0ef9241a8ceda3fb2c93a28616c8aacd5c22e652c58720a2ee810ac91090ca53a10d47c055f5753373e983c457b914eea12a78a55d7f9a37bec0a609337ef580aa434e41f9030a3e9e69c8bc0eaebd1a987946a6ffec018eba885994fd64965b9be87b59b13083ce43a5d86bc5b2366c90254f0a598fb5b78044f67703bbe49657bd8da1f1e853381c05fc43bde6a0d6a952d281f3efcf9db89f8ef00d21b9630e604d27ae41d09d3e4c02953329c31829cfbcb3bec32935f68b9d466320d7af551ef29632f38d2c80360657572bd76bf26ea1515b4f31494a89c06b487ed546aefafe5620785a2654bbc15da74487898819ddfa07f648d4925626582e244538a0c3932d5e04d839c008e5e3538dc66a9ba917df7f4ade6d0e13cb267f15bc6b2dec78666a49137d13464f8707f08d525e5a70e3eed15aef54e9ad1d96bdfeee080d7eb022d79d54f9c194d41f626755a36048edfe6dc9aec7adcfc099adf527cd46eaa3e3371d7c17e4f34c6f6e0cc4e63814b148a4e8d9a60e76648111a8056405ea4060d0f6e042c3280d0480aaa3e92bab91085bfab153a1cb9a5639ed18baeeeacdce1ba2677f4eb60933111d28f8d09a558add70c6a62cf9b665227f6de4c19fa1b5d7f8bcc3a48458e67432ecb12bc6785e87f6b4838c2b1dd87aa56716dffd7857ee6155ebf64cf721b40ec05d2829a79d4d3f07a818c3e615369e46c6f475748d254ffcbd8f971523211a86bfb96f51bc6d7443f2cb2fe1ad567f8e41dc1a3a27455197dc3d8f66592497826c63b7d12f489c167c400a38d45a9ece1b579462850a3a04087b974cf0f6aa4f2e86fc17132ffec7ae947a4b0274bd54cea6a12a1225676d21aa7c72492a510947198f5c9f5ac22f75b368c74bb68736fcf4c688a41e09bf3bb06a721b71eb1edae90c93434fedbead5b1d76e0790d0f99140d328a338f99fd788c719ebdeeeb4a6fd793f7c255ad076b5bd2bc59fed6699b39e0e5f8a03bd1ad76dfecd16bd10324f1b0fcedb3030d09184899ccb6aec4ce031cf0b10541c114d56b760dd6fc630d7a77dc98095239e2292416fafd9a2cdb7c2fb6eed1d971c39cb7efd7ab31f353255ad342e9129534f769640f6808a11b173231679d244880a8541c299cd0caae9bb61b90ffe01f93395fab1fd65a0930d285d1ecb510e8de8ff93b2b63614b0389d7332f6f20b61737c29769d0a05e472759dbe68ab17cc9586f07d4c2beb47e609dfe2a00a27dff3db68a65784b1d9b4ddb1b454bd49b0adcf63155c5c7979762c2248a0dffa7d31c8486e1ed4bdd01155ddd4a5830edabc74c509bb79ae6ae3c94d34e4fd1e6944d41b8ef5de8cd11774878bede8aee51b87303a502abb5394c8dbad7636f0c71aaf4230772441f0066094421550d4010cc2f71bf055b263a0b53bcdeee45b7517eaa4e3b4801b09bdfca83b45c68c52d8f0dc7f8aff1aaac45e1e86be07e61a6fb65c65f1ce21e508ec0ba3477c0bab7ee1c211e071b4449f3ae379e5c46fc4ed23c99de77e5675a026c71a90696528dc29998285f6d9a411cd1bbbf3fcd522713e0941f92468646dcafe9db8a"""), - TestUtils.hexDecode(""" -3F1B179FA452CFFC1F4776B275BC9DC61A4448989A5C74AA4F6A42748E49DF12AA62C5DA238BAB9F4309D563EAFD739B54E8957C0E91DB05F63B2A50F11205F5AB60B0E857F1AEAFC0562A76626AE579BA3387943E8B735A4B1CCBD23A6CF56D7F38CDCF772ECFDB7CD40781EC2622C10D65BCE780852D7930281726CC2B83C8D8179D842CF3DE761B071A6B04A383624398FEBE34CD841CBDF9C256A5EAE3973F0C256F89665A0B23F0B505A2EA73F37EBC11AFC2C3D4FD8626EB86FF0267D00DBC567796011E5548C08208CB0B43A880C1590CBBF0549683BC71A8BBA2CCA5F98011E592F3B5D7C8CCA0165A58BAF8CEA629CBA860511EA2E86B4CD9E721E8D7DC608504114EA98D016C0C0EF67EEF084B8FDD8BA4825A0615F7E09C42D935D9AF0DD847C2435D84B4702ABA573499C9088EB21CFB97E5B5A847476FD25EFE2C2763429048F797FDACD8238937024E5D66B3FB40055C3DF19E213E5941095CD8FA62BCA591007D03CFB879388983D6E7A189782F36F88EE409D490C5FA66B62510AD0D0EE9EFE6DFE23139944046C62EE639C0F82E6D850770A69577DF6034084DB97E4FB2BD206281A79CBBFFFF8A9E4B70252F6F03DE8FFDBFCB0A5267877FED3893CBE5119F0C6930FC0DFD82C63CB1E7DE66DF2141E184646151CA8A927DB49A3EC63B3B862AD60551B0E562F35E109594E4E43B192BFECF066B3C7612BAE0E170F0E1D7D246CCC3A2F94D3FB08BCF9DC7DC44735E258B1F9D0D8152EE79FF9EF095EEC3FCD872D9584361A44B9BDC88BE2AEF1158D1765EB4DEAF441F2407039E98DB8D148DC8B7EE9C44D5833FFE4C52A077F57D9E36CB220251C58F61759D18E4E449E72F29351F6CB08F9D996005A33EA695C21FE883E1C3BC3DC3E8239F2BE16FE445A18AF83639156521188EDF3F15ADB300A17F88C829EB72275F6F35D2D1A72B79A01A50F1A63741A8B1ACCC35E49D331DF670D30DE8855FF27C9F6D7BBD16CDE4C4C4DD48CAA971758D714E89DDEEC7CCEBF2E89F8CF03D7E631B9A18ACCF19FF35AA24AB6A1E10DF105FFE2603C30E16B7194AD615038FE96F4767DB8882D48C97514CEC057EE636C9FEA31BDAADC5CAF6239A805BB05081962A2A5054D9DDB47AD9D3C98D053A5199A687668425139998BCB466364F656B1AD9F13FCF7FDC50652841EE475D86AB89D0CFC01C6B5B876AF9D0312A43DCBBC71B2714B0C3226967A3D1E0AD7E9368EDDEA9120B2C8641EEA203F2E943F43708EE6CDBC6748A33E3DBEDA2AC492A6DEBB9751E7AE4AA33F6ED893AF7054454467E29D7EB7F2163FD24F7B5607C2E77DDFAF72E983AB532C6585AE8D78757DA904D1FDBC10768E3E70D582F17708B51D561C24EE0D5A26559EADF5463097155540F26EBCE03D89F49D7033AA00E1DA5ACBDF148DDABEAB739EDDF99A6B2BBEB48F83E3516380FC7AA9FFACA8DDB53388485061EF5B94E92443C24DDCA823E44A29116F346A22BB3DCE7022C3E2EF35ECAA91CE5F65D7C5EEC85D741ECEBAEACCB39F881391EE2A06BFD7B72173B171B7D11C8792F0A7D9A125011294296B157591A675649716F92234BF074F78EAEFDAE1AD79E4208C6338F42F2A9B105EC5C717301C638C63555AF0A81F63D0CDD04F9C22E2FF223CA5AE1A01C7FC61E9DA4412E80D493A7C0DD49CAC10C62A7D3ABC1B9C74EAA2D8AF248946EF8A37F1F7017E49D11B89EBEC111D85D7C1512EF4F99BFFEE68FB588DF3F39735169D1B5A647D71F52F76C6BC09F5703320DC92BBBE6D7CA592566483636957D235F5D18150B6A4641CED6276319244CD8EBBF74BC5DD3AF82E6C1118D19ED291ECF84E4EC2FEFF28286898E9659B01A37F4612460B34DA8444A4805FDEDCCCA5D6D8013335B4139101F28090517FACAEBBEFE59E44A969FE3B8402D690012AB908EA590249BD9354D456EF65331608478B2050F985C5903FDA5AF0D918E7F7E167C3A669B727DF0CE96B63D4D944493C5D2BCE97F2827CAF54103A18CA8CC0483BC8B98C42657349B8438C0274E4401463CB55E93023BA114FF8CF3A718740756DD8C92958BD07A304FECBACA3CCA8135AAB901AF23E1104E202395A08784873E03FCF2D07AAB003E6581741389C238942D7A2B9FB30B53CF5D0C408C0EDFB1C4FF448D745FAFB0D659B4BB76B16D5B61B0A38039488682907151802A815AF220F82680E523E838ADB47425369CC421DD36C2E60100A9EA7F29B05D985D644A7FEA573BD24B922396A481E33306AC41CEE9DD8ECCD9DD7833F8CC77477EDC2E97A72CE2DD930BBBC58FBFDE78DDE34CA1F8DC758CFCF2ABCD35CEDE0657B35583F9C016524D3AAA5E698BBF85AAAD01D7D3CFFAD4602858BD7E2F173D6A24504E448926DEBA1F70F3B0D5B454B02AFC4D0C482BA8019A0C209ED071BD2D5B341EE06FAFA7FB0D1FFE77FC6F6C49F78EEFEC44999E4330BDF33021EBD91DE8EF2042FE4C3F19E992A5E66FD9BF8E3D428AAA8FA51C7C761C2CAEC8908DB3066D50BBFDA98B82387E92611514605D6CBCC0AF9FE08B39AA1DEC89CE77987BF3BBFBCF362B4AFDF12A8A1ADEC69962A6FB26610C816F023D87E648A77DACC3997127AF770658921DCD300EE2C8C0916593067B3B31ED1B6B73D68EBE68CB22386DE39E57FFF6AD766193F99CDA751316A5B0729FE5307C107FAF6DB4CEF4B1C6CDE957DCD6361606A6606BAEFD9A1AE08A5DB21991F022C4BF758D16FD53D6CD41F637F5569D7357CA048F07F53C850CC56A07A4C2F3BD04DEAE79498EE10B366861EA82A7E04B9202750D4FF4017239BF1BF7088A3F2E2C79DED5A12F75CDD754840868754428BD7392E4F01F36E3B450A9BE5BB95FBA71C960C7D09DBF24E6662C86D8B5C3E37D76B16845B0F88C40AE7360545B3304DA5CBD2B58C29F6EDBD794E9AC779227B0FD198EBE3A172FF4B8896F0C9BFB7A4FD9FE6ADC73E097046FA25CDFEC45CA1E7FFC4FD582DDD8C79A9F3959A4DD7E3473D6F242B0A6AD4DEF109C12DEC994F2E313EA1930ED25CB401B82212E86150BB53BA88138AE3269157FC2A7A919E21CC068E0B9E934701B572AF0E20FC2CDB2B7452CC1E5545AC4CDD34EA0097CF531FD92E3FC38CC50E1FC8ED59272FF3D631FCC239E4AE0AFA46419863A166DAA2CBC63E24C26ED7EDAE476A194F8BFDD540D640DB3A8B294E0DF0AEAB7A735589E23CE524F534AC82D80CC51DFC08EAE4FD02E6F6E0BCDFA0FB23697EE1AFFA735566223A70EAD827DD31881A3C2471677F905B64E6AAE00467561FDD6C79B45016F1326D705A854877DD91D0B147071B00C5F8A600116487D39284F6334FF56F124951333F723D68465B765B32B396FC4C432D51E8C6A9782461EFADC2CB93EE38D4945833435E2E27E17CA98998F9B33057B1C73E2E43B6A184868DA05559B3050FF42C76D7440E1A5B803C8D4B0CBAFF9FF31C7E98FE2D011B3F87416889A81DF9F48643E943336430602C5B44C1D11BC7F62A0D67BCF9964815CA0AB83E7A87DB714F2C1872E5B9F0843B82846516E54A3F7FE311839F4910AEC6CF0D23F86BF2B0B05BB71B5B47E93B80F7060A350EE4D73EA09A6D489BDD064763CACEF5818B319CC973FBBC78E01A505A2F6C4F6812819E02A573AD8F7A345763943B623995B0634562479072D9E42437FCB2D02479DBAF2D088B31EE870F11047E965D04524D0CFF90B943B1BE969DE752249E8B48C609F14FC48692BFF40EA6095F1967DB766C8B4E18FA73DCFEF18F2DE1D295B51A63880E288ACED85B188B3D10A0B025BBD934BA43A5AC5E1829DA836EFDC88F4BC6BA0F4F23A4AB16DEF3B5488BF6C974EE1BBA51D17BD472C731DD35D5B74EDDD3C9177A3503D783968BCF8A1F2549F70069164C965304DE2434530B3841A2AE7DD47DC5FDD9DE046840B4D65A08A71A3D15778865CCA2418F154403183FD44B622982C64F771C87E18C09489493E378476B3B1C8D14C8009ABD3D1A51CF806189496A4D70FE857822049D3DCD4CFECC2F95D2A8A16D94DC6703B4C4EF3E8C7EB9D6859350131E1A03EC8A21E13F045F822C48EE3E3A481EECCA508F189954AC267E6CD19C80F8688410E2E97C71A6C792DD6E33EAB2FD16B82214588B923AF6C6069387F6A72CE06033913B50F0310112DC2143802AA2CA066388C96158AC154C33E9BD72C993B410FE5E9D7CF37A30EB85A127A7773ABFB416419A5B4DDECEC10E2EDB312C86C3F3C8BACADA66D057FDD40740176D137B1F1ADA098D978CDBB938F45D4B7814F2C5B894CAE249CA8E1FDF31E81997F7C55B7A43461F5C7C9893AD0494F4F0272FBC20D80F327EE55250F9560A301078BDCDE94D72A7D113ADC7C739D7AC2B8775D961F89245C5AEA8ECEB1732FA345FCD84A0C07C65F091B4B32DC4E117D24D782C404E8FDDFD6E9E65B3633985D6DB8CA841B9F9A3B3C617F1D69FB454045C5024AD09C5C1080F3EAA64202C08838B42E218F56422722536160F97ED3C08F285EF7BCD1119BDA59DB5EC6BC8E9DC1789B3CBCD469A4BCBE1CE237366A5B51B062D0A08201D4F0EAF6F8FBFFE53F35999763DA2470F2F9FE79BDA60285D052D65DABFBC43659DC76602DC662A3357BC3E4BD07BC32AE5B5E94D7DBDE4B5117BD5A9E3461021A569E200CD3CC518ED6559BF2539D8DAD74920DFEDE8DF8FD8333FA17F0798A17B5385A9569A640685D7365D3DBCE8411D44B17BF79B852B1348AB31335AE013B2877C1D8AF62F88C5186B7313F2C8736472FC5F2B4B38F761009F7623292EF14A4A4006305CC419A3ECC73082F63BB2CECE6A624C2A6DF29DBC6A4F0FD3658C58EE694FA58741DED54889994DC6A3DB4FAF5998B577EFA399E58D822B99623D76050736C17B5218671FDA3BCDF7E81B3E85D87200DB9150253ACB07AFA8FEAF74578125E1E26128116A7446C804DE54FD2D2B1A48E684F73AE91932A37372DB66A230AC4CD54869A0115895D2CC494E6D6E8B12845551B4F3DE0B3A4C114979F0471311434BB3784FAF7F9A9B88D536235543ECED732289B383E8005D98192FBBF41EA8026CA3A14B6895A6EF0548EBEE58C25530F56E0EFF157DF6ED0ED0D5565E9FD474B38EF5BA74D24B82219F317AD51F3E7D6F8E4BD8836B91525E162DB417C87E36B3C0FD874FB4BF4136926AA6D045033C94FD1EDCD69835A116357F341372148C4601CFD84BC36A8E5B2260B90CA797CD5A41362C44B4488399394AAA431A63A74B774E68025D7DCB1963911F2BDEEA60DFB24E87196FF38479D235C98E83F1FC419C87F708677F98C84F9C4848B255DEF2D92E3506A533D36E56DF81F6461AB5BBE9D171ADDD39FDE7552C5D4351DB59543C0FA939ADD6130E25D4326566FDF49CDFAA240BBA0B027257D2ECB83209329944E8F44AB785560DED2BA8EFBC55CA31E48F4C94749E4D205A50BEF3E3F039DEB3EECB213FE92C1C3E98A9F72B6CC316D6C0B87BE7F688000A2433E3A184A68722D44C7F6C90F2AD0B248AFC9E57448E3450888A875CB3006E27C232963740B985484E7FEB07775F4B4FD89AF6F627CC56CA1AF23E3BDF61443786D3F04DECD3CF71E2C6139B584F52B6B656CE0737F50BB270830B102B781E621B3356CA16019696A23EEB238ED74D160269A3EDD35F7ADD9E065F836A61A0CDF99272956555106A349166B2C299B8D0066581DC3608048DD8BC2F267BDB2808E1ADCD37A7538B9435E9E5D7ED4389BD2CCB6E926A927BC6DA19E8E0E946442A6943F65C56E5AB7507FC6EA1DEDEA7C1AD087CC005914CE80A241D42C88380A49BC4B6850536C5A99B6423B77A75FAF76CB17479EADFEF1FC90B832C8F36D92BA3E927C9D60473117267AFE4B115E39D50AC7991BF248DB38E8C99784848013B48D4CD6E034B93E643239E78936DAC6283DB748062220071473B0579FAC64510D033525D786778C53CEBC3BF95C4FE9406943E9D68E17EAB3245C57C00D0C206E3343D8201A2F6C278DD61D0CD42B71CB7064ACCDD38551DC554007F29E1929EBC81025CD1A5AA41510BC5CDFF340F42C4FF6DA37F8E97F5911F37ABF457DE3EAB6114DC858C0C14B9BA5B652DF63D0CFFF4D6F8103E0FD15D87D8EDCA53FBBC70E3B42C410F379BF77DD17F6FF57D7A0D01FFE0044F226F8D65DBCD1803928B29CB6AAB703A0EFFE4EB47329D9D373954F0F15CEF2577EB8F34665FFF2C774EB07F0CA72ED27AFE6EDF158C3AA193F3B5CAF99F52430A3662997DEB386DCF0A6781E42180ECF44E9043AFE95BDA84FD1F9EBDCE26EEC0A4A08D8423111B320EB87156BFAEB3827389108E12E7AAB3F6CC8EF67A7C877BCE3192E503608D6F1E5697941FC1418C16093A55A2ACF2378590F4B0702998A65C8127F13AC98BADEEB32B152F3054EB7D0F200322E40CE632CDAE8F0E6C22497BB6D464ACBE9B461C5D39AF9334F5342FF31C9273146D20F5D4BFC61F980B1862BE4A147474DE89A1A3278004F2CAE293CE2709748507C5DB48D98B484CE933DD3E925E1788F2470C91177ADA3869DF6FF81308DBE846F50C51AD66CBEB2AC91DF1C86EC22ADAA6C702F1CB7A141778BF957663060725A5AD6478E22FC959FE5C918EF1A11964E66B1910018DF4698543CD3015E9876AACE37988370135BFD7047FBFD3996B45EFAB6FFA70A4191F259B8A27EFA05E7E1C75285CF70910465589B41A9D29F51F7BBCE06457A3DFC540608157479B499B2F0CD9D8A8D6F2C01FC79E5079597FB6E2D1C3394B8D8AF65DD133F9D9300DF3DA3D740CD0E7E13EF62BE1D29A3DA6745A5A87558F23D89319BAB09A15F8FC01AA388E1FDDCA117A27426D142094A11E6B49E2C541A82C685D41D6E2520881534012774B4C01CE3D2FD8FDAB8C25E4F0AD1292974C4C141173CA219C07314314FDF94A05955E210DE13F0165C990227EEDDE23A52D7F4C8A181C996D0FAF6C313EB74BBEA4C2CEC0B7B01698C63C2E1D37313B637271DC49A7EED8542EE8BDF7C7D791F7BD59A029419616F9C8F478F060B855CDA73418D0AF090844FC0066DEA9DF8D4F3C9ED58CFED2A78B427B42B033C46485B767D75526DE8682D6AF0BE91169650BA4ACC4D54E0D357E993FAF358BEEE3F7F988381EDB31FBF174239A345130BAE1B0DEAF27BC5E1DFF86B29712CFFAB670D35D19DC5B25DA43D481336C0CCC2120427F30326FC74503548344B585C082A78F96F072510D50E1110EEF01617282CB681CD352A23607C3CF7AD9AC06FB52B38294DE8F87894D25C1D278678B048E3E3F4BA0D884154C5E16780BAE2322C389667A15EFB0B21718F56767EE942E4BCB190CDECA74C92DA8848F41AEA2328D29B10C95C6DFA74B0E162591B1BDC0ED6826ADD0B04C7495FC30E586FBC03D4E871915AF71866278F9CD1B4F1AC56E8E1B7B11DBF0C9A64F608E1C3958910829654057103BEC687A02AE9A568BE514187A3E27F3F9928EEE29519BDA0065179423A7242EDDD8CC337F0B7E7FB7CF90FC682C9E60253BD0997F34F9081FD785712E52262CD17C3508AE4D2FDA3BFE232269ABB185E635E659D405AB12E17A80AEE5BA7DDAF1FAA819A284A60B85B49F1A57DA72A0866B2B9C2D28178995E79D4458B58EDB187B0CDC5C37F111D20371FB8F410A7EBED95474859645FED6F451A396781EF7A02E6B52593189EADFB1226316FE8DF79B23CC67BD2EF973CD561DD612D0C3047698EA0D3895A28B4111938F0A0354E4DA7484697C85908A3BA3E80BCCCAFC73303C767BD3587C1F9D48FD4DB93517A561DAA10F53F330ED14CD65B4A54FC43E5F5CB421B8B6CF7B83D86CBD72A55791588D4B81094BDFE45E3F32A2C3FFE809F66FF310D66032AD6BAA5B33E79F1C476029A49D49CAAE427D8A81EB642B15EF0C544C9EECB7CAFD2A854BA79E4D7EE01A96CDE9EEF45E430EEFD8A16D5D22B751F981667F36DE2E139391980DAD22462BFF4896D277D89DCACBD5CAE5EE90BC2D5954C083AADF632D9051B782190ED4AABE8FFE195000A6BA05115EAA0BCE755B23B10C81DCF4BBED61E6D31E9292DC1A7FD6B453EBEFDE55D6AD8866CCD50473705A24F519548172D3D9F92E668D679D782B7F1041E5A558A625D65E679FC75B15499BFA304435FEE6F6498138848BAD0BFFF6942029BD0C5465395F5368692D6B21B2E22A638D6EBFAF3A0EF1F9BDEF8529C6D0BD328CC82BC66DCDB2F5AE20F53B8AF66400D6C2C0A3C6BCE1E8D2B222FC54F1896E58F61816E301365E12866C1BE7C4BBE0DBDA2B504F0628A4DF1EC7942BC58C0A4CED0046D73FEAF2231FB9FF61C0F7AA564EC1E10BD65B693CFF56DDF3596DDC85CDECDF7F123F9DCB27269A7F65A435ECCAFD89A211C829BC7F5916DDA61959AA296505F6D46543D863F2D3F007D8960634841CB317F5EAC3D3A3E4561801CDFB269257FBAA6A60E7A0A1980C9BFD6053BF2EEF7414704C7160A051355CF48A0C0F6FFD683C453513F8212364775B7424D9315A920DCD5B140A8440EF7E5908D4061F580022399509C0ED416F945705A19FDF8E65C8802B67701FA1D15F06013990C7BB8D0D0404679713222924DB33BC659FE58F82A99BB1AC551426A13C2CF316664AC8037B41755F110F6441C7BC9446430D7BF917AFDB8FBEF84E895388A68763E0E16F89FF630BDE9732852B70A4A3AD8A29D2A4670757AA4202DE5D53E653848FB26C6031D07CD010501F0785D1B1D69BED49DC3B07265D51A15A7C432C3EA63A0B0D228B4F8AD4060DBB8D54B94BAC7F2179829C8D9F9CE4F7BFCCB472EDCBED73B0D18E3108156FE659CAA40B45016E0EFF20F81C29EADC8B638364FACA6FC85F98A9BAA9BB7E5261AEC6786C18487B14B77ED2B62B762D6B8B39AF5A870EACD236CC53C016158DD1E71382475657C512EDEC0977320F1BEC79D0CF39403975210DCEC3ED5B58F"""), - TestUtils.hexDecode(""" -e870f21e348b630a1326a0334c872302d0a6da460dc9a0bedb6daebc027b22b9b332c967a2f5991252bccc646e484b83d4fbbaf2887629032de5b3e1b86002cb089bbc58e35737f8c07a694b5cfd38ee3976fd25244e6acb2ccaed20d926af4c9c7526475cb89a72a26ee9b2a25c29128d53446f797344d3eff20d91eba8ba9d02f939d38a775911604124896569964fe5f835df7cbf044f2565a32e017caa93a8848f7c4fff257b885374a6af0df150b79488551200332d176955f304d86340a6df8f98cf93dc12909e1693ce62de02192e63b8af668a0fbb2c345bcfb9b5151131b7b4c7d7eeea48666a8219d5f8b0cc430443ea3d531dbaa6360e51a842fbe1e40ec5fc9ecf9bf172570bf8b31399ba8f12f3b83c40205953414caf7324182657e0fbcc2fffff801c52259294f0b23eeb5ef14c34d955b92ae782739a9f9dae5eb03af4bf4e911c7e758cba1a0f1d0ac1c7256e5d5fae242312f18f6747c5b56d907a49151080485999605246550a6ce8e6341bbd1ec122b179b3102a2673c163ed7174089c10b29cf33b9b5fd1ba22dc73a164404804faed60958c6faa6a09b03dd2eed0fa8782212f1da486543ffc688e37bd43621ab857aba0b13c1e0969a482ce92e00d62ebec1870188734135b0419cb3b9f3a9fcdd68b5b4a53169ae0bc4959462b8eed39264c0b0b34e0595c7a719672abedad01638f3ebfe9e4a460cec890339595a9699db82819723ba08c7bc82080f8989d3d8709386ed1c9fc791ae0cf954e3a897a93d8e235eeb69ae131a912736fecdbe1ba34eb03206110fdb1f81e71dceea673fbb98886ee0d94cb4d76e1e94278b8f2501fea2718466802d3d4a068a2ec53029018df3eb088246b767043f843f79b5ae5537924a9b5e5bd46b19bd7dcf7f14d4c9f4dd05b2c941377434cb37d80a899ee97a5d68345cdec8a43cfef1f286c0102c2d8c9b0d07adef966992dc7ce8b9606917e238625707393552ba9c01c4e72f6e3b533a734c0d60e3a2aba08a823a12a45263b61402d8e62da3e5f5a5c12e0cdee0d255551b8af7d500b547699f72b31a91519891850e4109f4ef380757013fd57a0fa0ec0721dbe825d4cce624cdd8b7f7cf64fb31332f374f6c470b9b8a5171f25d005da4e184665430e7ae553caf2ef9eba994f34b04ed6886c1b768f03868522959fdb164e8ee825f08c4a4dce01de6686695b5dfe6102c7463ab54b084c7fb1366a0b292898c0d7499a3a6ae1995bd2139f7d7c84a0f96b497bb2306028389b983f2e02a2fcfd3c5f8a0b4d2e334d4f3a460829efca41806ba82f2e5ef585531a3f1ff67617ec112f613acafb8420a1cf6230468601cd8b0807d975065fd36aefe77111a5a72ee622da403a51194f8467a122e408a0c3998a3a7f18c2f7774915289a1522f5670527e63e6bde7ee0a84750099d949ff87c6dde67de9cb220518ccda5135d3bf58a42b7d96d14dba0ab87e79547888f6e87b4bb9ed754133d16444eca15045ba54026767e93114e8a3a75a1ff65d0f03c667a8222248119fc8994a84fdf73817bc2d61d6b764d86c69d68b7ca3ae85031181204c39085af1c7efd687fb91d00255dcc934d47228c714cbdc66d4b418112ff0ddc030dab0f4edbcb0309419120ac944e15ddedea5cd3a1d62abdfd8729edcf40d43231e378b2c69670c59c30b4218e7b7f2dcc0ded133b585ad673bed77194b98965fd4a04d93db53ce26128e481de6053a14f40b34f60a169e26e99b4b29979c03e4880fe84474f11627620d196369592c0cdd88c3639c1346d3ee265e550d470b8440c5676387769382ad4b57fac799926cba49f042833301834033d668a4f0e95e2bfdbf295ee9732e30a75b1a76d7a4f0c12029514252d98bcc4330fc2a3172bfe72c8f8202a308de53c4587a17c5e149c92ffb88b79d8b07962cdf91f0310d457c7eff09485a01481313b2aebd081c49b47558c252202b4639dce456a4e786db6a91a24a032d47d1cf9d37969d07e2acfce0067a20994310948821510051ea1ff97f0a5e88f0d36825f7a9b71d5c64d42dead04fed5f6b63dd80bc0325bef6d413644c1b5ac212bf9da2edafef2e6b6d99354470e25c5050703e524dfe08af14dd431e609be5809012ff5d0d4dc260f10fff302168b9d73c86ebc71c21d76ed34f08b12a6dc7ea174ba1c2790ad34a7b5d2e55607ab26eea6289fef0886187f43d5b98b7687b227b58692d61e6a8b9bd04a9c3a5df88e03b20c66d618a6d5a979cc0e33ca400f55918a0d2669c19817e9bc0126a406fe4816a24d06e072717435576868303e961abdef730d973768373b4f413b006c137d63fd1a7937c0ddce317078b610a5fcc1a49d83778260c088cff2cd6e35f58263d43edcb81692121d737960b77b17275765218d0b686907ddbcf0f681bd2662451dfe012db5598c061fc03920011a245c3d8fd3a8b0ee6291959a01e811957dfca6351df838ad3cffc5f28926042c1919a446cdd525d0a1b56591ee9574c16f88557d54b97cd4e077289ee304537176c4cf21e63e33203c076b00642665431183c8b6ea4c58b2d11011d1a1fcb3325a1f7cb148e0a0c70484ebfc6a460de38392761da4f101a2274b21dfd8a5b6870cefe3f1ac9fab09c49acd26de288d43326cfa68248fde5a5d0c2adf5ee4f7a87a570374aa40c904bd3052836b275feca785d29a5cf3af7df0ea226d5fa5aa33df234354a84ecfbc2e2a3d2b3cd2630b765dc0d6a7ea00884d7e805cd5b4d7219b7f5452e27b761d2734bc68d6da9b45de8b69007e6a961a73aa42eeeea30700474cbcbafb4304fac39b6dbbdd2f2a9eb5b959ef1a6efd9a41661265c70db1828f66147fdd9a7865dc9f0a605081ef41202c731184d754e499c95c19af4aaa7a018c8f1bcb1bb3ec4357bb7ccdd227f37179eadd63b10c2c10fff271a3765e9470e06fbfd3e5195ef39a52b20041507f3cc360c37608e976bc29797183feb75e61d4653e90c4a82c744b952efa874c92a675191ba7cac12479bbbe83b5a4b2e919b8e318869a9da789be9a8ae806081bee3c6376f54e5f687a2900a9e610094b6d21e4037066f9c85d65fbcfefaea7f2936aa95adf632bb83b1d5630ae48a2b8c3ffa79e44296a60125d14a5ad30e70f97e072da5b00e115313c0f3e572da51faa8741e98bc2741c8c44ab6d4d60fe0a145eec8bb91c742a0a8eb133a688d322a836a2cc4663ebf2eecfb80fdf1f95e83115d10364baa9357e1e133338b01d6ac2fc08910f7ca44ef8cfce5f5d675346417a40010b2c384a58626378819293aeb6c8cdd0141c3c404a738badafb8bec8d5e3f026405b5e6b7e99acd1d5d8e7e9fc01092d3031536062646a6d747879829295a7b8c0dce2eef5fb00000000000000000011202e47""") - ) - }; - - static SigVerTestCase[] SigVerTestCases44 = new SigVerTestCase[] { - new SigVerTestCase( - TestUtils.hexDecode(""" -8109bb66b04ddeddb48e77501a8b1e2431fefb69da28a572fc535be604e351cd18beb9691c57c1187703ca63921cf5df53c1a1d8472c844298cc59b0906ebf085a85a174ec9cb709aa81328db8a3b3d95ae191e334b021c966398fe2d975db14dade081aa77ad15d4aca49e87a2c376a64258219c1d72c50ca2354d78c5444ba570125773e9088d0275de193b402909c9f1e9754adade9e8103bf8d41bd81d2eb5587e4039b64bbd41525a2c2312eb17e0c47071af5bb3eab2627e92ea39cf6babf0a5f4d55208649742c847cac30a2af906c688ee987d2b9f103fafc9e86f59584e616b15ab231b64402c2c98f3fcc95cddc447741f2dc3ab4302b863f32b4b5071158bd66258343f1d045f1ff297cb287e3164593462d56df6b0705ab71e0c75ed1722611ba541254fc381f064f6226178d1354cdaa9b47c13b1bfd54a41d9bab19929e25aca0ea68d8ec2f42e816a9784293919fbb01bbefb93f77e3dcc89cbad5bad43b5358207d36d98a74626c33d84524d0263a188c3da78c9242fe1d7819bae24012800d11fc5068e351272f12ca8b57f4a6365268e1df64e4d5dcd2cb7a04e66de16cbd8092be8af5dc85c9300979525b507600d8590ff68a61290d1f4d29cb3c39a462c16f4fc3365835d2b172d1976ca92b6bf7d28a803151c47fa8ff00243864b60d80872cba15e20b1a0bee3b7ab1fc2aceb4c87c2e69616d1fc8e1bdf5daa83e9b297b3b744d1a1528c9caf12c459f78c0a4d6e62da5cb8c06a504d0d68a05288822874891e1b8bcde599eff5dc2b8e7a5d3d5e8ef1c28ce2e2a8c56f2a3911a82dfb2178172808fb81f4c171f73b10e29d3c8923d2377b64ad9c56d0cac35ffa23fe98120f1760afebd25b26bb4fc977306a829cd7dbc90c7f05a76948bac0428f93463e0c04e8d00326e57608e66fcdfbf91d4dfd9caa1452a2d91cff100538f6935e054d679390b21e8e45260cabf1acc2fbdfa27142b25c4c2e3bdc6df8bc30f26f2558caa5b68c34c87f2054cec383088bb5147791652192b936e1aa27ea851336b2e80b1ad9cd8d6412910b1750fe471f9e7aaef8cd21e1e53fa1283f0a32b3d2d17635ab1f965b8a4c052cb0e90d624b832eb2e18b5fb19c504d4b999850b03a4828913878dc519644d570a7957bd571021ddb29aae7043e18c8acd95e5a0c3ba4da989ae53422abf52e386d476d444ad15204110fa28bf28c6ea2e896b3ff5a2d58ecc0ca5801ec916fb59e135ab3e8e05b83fcb2bfa6af62c0d05719781bbc7305005b2b9a790ef912c0fbcdd9df52806173ac6d5d63aee49e10fd03191e722e68450247a7696ee3b3de8c325762795239084622abb2ac462dd4e57532335a51756d5e8e56095d21925ff3ff0f6ebd1a9bd1ab13a23607de3ceb409422a6bffde90b5d3eb5ed2b06f5d29fe146c7a3401e1741730dc5ae0ded6a98f227ca625e741a1b2e5b0d7c92bd9af5e12e09f792c5a3e45c24dee0dc489d2ff1e1960aab472c820194e3aca1d34fad159e5a021353b29be8624c6ce946687255bde401f4ce8161ae901ece6da3b9c69bf3742b31afc4258c79c8492bf6155439c787e63713b3b277e093a95776004399a075dda189b84b3a3e219f0df2a1218ef6778294920e74f1c59ec86fe1d4129c84d6dc428783364788418a83c098ffd774b13b830b3e9e5882a73e05915692134624d2a79df7b6a88f301aa200ecdbbafca0a9be8d981ca4340fa808b7d8bf862e9243cb94dc2659262cdb5b0a7aeb497d0ca6a2d1977bd375c9d9f977068d0115d4a552ae364f46a558ad29a0eea0f10ebf629e12deaaa40b916a435b3571663d570f9605129bfe9c"""), - TestUtils.hexDecode(""" -430B1F46E87DDE9A3D055A7D4D6AB1277B2DA6EDA642896412126391AA2B29AFD81C246EC839929F5C06749491DC4D81D58CC989D8500B6879E8807B1C3AA0B199EB599AEB86B344B77E3DB1AA034C938D80CB4BDCC29B31B710F57C7E491D99B71E97DD6FDA01A0D8A54C7481C2786F64FFC53AD358CF31C9C875ED278CEA03F2BF732372B19252BB9FA4ABF465FA2CFD1C08684D10582B410A8E012DBD407C5140D97CEE768C6D68124B2C84113B58C9A2AA67093B44CC3B6199FF1EFA6506CC28BD30BEC4CEA88411A491DD948DDB09ADFB92C40CA50E709840BC1F107E0CA428C111EC4505C5346E74AE4AB5647C1EB80F9C07092F8D39A975C4890317F9C0EF474110AB941949029BF39ADFB8E65CCAC0360A3EFCEB69D2BD805E4FC8D0620F8E039BC046DFEF1ADB03F5995FF62AD41352D479084EF3E302578B83332506918CFAD6E3BA701C94B0138DF0CF6C2948049274CE61EE0A64E756306273A02D68F3C405883F2F668820356812B2DA3A32B9FF23608DFA559183151221F83DCA18253FCA099FE24728F302C8B7808D7AF978299F3EB853A8BECDA46B8657598BE9ECE8A02DD4B25C593DDCB436B82335EF9C6A7B8426B701C66C9EBBFB3C8405A73881DAB57D1664F3AEC6F5BA19155D89A0A80B5D01C46BC79E1D4338A50B203397CD4B16ACD597A7C77C49917E9FE4B0D761065CB89C758498868B14BE2B6FF758745AFDC535EAA605C3F97648034D2A320264150278A7F1CB114B977C9D6BC1F29295CCCA16B23B7709D5608E4095E41D08B22AEC6289ED402414787062B0DA2387B6DEE76B32E42C51788B65E815E089BCF92D778F49A9707D37FCFBDF8CEF953A48A4201FA0173529BA360BFA6A77200F57FD5245146C2CD7FE8882670EE6878386D06036F0E1BA4B728CFB75806F05BA6409C514731B0BA8DA11015A63A8B5B5AB8C69703185191D12C5611F1407E8FFE3E50FC39C3310EF4091BC09FECC11D3AC107C696EE89F74CD6147830B4B3A971A0027747B62C528F6D858D1F9E67F59496C6B4E9E03FF0A598B26625B06C79863B5F07E265A40175E1A6D6EF3F900F3C4A28AD3E49D4D0B7E4ECEBB79244264474CCBFADA43FCD33F4FEBEB0F7E5928479F869D6A0FE52EB0CAC1232D7F674A057DEC4C2248934A40F5E2C9CBFDD53F71FC3BE06E48E13398ED426D8D3CC82118B7E8E5BDCA248380F4E64C427D1BF2384F60F6A07F01EE62AA1746CB143F26412547E7EF0E8FD1F2DC606F3643DEAF330D81CD6309465F9ED7F34D9B175FE1641D90212D4FFFB91CC300E7DFA0C555F7B35D2AF6A343D1467436EEC7AB95F2C34010FC99D66391377770A7DB8CD4D5C6BBF931092322741929F790E037318D6ADB74B4768C11F0E4674D18185DFB3D051725F93800CD38F58688AAC747F885908804D6CADAEDECB43131D75B18FBA2D4BED8D9BCC2156FB23F8F6378C622153EA8301300D0FCDEF1E2BB4E6F807784EA0171E95C372EC19B05A6C7B8DECE7080A057D29CE5A445A83410EB83B174590647424736A3B6967BCDF8A416A51202CE3F00E4D97DCC2C48A78D12CDA98E94A9BD6CCBE09DAF8085304F6911ECED3547DE9512461E16721322E4E6233BC7CA360A9004DA5AE064514603EFF0DF4E2D8EB04E9574C59F3AC14726C10100C688203F4960197CE696730AD7E558D7B939E3E6E7EAC4E70A7F6AAA80C1F1546E282B5CC7AA193213769B137C7F450AE5410817166F29F2E4E7E962932DF282A9F08A1DEF3E19C251F95611DDA9CFF4E2FED873439B45F8451B9AE06C6B2C698778BC4C742708BDB54CB35B686F0E7FC856CDBF977AFB663DFE44F7FCCE0E0555BE81EB28984BAFBD6FED3F0182F78A1396AF7B7081280864E5E4BFD7C52DA28BB5DE5FFA211678D13D41BF825F4B21BE1CBD29719ABA341E7B0C3F101CEDFE2F709E4DA4B5A6D0C021152AB546837024F4DCC4C45C132A038315A0F1D69AE768F70606D070169AE0818685C4BDB7341BFE15AA0455F535766FBEBB50875246A6DAE86C7B9F6F3A9FE01AB9928A99C13E6628431D41C1506381A63FAAB57BFB3B180F5D7FF59A434233EBC5A659B71CAE6970CC838D5FB638676216E3B16E8BA6C01349A7482AAF32ABD17DF7FAB8C69789F0194022BC4E62B6A6AAA4CDEF13B1E3BF5E1F4FA69F82B1EE3FDCC16DDE1106E3D2C41F6E661E33984DE7AD6021EAAD3E64D8C9CD7B5CB538AF88DB82FA048E5705EFDAC0EF479827EDCA0255BA60771A5EBC716C690CD3AC840FB6FF462063503D68C199050BFBD64533D94E093A47658822A25D54CBBFC689DFCBEB1DDD5BC6190B8F02C6FF3D001AC63729D35C8C50FAD3DCA2E67C5CCC6A8799420B159C7C5CACAB958B423964C489DAB1982A4E2222D700BA5AB772C4A11A44FF64018AF477D054217EAE28FB8E37595941FEE7AF87FD44960A144DB0CE2A44B33DC79B1EE31CAF80DAD620666D0ACEA76841EEE6CE81C6FF1F6D1027502EF89F1595065CDEC19B30E4B5314EFD64031B3B9DDFC6C95A4943247ADF7E4C93350C241ECA71260A454707B84017C5EB7AFFEB5DBB863A1CBDE0062C662308A2E824CDF6397863EF78F62319E2873B506F8A9EE82135B803025D962E609E006961EA3F7B67347518E70D9273893D79530F67CB678D6A8D28A0342BAF904BFC0A69AD575CDA4AB73AF22B52AE5D58372E0C26795CA96A16B8461AC61E6F68433ABCEFCBC16B857A89C475D1A322D34266539A17D485B8FA356EC3E154D37BAFC4CE75829FBE8BC823FAFF15A49F847C286F999A1F2C12B03E8F8A4C34A97588D91971279FFCB100EDB943E636F78ABFBAF88BCA5C55C935F6147E51BF798267E1350D2F5E3F74B339F6EFE86208C5BDE149C5B71056BEE748D06614AFEAF6DDA2A6EFFBB56B0880AF9B201B3C12055D292E3BB556240DD031C29A67BF244F59112BFB6865EEEC1DFE1CDB1E27F0A9E3372638FE4407099D0E54E9A188079C8BB9470BE6F63C83612D80BD60C21B251B64236E5CAF09A11C12F1A5E94F199DBC7C9E394C0B0E07A583E707E5241B8FB33E39BB26C31929F39316F4FDE206493566E17B51CE635420493176D8FD353206EF87F0994F039DF8F008AF602F50D7F9C0051B56227F3A2ED20B29611219FC4376234EB900093A81389ED00991272B739389F1F978A92A3E41F0A28985D697C01240875AC46A82B2FE94004CBD7B1E7594AE38A9DA0E84FE7E122482BB391538EB8E85AF9DC022CB32CC08FDA7A95165725EC29A0F824F97F0251BE636B57E0791A7F50EE190D45749472B29A674239AF95B373A40A6E0E09C674071186B125EF5AF72CB434AC0AA990341F063EBFE30963451491474B603733959A23A6D5B8A378F15A5A5B9CE4BA44BAEF6AA531AF5097ADE73F64AED0A541784119665F548FAEB447DE108AB74A74893017F0A1AF84AEF0730B555767B0CF6AE502E7693374D2E01C54C64E411AA93C96DC5FA010267B387299D4376FBB190E1C51A560871B559FC800D82ABD119A5732B50270BEDBCC8A636E7499149AE0E47F736FDB71EBF1995D1E8BDCB0EE96E732E8C2509F98717C3D174C78A4A2BE43DD89195408CD300505A219305809A1BFE7294BC2EECE6D98C768A8A1E0F74B665EE3D652AE8E008EBBB11F0D2148E4E5C93D7FE0190D27B3EBB7D2194BFBB624AF3A894CEF7AED571954D006824950A981F4ADA72BEAA0D820C5DD9BD519D39BB7915681F266DA66D49BDAB9E55879B953A7332F877DC5F5CC7BB3C9E1C1F2E41EB55EFC02A450B5142514F1E06D43E48FBF5DC80DF241169D5936432BFE9BE99DCB17293CF968A17F3111C884635EF2BEDFC87DBB80BF25EE9BF57B55CFE635FD99554F5FF2B4482D1948BD282FA282C48C0302348982E30A772BF14195CAC7FE39F836E6238EB1E1FD074E63B9AD0A8D37111087E47FE5D04B62DEB496353457BC76C53A2FC9D5AC9AE6A47F632E6D45E08786DA128464FF2266BFF92B5CD89176A19226F2EB14CDEB331C497F1836FB6C0A117ED6BAF95E9DB8254487B0DFA7301397AA29D95FF2065D851BD302B747AB47BA0AF408B51E4BBBF042ED1B2B604EEF4C266FE243261515778BC9451A8DFB025FA3212E868C3A078C7CFF65077DE94E50ED90A259FAFAEB398A94FF15C838EFA7F49904BEAFCCECD8C9ED4E014EA00C7AEF1D437DA306E8B7DFCE536912C169BAF0A3B78A643D6E210E5550E3B2BAF7EDFE01E721E3D05BAC1378EC1DFDEB2E2AC0F0BC368E0A8CC64F375DFEA2FC20CBDC515440FC2ABBBCEA3584E103BD686C5403EFE376D44F5242D35C9F9D35E1A869FFCB6657823EA0D4331ADD5CCFA99BD6EB3494A48ABBA7B7ABC32ACB8FF00512E1B0AD493F579898847E328C06FE05FE282F8D4AF48A1AAD0495AF1AC7354275A6D45AD5A7B3F6787F893EA558BC5D4ADDE1F0D265ABF73C86550D25C00821C3138B385448E3E02901E2E6EBC6A0F211CB6F22F8F865F0DF3893B987DD086B6674F5464ACE18B9F0EAE948667B2FC04FECEA3E2B7EA6B869D5F66D02D4DB124A59621B96E0DEFBF99A91AFA0CFD6D5A5968E62EF42B4C8908C3719BA0254929A9A183D50C566CE4FC970E047474490FFB07F576765AC5286B2E0FDBF1EC56A8AE8E6F560C69614FDF5C89BA53B8B7189E6388F7CDF7B819F78F3E6EA54C40865262BD2C8CE87284FEC36E2E73BDB8AA9CB5283272A90A6BBBFC3F7FED5F124E8BFD770B6254CDC695FBA0D8627315370E2CCDB89BCC84C96E20805AAF087F9E9BD1A189F4C6D66A6DC3FEF773788B3B57EF876CFEAE1F2C876CD239BE3B8A94F21350EDAE6C269698CC66BAF90B3641593F96399C71B2ECBE50F61B5D6F37D47DF702A9B9E47BED2824DEB19ADE7D7D8830A8F610088CF4BD0AD22A5A4FBA767D01987688BE710235A74129666FF7917B506A18E6B5D6166E8B682BE6B1946A4D4420926FF8CDF2488EABE71EFA7F2536B9DBEFBA08BB9E94086F55B1B991E18E6023E6952D4A563F2420A1536A1EDDE119E5779223CB712AB5C0BA4F0C176830FE523DD8603F1B316E128579E65454C2BE62C922C1DFE09DFB47D4497CC552AA9987A8BFE19C44E207397204686C718A0936145FC102B8A7111F74A421226AE016EDE658DE5DF9D3C28A247A87F2BC6FECF66CE7A6699880E0871CDB6F066D2CB3F9F625DC5E80751DBBC85982982E2EFAE3AB8F4F1EDA0D13C3B65FD2178E8AE4A712B521B7539785BB058176AB4396E6EFF2FD9052D4C6AF17DC30F50630233C3F05C62E151EECE13CE124E58A25F0F3AB65033ACAC9EA6E41CB3FA435D367DFEB0B9C9B37414CF32DC85A3C43087A578165C86D100E47DBA1FE7061111AAA961E67ED057C715974D3144912A58B6DB22D51BEDF6A8646D810190D91B61F0776DA00C8B0BAA7A83F4433F357E758F5AE8F278119908497E717A7AD25B09EA7C76B306A9A3AFCD9AE6B4F64016D5E80BD3FBE2F5EE673A7459B03AD9356148EA83461B66716346DBE85678C37C932EBC53B033A3F46DC28219880CFA8BB5E15F8862D345923BBC179FD763A0F943FC56BAB69F26C0C15D668BAD923D7AE6B35C07621768F9D972E2D6F46551D45E3FBBB577D13F01E8C1AFDBDD2F052E931C0529380F290FA1DE8BF5A11F82612943BAA2C0D086EBEC84069B271AC8656883F686C67B1808E27C860ECD1B95FF6CC6E6A5846DA29992CBA450081B8C37DD4911470EFF281FE94F10636A29B790E41EA6A342A5BE79CAF575FE9B0147F2EFE02874BC8A0E136A395B42E77D9F18CA4F61501E6C1805CDCDC10D0292593481F7E0F93281D0456EB51F6ABB7C379C028890F445D9FAC0D96AF68CDF6CC879A406CF2F0991916B33A72A193CF170B45AA079DB1BFD4B4126FA9AD3ED13FC98CE4C6C3C30923C8C53BCE1812B21BB644ED3A0CC0596C60032FFB1462DF5182528553AE865BF87FB7C7F61D1FD8E40D830B8D8F54924EDF934D1EBB88DA90BC59EEF1F6BF9FC2D17D8E9E0E39FFAD22EB84EFF39BAA70447B124E492D760E55D6301DCDFBCF9173FE293AC4D6CAF2E1964B32973067EC76BBECC65113C1FAB85375D92CE1436E1D1B205A88202B304264620B282E62CAAF5CFE1169EDAD9459B15BF0060C5744A17460F9FB164974CC55B3FFA71AAC13437BE58325E5E27E151C71D195F886F5630925D441A54695DF23F64C6BC3B0CA83F0E88D01BA4DC748A29F42AC2997C2A21EC258E430032C09E73E73AC2B21B55E1DFB2DBA281426620A0545D2507D1E96A3778C780FE77F1DA3B615E1B0D14DE8729229472E6619AB3B67CCAF21CFBFFD1F237E780927F147425B2142BF62CAD6B467A10F7B3DB922F095A0012EC179C4F8D5437AA8024F13A2A485E8890940DB69FB719B94B7D2629D277B593B94ECC744AA4CFF3D33D2250236C74DA057496BEFDB961B89BD6F44D581AD7A28524A6AF2253FD27530B7FF16FB5804FCA7E44BA2A3AB85FEDEED837DC130F533E8215B3AC3F584A2EC0E9B6194F97741EC050576E16349AD852DE8AAE2BF83CB1894107299F101AD5A2C05EC590B2CC698663C44FC0DC7F893F42BC5A2DECFF2FAF46CC1C00FA7294A0184A85CDDA2B1F38A89B1B17EC08555D082411A4CAEDED562C9FBBC1F512118EEC3BC931CC91636461151BDA454C4F029E01231BF170EBE17C526F3D8F705DC46560642B1AF36E3B401325A6CF59B88BCD4B3242D676FF4066E4252ADCA37786CBDB340DD81C5DD0540992F0B142C5A18D3BD1070719AF996E3C3768C3B234D303E6E9850B35C7AE52496C76106D7CAE4CF8ED01767B6DB5603F339FBAA019B08FA35E3DE1129A6A4D578264CF1FC8A1DBF218DD72B4865214DAA795A00505D4AE2B85E90F589065D65FC60CDD828007D4D3A4C084C7EC159C5D86817860CA03545FF74F17AD8570B2ADA55ECA12BFAB5C10067A086A34A57AAD8694C953137BBE901F8D3DEC27DB5DAD2AC96D56C312E25FE48BDC889373ED252B4F88D32DED6702B58D35A1FB40ABE2F2ABDE21CAA5FD0F67E7407A8"""), - TestUtils.hexDecode(""" -d3bed8aae32df74803b6961baa9a2266122e26fd3cfdf1568b460abf5ebd475e1764c7814c6a48cfd6d4df272ea9790c8ebf12fcf5836b0926d593e90828bd49ebdb997e79b79ea68e66f48dad497fbd3a6c3e317162a3f46a4dcc45616be6cefa68210b11fcfc9a906945d30297d1714ad28b1fc7b4c6cec5ece1f5d20729918070cbfb25f285a6fba5e195d2dd75a8c62f581be2d75607b5a8740dd2339682f31230354ea03d0e7cf945f167937592a2d2dcaecc5cb0d36217453809886151073e5d15e6bf7763cce81da19738be3a3bfe96788a56c47d2d166efd18250ad525b4e9e5566c19287ffc277d26a888d0b1073242da5e92b23556552b841ec3355e14173090649a14cfc0134b7714dcbe52095d759d0eaecc7d26f3f12494e4247435d5a6eaa9957aa503f710f8e2844905664905de2f30285e774b46270c58f45d267e850e1a6f711b00e5153040ce090660c97b14432c27d0dd50c0585a8f4c4e1e15d2888a90c184508cb400af2f5d3dc0af3eda99a5e97d0836d079eed38aa6e3e4f724cc63adab509ea5f28bacf3181cb7617a3884407a274824742623eb441ffe1ef15bf6509e7b2305b5341c7a3d73e5dece5b9ead5b99f7e65169ed1673bdb925b52a6b8d524ee37e8538e6917327a8237bfc3ed3f729cef6840e75ef1cef707fa10009e4d5c72561eed18c06e3be94c579f6629373af6a55019c3faeed00abc22deabc59dcd87ecd40e9dc0a5f4b7fe1d711990fc8c03ae9fce980450739c0a441e3512ab7602038dbd1352fe0da554176a58c47c29111eda3d2b9560b3fdcda292c31621e22bce8695748fcde6c81a1270a1944790c174de8a18a505543b459932c6f4228a00984166ddf33e981c2d3ad2e3cd9ce87aadc57e1e437029223e729a99667ad87ca718db5b133a930e73dcfa2d37ad7580373da272e54f62f3d13db9a4bdafb1922145a1624fa96921c0b6bb1b3d7a115ee58dbb2872db79f4d38255c11f160397052aae3ec34921bdad97da72714f37eed4765769e996e45974961e7439352445147dec09b1bd02a776c2c22be612a723b8711f8391e4918a95605fdc866ed64cff6cde9baec4eb42bd880dd0265befe1a33f4d2c0900627f0c7727228aad47d0922caf2a7c86d70960ac2634cea63dbf5d33af04cb149eb618f9ee97adeeb0df8bf599358a82ceeeca582551298a63cbac754b6975cebf7d6e78b6d5ee24dd6c78b51b022f857e230fab176446cc2cbf6986caf8e76734f5280f463641bbda5137fab4800c58f0e1c4dfd45d5813df3f917666bbadb3547c7381eb33b00fd569d58dacdc95a25962024786770aed94d97d4682f9e94d34ecf09e9269993f547901d0120e5e969e3f12a5ac219158750ed0f381dd72a91ffce01f2b612decbef0fa5441925195b813e1273dcd9988457214c9cc503206eb4756e46f900cf2011963e761e12a3774381b877d93aa1c7892f512fc0eeeb225ace5dd7816b919d1717b6e4a34dbd30171a1d036d9ef9d37ab821bc03d881ced0f2aa94eec2fe0b1ca72b7049f749c9e86ba4ff44afdc90931029fa59538014c519f76264a2a45bdab759da02761303ece94fdc2654cc9c818f4af979dad60a9506dd381d150a66e5b0fbdb6e734404f4cc71e6b4e7f5690556d28158cf049f8ce6e4043a82d1ca3c15e480ebeb7e211b2fb00b4bde2733f03f9cc705038050769f9aebb5a1ffc1c9e3d05132ec1ac7b55b6b3b127ffec67cd6e3a1649fc9313e3625c01ebb600c30f622f8bccea15d6f0388439fae057fb1ca54c7aaecff7b1316e74273a2c66037926b246626ea2321c311aac3b5b907e551d7b03f069ae354ddca45d1e5ed3023c576fdfd1c1bce9d8edad78acfde17c9e4d83ba9087d889dee4bfbcd8908a41ebcb4738861abb6b6d8e65251dc4b7c26de398c687b30efd895069410e58d7bc2a105640866321a83dec80ba7b47cd64b002300a9fdb7e7648c2d0f9784ba55f837904df1fd1db46ea82802d4c3e925d4c3e3cde9b9b6063d303d410f3e917f10aa0a18fde5849d14d0a79d71a983f9b09a41e9a3f80dd36e46bdabe65a1d40d7e53b94aa9677561a549aefd98826cc32f6dc5961714d9cfbe913dd3bc68b8891017915066792cded38946c0316fb0eb6d89c10b84df01e0f910a9ce8fa1cbde71edb210918562910cb540d3eab21c8c8e43151a333c516239370ea3dd42294712d6cb920b1f5469e74fa82d4bd7892cec246db13f3f37ef0e980e095faf06e5aa417f5e16de83c8c1ee5ba8340d10785e1b10aa7573dd6f77fd87eab89a014449210e285fb17d0ff7cc3a2c61e6485c2f2e81fec821abf0c694b77f71a91790037d0f141cfb4a74caa4125dfd7236251526a44d4ffaba4589d5237fe647a4082ccd708e27e82bd28597081fecc184a5ecb2d19d115acb18d9d463e3f642e2e606d3f6d496fbbf19149ccac758dcfe8eb53378b65608940925c23754e0f1a390d520f26c4cc088c091e55b3cc475565c0d166265a0396c50d9983e3433bc5527e9fce7fca2bb408b39dbf96bc183c3659f6e8fee0f23e4230c0eef54ae9581b3a38436810accd7c37e83326e3fe7ed1821393a11127027821bef0b96f58a66968271915c1cbcdbcbcd8c62a54bee08b3cf143e859564b798892fbb9c430a6645bb4c8a2be76c37afaa67b7b5a621f987034e88b1608de8a0a09384d85b0c2c872cc2a9f8ac348c5f864d28558f6c6e4523f408586490a78ef95ecffe5b8fdbbc264944869aeaa3ef428d5cc5fcd363d1003239a6651532a442935e674e3cf1aec6f8b32e32db762bf2512efe763c88b9bf4413ea3344835b96fdcdf71c83afd75ae5925c3e76b9afb9fdc72b17f41ec516ab23529e73b9639f5ca42457c5afcc0f2add498456e1db6b3e775ce48753a9a70840c45dfe7cf396b627fad775acd051829f409bd37046bc4cbb57938cb490891c3aa6a04f60769e04685ac1167c9de32fb20cf43f730d8d09b0d74e7f80aeac659509d7941460018c38eda19de38967fee38f7e9526babd21ca1be031dff0591d765ae30361fd8c2a33bc1dded2c43e0e43533a55e72bf1015f5167c8d6bd5e6a19cd4e2ff19f1d47cf42fc361649a669e4524c731bfe7bd11c2e4ff599724de173dd6990f30db8d3b2084d2d3aaa0c0d8b648667b951d510480a28d40c938b71974d749e62d88cbc686eaa31e7f89cb86dda1e778a167610e7bb3cc97cb27f37ef9121ac1baec0a10b40211cc314b02b5df4274acfcd13de277e470b63c0f0fa387dced40050607517a979ccadff817383b404b4d627d8e92b8c1d8e9ecedfc2d344c4e85878b91a4a5aeb2bbc9e3f5010611121a23333a42546d6e8e909aa3b6c4cbe6ec000000000000000000000000000000000a1b2b40""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -f7dca662f79909c3ddab57a31bf75b9d925ee06460453ccc8687ed15f17d9b3d5fc251767fd178116899bcb8d29b81a71bf5fcd021349f4d8b9f99edd4c737300e23b29f425671f66fbf2d51e1a668961ef145edbedfc6d1749a5cff043c58a433d4469a3e1f956bffe2142fc6ba5e86c8e326d65ad16ab4a8d0af6644dd046a6176b92f147a04ff674b572b319b9fff5a9fbcd7ffc68eae3197d9b3799e94e18a7ffa1452f1b41c7fb7b98ac7d30f6f371233d4170fd10e95cba9905eece5e06dc153340436c1dd34ceb8334369e9ba4b3c14e9ec3fd29a701fa8baed707a7d51dec96e43de8f4b3b30fa1de919da643d138e911d5bd800e336402bc74fdb6522125a8cd1b252bfa663cc1fc4462a017ca356a0f96bdcb3d54462ec5994fb32c2648361f6230159c74b4869d98c048562eb5837d711ea29abad6d99f8e95613e0069770ba7fd265c555b010dad0619199a44db46e9b362998bd758b882ef26d90fe04b8b18a8887945362c025edfda0db7a750670397a5c9fa8801399fff8f67f071a8a2d8abcbf548f0393f93c89a28dccfcadbc204d108a05c3ab07249d5d4e7afead91645fa7396368622bd2ad3bf3ecfef493dc235365af7f42abae241b7e0f9f52a66acfea9bfee57631f1a921ab1798834d30af1d58bfba62d4818ee30826e0b8b620b885f55dc08b346e7f868e113fe9bdd60b974812d5991b3b9beefb4802a4c1f759e38736b2f4761cd608128887e88637fb5f4d5bc548e9cc121e3fce98a415c64a28b901d26e4a406979511fbfb0d8c1bc02e0533c2ec33e17fc2cb5f430a029d69950a980bb7ef7c1911e28b355478e348dcf4be4d3b30b1279f0e3f0238277fa32c2ae9fe12f1ac3ce5d94a8c1d641ff55458a1fb9b450b0475476dfc41177bf65ab97b85b1064a6b40005ebe1d537515ab664f3c42c61986a11bd93a806f7336b338e9dd8cf5717157aed7ea3747517fc91e75ee9fde429988df68362b4bc31c7a464b07f7a0dc8e91f8fb34679a3d38224c4ef7b7726ad7a17fa68b9d417be3d66ec95720b288f3578ab366ab1e569f66117db15aa5f4b0019cdf305b3fd2297acaf1404e944f9763179b613b896c5be2ceb56c854cddcb3c8fd71d2a62526c1a1d2170c9303ac4e74ce34bd04a28fb5e53461e5ea9aef756b189aa0b5f311cee714ac8e7aeb65693b8c77cbea41bcc9f3bd3387feae9f000abbe7c3f6966c07b5ef0c926e53206cbb2118b3817df8a4b254d03ad98b6c0d86320a9fb8af7d6f6a1dc827e78ac28fec3408e142fb114929fefd1f5a613413462b5a9dd244d820165c87f0c5ea2dd13a5aeb3bbd19c9563ba2937701647edefb1b518fd4b2f7f31055933715d17263a798de2025225212d41e3788d3f4b7b6653071018e35366d2cd39ce7442c70105cbbbb261dfc73308a443f613afa4aab199474ad2f2647f9d94acdb8c11bcdc2c4f8e93dc16bcf9b40f3fbf0130b2776175a3a0370f6dd7c1c84a55057e95848fd3d040a820db1d32229f38fcb790585bf6d896798eda3d27c1229293c0751d689f67dc6bc4e2f973fb6b62355538947fab1b1f6399b8e13faef7a2ff8a20e03faede7d95416854e5e6f1b5ff4a77b24c74fdac038bc1a12e6890f9c5a34f3ee6ece510f1a536ec613ce47173f09d4863d86158b7042bb0df99322bf55c6d5dc14f7f766b43901e77fe6281d5e5e6d722ea65460444172d91f0f99b3140f4a75585c1fe21ae8edfe3862539bd6ceb398450caca1cbe6ceaf6ae59e961cb0b106541bd7eca3ceb2e367921eb4566dc3d0444b766b0cf2a951171dd73b02f668ca8a4221d933791ac84cc6c73235ec468b"""), - TestUtils.hexDecode(""" -8F69A33C4CB9627BF27401D4A1BC131D28AD0E2E5A317CE983BA2CC7465861A414FB72745E4DA31C0E04576DFE0D0EE834A1EE323D5A0901DD0189EFD6718049E2FFE1AFA548BE16E04B8963325AEB0CA90238C7A243A3F6AA17BC1D63836898688AC8E919B8EB6D689075E050B4189A1FEC723E0AE8D4AAE9FB6790B527A7552CDA174BF40BF91C4142B076ED8CF112A871450AD994737FD5BCF513D42DB01906636D42C6C10B64F74BD37D68A966DE0F3BBE6541AEB9991DDD0C0070F16715C01820546A014E66D786B8922E905DE2BC65053C42703227B7D8431427E3EBB0DD010DC58C2343147700D673D5707160F234E35BA24516CEDEAC77AE15C667AEFA8E029FF14F169FC0A781593E11D42E8659DA8E91E53EE0A1FF15A3C203BBF9591584A99FF8BACDC37541E126B8CDF3503AB2D1BFC0C37F38A298AB1DDA150288A8110C052469382A9A4F5565778339AB327DD80644A26B218ACE0830E56813CAA658A9F17826CD12B815612BE40906ABC89185EDDFA8E05102842CF27BF040FC7B396E7E2E023CB86AB7AE25F36DA6B6C0842126658E0315D6D8F4B5DF38CA663B55998ABFC72FE9B7EB7CE3BEB72AF73A0B2A45577C5215C42E465EECF4A4E69B6DDC1E65E0C1EBCA"""), - TestUtils.hexDecode(""" -f0fddedba6482c562d0ea6791254b7aa34da8b70ca4f0a7cbdfb0e4fa31f902aa37484c4167f74093f5ebd508e4b89966aba03065194cfe3376066b848da8faf1768c397a0e3797bf09e1dd02be5f1e77703ddac9063901b52c9b4be73daa5d44da1a59510b25a974d9c54f8f7889587c6f69a17989ea8b69f4dabced9e23442f337d015ebcf84cf8c5776f4863275532c4bad840d314797e07de00a9c7fdbb60f83392efc382220ecf3f9d60b5594da6fcf00580df29a378a9cc3156bac8ec8bcaa7de1d8d48d2a1f33ea8a8f4956e3c46f386628ca96e009852405b6333710287e376aee2ee7c6f67b1adf07f76fec3688201bd3b152e202c192db41d9bbc0d8411ca019f9a1bf1268b34ce82a7c037fc63d9c63a561003d8247c645173e01c8ef63853e4451185d45cc2d5d2da4261eede504c6da88a55d7cc7bb8df33eca74e9f4b9f9139b9f98964aecc5278448ff9f2a032226e908b32d741037ae689c204bc1f3bc07850debc3fbc839580e6ae1fcfdbd62257ad64c2d6f6945a6757242d1473e64f089c46fe050d79a082e43cfe656f09d01ea219eeb7684188fe80ad59c4bdb57905cba37fe0fdc1b205f1a5a899ab55a37c7d3e003f1051bd3b322b37289df3d350053d6ec8ec1c9cafb49fe147c01f092dcdbd9ffd2b7900205334a077b2ad5c57a53410bc5b9f32930fc6f6a270d84d4436d8c716344df877f5e523ec9e1ecdd43ac21e2c4cb8706415be0ea1060c7127d6a327eca92956771af363c03ec4a0ccdf958bee76803208191946dea6e51a85dd071f3711555cba324e5a7d7459a7662fa6cce043b34845fe77cc651883c478d0d4b2c09e76bf401f0c12721d21357546dc78d2f054b409b6a702328d720023096e911144b7bb724f1d799b0b446954a305bf46944f122867cea17b9798636498a8393bc2dd328b0b3ae78b44ae35cbabe62e0f0d3ea4cd6db0bfce87c6e9fb3364c2ee27b5edbfce17c8df592882dd057dda81855abe0d0898961ace81b0ff22b4471bf96ce814a45f7c6b3e07ef1f18c9eb238b44dc6a50d7489a1af58d2dd1ea2ab2b1a0b4b661e55bbe6dbe9314e76207ec0a02edb2fe7e8fad8141401d1f1a80237cf5a10604ebd26ca46c0ed5d8bfe96c3a1d6ff5b7d2de69402d348e5db561e531deafe29b0767620d7613b817d4d3a6568911c291c3436b40043cdef83a8b7f527aa8e9ca89dc923c2bee6e41312af6ca1530ec7c6aae798e25a6a31ecd29f4ddd56d663e430e5c1ead28a23d424148b1a8aebe9ad7faafa4e295215962d294edb7b1f994ccf43238038ff1af9597d24ecfb68aad4e4d2be280c6fda0cb88b4a1b0deacf678857d83c955115c094980ef8fddfa5045a3e38e733bafa243a91e89a5676312db195f1fe7c0f7b0262628a68c6619db1fd85d84a02b9e7da8234304192aa3db15a294dc4e9e7cb32f8662ff0a49fc4309700e0dea871edeef3df09ec78c3791fa604ad69bbd8c211f136dbbfd49009fb5e4fcbb2c995bbe361c580a3aeb1c88dbb2f148cd05fa9ced0d826e24c268b741953c8ec804add66a9b8dbda05a9296201d0f447b45a4bb7271fbd3359a29815bedd33ae87b52bb270cec2369dbac94528eb48a1a66c129793a4365212f1cbe7e24c87a805ec0f41cc2f36bb2f2423ce6904406b1362c46d51d6d5685dcc06915636e20ea3649d6d1da39c6177630d1d48f393d7093fc12415e5789b15e1ffd07e1f810057ab6545b22b24a93f9af3ae254407f9920af8a48ec40412998dca523ee1e122a5e1107a1121cad25652c1e00f6fa115c58b4a7a60cb4e3b219d9828f2c8efb04a443717e73146a89fe1a4f887b564010eeba3695164704c517d3597ddf34dc51dc460773394d8cb4d562498cd127020973bcb2315c25ad136dafcfc0d674341045ab1de0e4230ec91d579ef1a42ad69892f17dd271e9eab28097f8f9c5e78c50c36c8a02f1625ec41132ff1731e3c59ba20cafacc9ea890db35b8c9606bbd5457262d0c44c4659f933adb64fc74a884e152627cafdb20cc64ca10ed9ee16d814b506415cd0141406b0286124e37f777dc810d70d4125a72bd98a2b73bb26173494568bec76350b2b3b399fde1e3c115f1fbc99929a58a8ccc2b9cc1efcdffd210d88ad48c54a48e837cf841c9f1a350531b695c6fa08ce3148682fceb9fd17f121fc1e3275f65b5a8cd93a25d42318bd21e94ea8873744f2ab530c58dd3bc1109a5c872e61887bddc455b1bcdddb91c0ef4437a49a9f6c73fd371bc6c6d2fa594f78224646f2b8cfee3563c57149aa3a6995dbcf0e6782c53694b39b8812dd069c0cbe713fe44446e44beb4ffe38072deebf3ccb20134168702fc023c4ddf9aedd387a8bd6fcb075850cf1f29f2bc283f5731b75b68169dda2289ac221217bee3e2ed479fc5ea8244a99cb27a015d7a3ebbd1f7acef07b63f17011c5e39ccd0c025d0bce5aed7c482685c39f1fd82a9b08c197f9cc18da457ad0ad55250ea935bee50df659b2c7a501a348b8759643881a9c5555015799adafe10130d6107e0b964b48d23c909e55843b62b9dcd1dd3b235c487968c2c3d87fe29b2fe3ec7a8fc1c1666fc8d2b6adddea39ad704cf5eb6c22f0a5aeb80e2bb04f6c2c6bb9ceadcdf7945140ba942581213dba8428a8c06155f200082f7faf357ffaa653245e2752787fc1598e000eb567cedd49b98d5e4fcbcfd5c4ee10793c16a4767445fcd16ce4201cdd005e95cf5a714a9e0f648673269b5fcd8ca0cc254b6cd2fb428075a12b7ab2bb07a5ddd82e58c04676563b11dfede4daf13e1362a5171364a2f556c36130c1eadb59dd966622f8b86502f379e0dddf69a1f73f58ca6867b4612f28e67c7dfc49dcb56dcb17a79aa0e56a08c14e1e909fd21d05003ea921ab717bae0ce1f15a74a71c4d7e6936d20c7e661806d5f8a5f4cd93ab6720775057d4c0450a6c9e2211af47c57a7127f59983d824d35f48848043aaf3e76209a6cb6f34b15e5099b2c3801bcdca3a5c626bec9b6e92a67189dbcdad0d59d2b30a1f9cf9de45084ed6d35e32722b6642ab870247b42eb8f5fe39e97709141e36b5888fbf496199675274d840f15f5ffe40d74be3bba8b4dc51425f839ef7d041a4232ccb93b754c524ba141c75ba94209f9e76a0d7c8f2aa3e126e6eae35f19de3fbe38f17143d1a83830a2b9b4c8a8b0bbac29363ea9ed0fb1001f67e1501b6f4d6406e2335a61f3386c9e6a2447e3249d3db8390158af9b7e57d81fcc00a4210194ef6f872821a8cc475187780d658903040b0c0e172030576772769facc1d3d6dcec001c30335b5d5f62656b8f96aab7c4d9dceef3f5051b2240435b75797d90a2c9d20b1b1c585d89919ce1e5e6ebf500000000000000000000000000000013273441""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -8a37e080550701795416f5587b977446898ac8147890840db53ae4c7a65508bbab7a2ae6095c3238547f76228d5527b3cf1a6f773c1df211fbc5c754b69e27dee951eeadc89246b2a5fc047cb04416c905d36b9aa8f449c2198aeaf57a7aee84b4cdee17f94e1099fbac56e943298ffb574dae6d616ad7e13788d56b841acd970b4c14d9842452175539e3721ed4b00fcd9585b05915580593421fbb449ab9be941f0d91cff4c6756dab0cc6ea5266d8dd8e79e86a4401a85112d3c871de6e96c86472022c9809b8e1e648adea7e2c3166a7c1529c2ccbef40397051e17e53d0000c6dda30386bcc82254e6126247cbfc19e3c4f2f94db3a05a8fcf608feac3f3eed55fb53724e97ff20e31ba8ed2befd52259e3a3eeb8e7bd80fe56f9e9806e26bca49f0e28be54ce1cd53e75c2c9346cf4d585afe8f9c260ce6eae3649d1ae093becd4220083927ece4f17557a5af9bbb6477d3b0da0dd23f0896a663227700df6df2ce10a0b268d5762696fd9a9ca3ff22eb28b8f999e9f91818e29459c46c3c6a5b6c5eda8b880da621d9fc1792539cfacd58a1b7eb3a54bdaecf96b37d16752659ca51525e6e9dcb06fe54242ae65b9ac8ac5c749c09c12c310371915ecb7ea3cf46d2bd13c66ddfa2b6690e885c469ee34351fe07b749480be85515deb9b70caf055ff56ab85e33a029edf98394d94dea7bb8bf3373de77813233fdcab6377ad20a5dbd3144f2a6243d4f73710c97f9e113d70aa9771b52f19adbd074a790af5d3ce83c74855334161be8d572ce59f1ffb5877f4c56eee62336c7e690295fe8e0e1c964d1938cfaa6ca8f93896716605858ebd9a3c6ee3dcc8a803017f8270df26f7aea45df98f4f3a88f6943e3cad22a79b057d7b3d13554c2dcecb040172eca89ac6d55add4da96165ddb336d439370e71f56dd67612427be4fffaaed5b9f6a4a30884499dac7b82d536833db4480e050089c766120635d9811e0873863d0b1d355592aad472a3f18a1cd217b3d2c203f24e795df30db4350647c1821ca7995883d6db4aad4c141e49af64989e85cdb398968de223f80ebab4b3deeb771aa7270022983ee63ced61fbc4daaf578ae25bcdac546f4e2335f4910f1f5f58562e7ae7b4cfe50ef5e30de69d637da2e50fce483adbaf75a5a7ec6d796432e5ae95461c45ac74c024d4a515b81d18d702b49514e16db48944da5a7b86319c432a84bbd3898007d515620665ba4a5fc83cbe7e060bc9203d1cd971fa73b538d949810e7cde88d082eef96c72c2c0cc6aaa883ba6e4bb92f90f72388a7814cf03c86fd6c60bb92b36a072cd81ecc3bc8952f313e71f981ac53e9a9afd2d996e88fa7d0ddfc9eed0ae45c3665c60ad92e509a183a95aaf2989e9eeb92f09f5b9a462a9a3d5acef6af41ba5c6396d61008d0edc1ebd3e998849fad4026fcd4901448ae94d66950f7939103d2392ec78c7b9ad4fcecd43be503eeaa5763b0d03a55e052051c79f8ad82ec98d24f293b1e339e5093845f37b76d33c74f37f17093124dd18ec1282d0b42a10155da458ed0ec68bc4ad35884abdbbe9592e5e82c78a19f413d6cb41fb1c896246ed4e043d08da02f1f3706427e2d963c6c6f9181f4057a21e2d69597a84b54b197f42caa629b99e20e28a9d2d1905309245dd7e0cd5b5fdac815acdfb64b6128b3ba8d10c83e61618a7e8558715ce1f5430db60fe6e6f0e01791dc734dfaf19d48e813fc1d5fe1f353f4dcaf70b7fac6a170e97c6c541374476c4db1220a4712b1e285d2f91a5fcc4057e6767f1fddf4fcb83e16258b93419d7d25ddb3e36eb7837629253adb7c79aa1fefbe81b2dc59cb93f5390fe"""), - TestUtils.hexDecode(""" -5DE75924D05BBEF6B34CEB195AE3349EB621187051B1EF95A779B99A3E0F729994BD19C7D1172418BBD3E015B20699DD09D8BFB0A343F477AE2A3BF5737AC994619D1FF3C13E7676D1BCB446289DBFE36E2D1508A3D437B4B0DA06478DF6D4701909B272E9070B1FE06385DBF8A552B471C8EB48EAE39D141009FBCC5D57D95697ACEB7B5231AB5976FFEC41E947BEACA7639F664C6C1D058505A49561811ECDA46E23B651F918112F38B407E82219B49E5C4E7C247DC4BA633C746B42DB912B07D56302FC5C08F5E0C3E311268041F970E670F3AD26A207701F1359EEF9D4134ADB882A1C899B0E4FFBA2C68535D97796636417EEDC0790FF808C976B57F0838A694700F8D75DD4FE5ECFB4B6A188FCB77FB1DF7C5F7C91DC81017A5E9A6D1EAF59680D3291F74743E1776A6DE31101FAEA31D876A0DDF3777A91EF1EA0B575C83C97C7A283E7E958287F5A52F30B6E70201A1410355B47210B911A7A4F6FC23BC95D7951822115FE410ED2E7FEFE08940B3F8E63F13F26B6E949C498E62A66FA675850FB9F7AAFAF7D054F5C12306ACF2900A5B66A29931A5919CB31D19304916AE41869CE3294B0F5F88D845A7FCFB57B952BEABCD1DF7FC11E2D342AA5A70A8AA9DBE1E6E66555EA618849A95439864DF6D7789D8E3B46C6FE4F33877F127D4136D993061DAB530EC979F818A57E1052B5B33D22E941643DE2FF9239741F6459A0EE28658C3C0033FA62DFF37928C59189A7A7E36B1E305F3E1F421EDF4D71A96C71406A0F9AFA5C96A9411AA1A35D241D7186E5C8D0CAE15938FF869897DC3B7D8196D64DE202108D6FB436FF89983EA6DBB5BC88EE2A02488E4D12AA87CC4BDF41A339E10300D32E0FD4F3D3136FA64BA90D64E2BC7C20BA77DA4DB5311F616288496F2FE3E7B3409879050FE57A23DB0344CAE82ED329B0D31DC9B7406CA715E3D84E364BA98F73F693B6E62DF4D741928D21D934453BD67FBBD9725BAAD34E5F3204BDBBB569251DFE2D69A9A96BAD90256213BB0747E7950AEBB4CEAC7224FD5F8F99A16866F5A1DCE07C2CD1E06B70A81FCECED0AEEECBA62521AA0A01FD7B5A3A8A14DB55AFF331E469F5138DBB2B96BFD0AAEE7F38EAA375F71759268546D590BA8C0C022F78CABC4E089992409D3D7BD19048D30B15C796170BCD7AAF7FED0387542BF8A6674F197EF994FF81BB80C59208A572495DE4E584B36A7E9149B5E2081A4DC162CF8376029231EFFB4B4981895FC36562F51DD5158DC82ADE52ABB0E98F4BCB3C0A24566D07686732FA734CDD48D03DF99F7253E589CB8725F17E6BF964E96F9827CA5A9DBD04D448025EE014EE1B5DBDA514D3FEE4F20664C11371DCB16991DA883BF9A68EE30D727137D7902F4839635B1C63F6C4F7D42070E880CA774680DAEF105D277EB8D9090A98F6B813774D42DEE922314480EBE562775F68ED180B67EFEB077D8B174C7D4DA877B0DD3698CF506EE382AE6FC6F68EE93ECA3627B28248D3EEAC469EB0C26BD1A10A7779CEA142958F9F9A533BDE974E1B3CD9B74FEEB2EE29ACD7DB65E00D7ED6E94E5E44A925188285166570727FC687AC7EBE4042BAEF68BC23F4B9C51BA5040BC6BBA41FFA9AFB1AFA09DE1BAA4DA091A08086128A9CA5F27D3F4420327C8FF4801BBF2057282D05D1CBDE60E1E6FB6715EC41AA9A852686DCFC47279FCCE5D86ABF02A6B5B57DE22B2097B12381EEC567E4ED1855F9B482C174D6D40A5825687C02E1D0AB634C020497A44E07E8FBB2D05280C53562DB4C90AE0901B88179D06F9F991E33BF17E7A9227A30454430CB768F56842995081520158FC34BF5257EC8EA9338B3714126D6A95A3D77FB61207154F6DD0041BB03D84D8F75E6EE910460F22CA765A2206D6C56C6E498E063B08B76B1DDF98571F492F9DBD3DEAE7D9C8EF21EDBABED962331F06371364DFCB3216E24638A20F77FCDD894FCC5525DD0C8FC329494841EAFD93CFDF0053FCC27F5A1263C7F4599C186B35FCA9C6F5F2FE169B00275F15447AAA3A823E27E322CA2316B25823F3A79FFA785E9CBC953815FE06F376B6F5860C6A87CB9BE98690C9C2A93EFF1BF1050A01C72CD521BEF265D66BC4B8ACE5736215DE59290DA957175D704BBEFB0E81C2CF906C3A579BEAC3A0C945409DEE4A1E683A0DADB3C4AA7E0174710C72A33F1BBC62A6E6F3EB9C138C0CEDA817688BCE8CCE523A2A4E2566775015F3BF66C09E716CA929BCC6DCBA7427EBD93B21CE276820734331B078558C63ADD096004B67E618D9E58FF3FEF00183EAA293A1DA2520BC03FADEB6A74B52292DBBC6EE4E5ECA8F8B0556FED36C2B41F9D8FBDA8EAA1F74BED46F05E7712E20E463502A420B6CE67D125BE999EF906300C627C57C468C8DD608F9AB354791E6FEF0EE63DF3C1821AE78111B27E57DA88FA44D89581D11C2C72F565A3D0B5E8E2D83DF178810075E5F8FD29E1953BD2C6326B693C5CF6ACE086673D69A67A181062A6ED511E0CF36381358C2DB2A394B05E0C1EE9C54B89C68E10857463F71A842BDB8429EB31D250542F88E6BD3BF10BDCA160C0FF44EBE7D0D982F15C4892091B4A69A3AE7051BECD1D2DB132599F1101E2BCF60136CE947F339A3DEF9F6D81E1BA3F5D4CF2ED989861F7CED86B1A6A167291CACA74C45BA7B5969C09EA20C4EB061D4CC4B68392AC866AC591764A16D0A42710645988FE070314D0859A1F022789442381EA0E3E83F5245272CB5FBB861C3729EC484D2F299F37D2F50688D1D8DD91F131D03207CD1459B289B19E3ED609D70D6BF8E0B97A75F4B4F1DB52DCA7AD03100A36C45D2AA221CD01C8A51D5328AE47E3307EDCEE9B27F62E5DA9EEE15B7A2FCFF1678551BB3DEAD4CE54A16C22119BCA343822DCD20271BB1518688CF69B566A123F65C4787C1C525BAFF00CE20C46C536E47DB1E4410E572BFECDD7904583BF61847868D7D1AEB1EA071EE15A9CB9E3EFF8D17A5BB7EE8BA83C95272E065979904AA99CF036BE085ED869D3CCB694C025FBDEE9BE140A0A21689F95D90D8A54DAEA98EE5DDFDFCEE2908E65C210F347D26F35B95B34642939067CCF04A098ED3E2CE3C0FE66305BB5391E223E43119D38A33672FBC980BEAB96558D3A940700B3CCA9D3AD2CEA08E23082DBF30FC08E94B6640CA04BBAE80091ECE96F128B37141131FED2A5549CAFD7BEB5B180509880C49FC6CB1C11E4CB7C7901C89ADFA0E5335C43A74053347D3028B23085647993B5844FB2716B7154D93E25DAD1CCD889EF3B16FAE34D04145237378D66BD09A254D395736990204A5627F5446787B467B619EE8F06CE664BF7B94392B5C77BCE828D6186348EA2DECA1CC84999FCCD95C9EC55E28C8C2FB559C9020C6EEB661F708E40351D7E530BFB7B1C3683BF15FAC5B17D1CE7EC5CC3C27E04889A9E59E6534C08AEF6934747083CCEE84FF2345D519CABC7D2BA6B783D36C864C65C47CA636B28B71D6797717950D652659AFA8BE3CAE4E269BD527C0425168D04C097DE8F34834A7D1728367F148524366F9E53C4CC255D3BD6FEE7B5A6CF459E1685FE740CC203EDBF58082820B967A40822D36BB4A489BF0CEB51387009D5205056387C292D584309076956E56926283657BF7CF096F54E0128A265050DF528AEED9247E19EFCC79EC301A9F38BE7AE5057456631840EE39E191B25F4F7070BB15CE2CC18777F7CBEF100FE7993681D4E965D0C19A68591BAAABE601BBAB89FC27B3C5BA83545AD645F0DB716C98D5C7A37E0AD97C986EDB88B025D25E3DCCCA816C707F0E2542E44F4D69F943E1DBD08E344F88661B68A822C3EFD648AA23AFFA2F533879540BE2F670F4D53091AF68867E7C71EDB6E9E494E9D30A1839653422AA8AE34A525EFAA62D3F5FF00D91F5DDF80FBDDE464A8502AD9AC85EB21025C0E4E2C2877D50962C5AB8283BFC823FB221CC285F3629056D1260AAF87B556E556B4C723D44279A106EE4075BB79773588333B42065811D671016AF177105106203EFC36FDAB2F5E5EC8DE043902583C1782BFD8BB772353EBC5CF03A0D869E5F3797713B58EB7480CF7B92AACFC9C41040BC9E1F5447F9852B2C5B5F33B5517F28A01D5435C47E063B41D3B0F7605B07AC33FF6F05C6FF44EBB70FD6E1AFC2A32C9A0B1AC17044401B93D6439CE53C3B033CFF06688E1933CAEEC48A04999A01956096339B5E44AB3A57FD1F0ACA23A03114708BB16803C2CDA679061B8E9808A2E11DB0957D4F73C8A06E6C50D6DA43E4D008ACA23CE2A3213BA0DAD20D5BA8B44DE5D50E188039C112B8A40B250E7E815B1367375C5698B61BD915A70096815479916F455B9EF837300908C5A8BEFA5157EB688EA02245AD3B309D10C769CA1B8E5CCA2F5FC66CC3920759A203C3F6B8E9ED10CAB20FA143B0BF0BC8529A4E89AB0C99AF77E43E68B61A9E4176066C4708FFAB05F3652817FC42039E2F22DE2058CFA8701AFFA894F3143FDA27AD85C45D3AEB30CA9759537CA4AF2079317CE5F4B5EEFBCAB981E42065AD5CB8A4CC9B628CCFAC18D2E637CB73399CE3D90A9060F88EF438E8511CE6F403A0CF14C6B641830983C1EDDE73BA27E41BD678E834167C718F5B1E2E6C109199F756905FAF9F0005CC1D110CE277DA02675461AE70EB6A412EC455B6575F16A4DEC0565DBC8F387D84F9D3AE67AB35E511657D82B5606A4DB45CEEE81C94FFAFCB88B8185CFB67E4D7171EEB391E9E1DAC625B56FED22D86E8A34924740F94A3D50CBD05B8E2476CBC7C54D2F742F0FD7162E7A138D4AC788E710AA45824513BEA162E2A1C1F709413942BAB5AABF7E347A148D53B8EBA0336D91539766AF0E827BF8EFF36389ECA38232FF2D7E341A3AA710F590C78EB69156462BAE9B8B73386F38EAC4FA26456FA555E26E7DF679983FEF23DAE87DBA66BCEA19A9F991F864A17C23F7CD592ACAEADE0E82F4737B70F0243F94F015B59330B71E25F1304DB3D8D7E2F96669BD7F8313EF9E10EB1EDB0F0BD94745D03C83768A618AD9ADDEDA7C1E6E134F8B7BC96B84652C982B1D9242F8D2CF0ACAD146EA3185E2332904E84088CA2D7D60D3E2DAE411171726B5FB6C95B3DE961E62474CEC73226E55AE7D9C7C534E278927F5D669EE6D111E325D54F338E2A6A06493D6F1B7A556A94CC9512235498409EEA477597EFAB239380491C9CCBA1F00A0D1C5D758162E9F4F5464A1A64A22C32721AE57E246722A6B2E07E544A5FEB06AF86C580DAB2B9DFB5AA0F0251E6840EAD66FCB6B89F80C2AD38383B329F9EF4589BF0E8A0C9996EC19E1DA539CFDEFB2BB0F3D9544392A06F765A74218B7DC34F38D230D1AFCF9130410A4B4FE038F7AC59B6B062EE2D2ACCD288606AD9AFDBE95D9572B78B54D26166C7817E6F72F7E6C55DD1576720E4AB99CC26722107F7C278BAC2D82FBD0A3B0E1793C2D8B498F90A9172D17244A4107D9274958FE078FA8A5A33087BF278383F439C0B41523E0E51A662A9F2822CBBB34EDA97F5398EAA12D52506C2EAAF6D4B75639EF0676F482A69DF0E8A9BDFBF6105E32B6FB3ADA2E29C62A0AA687820B4ED35C2418DB1A67A3A5B92DC61368585CF7F3B1B644A8137A52CA21DD982760CAB7FB111558ED0310E9FBA34E5480F4E707A2CEE74DC24AE5717C06DE2B509E4807824707505FFFC5DBFF798E8D85F758A94C2D3770674DFE03627457B2DF10628A31D44BD89D3435D93E4F9BC14D47E6D4B9BD3BB2287ADBCE1FA58495D9032A9A3ADCD56CCB116787E060EA431C1EA9E60A30B609AA9C66064017EA05BC16392992B7DFF62EF1046FC7E64F8F811CE50AAB40AC122CBD5119D3045ED0812F6E30EF6B6001285427B643E3C6FCB6390A9FE76B342A462994F2B9074B56A848538DE205C98BBBCC75DF6BF23CC1AF0B201E5A0618D4BC5035B9F71BCE9D3493A97FA47607D65865A5FF3FF17A7CE28C0E87A57FE951C8F804EADC21F161CCB5D1E66F1E4DBE92C69D4358E0CCC13A12DBE87C9B530579189EF2359A9DF5A8FDE00CB2B58EBD748B23F884626A66EA39847917995EADC1839BFEDCC24AB6BF22A5C247B6FABE8CF382DB48148915167BB47F505C184EC027C3AC741BB0F6676B0D0E7781E19FB8D4D630E71ED4843010198DB9B122CC301D432856B393632369FA1C99BA252F086E317229486C034F1960087ED4606288A7C89DB0EA0DE94700785322249E901897611913AA74F8BBF412639DDB639CBD1C41374A3EC66A87451D9E4127F7627DFDE4E1701D7FC9DE13DC7754952F659EBA7B1A861B8DFC78D1379274530B976C66F9CC4002563837C852D83B3F3BBFD892F14DBF64C976C924E3C656B69131EC17B7905507F78F073A7E509157215C988D490685F8AF23F64ED338915E72B518E4305C9CD44C219876456E87C0C59C5D7524C86CAA161C745364A12890064CA9061056F37ED1BD56B5B09B1423775BF0FCC898AB1BBC283B23DB6E91A3D749125992FF1BB598260DCFE428D2524050C1F545FFDA18A63B052C0C8CA4DF8C3BDE83EE5474395135FCA2B05157C25548B0804D1EDE"""), - TestUtils.hexDecode(""" -0692e4fa67413edeabd602bff25ccbfad2e3402aa7399d8a9f7d0d6d389532019b7d3e63229d12ade7d487f1cade7f9533fbe2eb22a810c94b814a923ea83d7bccbd975af424bf5535f235117afa08156650728d96283a92d6276e34f864c37f8c11674307d653060d8310c0c7bba86515e051c3b1193087df6b22648ee59d6bc7a8c1b509b71620e3f7b5a0aa445f628e15e0725fb49e757cfbfd3dc5fe92a627bee707e33537fced3489e58fa73b49cffb2df08cd45aabaaaa491e77cf205d5be4f86f5a8d4272a5513ccdedfcc210fba346322ffeef9e11dfece2cfb7b854eba1ab581cc533cc6335b2195a20dadb86fae9efea0ab0c7d17710f8b0d8a157272509803c3b49fde1063e9297920bf245fe6502d8bf0a9a1f064d5a58b30b5a14dda6698ae37127f8d867f9aea40e93da3f4af04b91caacd66031d03c0c7e229ebeec8b818f4c970acd5c4dc8e17a3ce618ca96f4ca29f46f5e4059becc5f16ee43df8ba2ee1706c41621da8530689b42136b8a62dab7c691e566b9d48a28b45af799af56bcba07bc6044b64253e9a80e9b5ee01e8af0ca627a84d1a2a7ca9b0659dd1a60b788e5f6538a8223973476e9466459fc4f20cf2d1dab3ab137c5cfab433c436e7f3a6a681f675358b6721dc2850ec7b43aafbda90d13254e4ace6016175bafc1bc28dbf29541639527f246f6c007f41ed1fe6c0329260ce2ecc19395489b5c39d66543c0609120449037f321db95a85be51f1d01a485939390c47b53d82741edd3a5febac17ae6a8a4ca45df32fa6875b4e907d544e529ad26f29b6f923e21acd7964fe739fc1864d72eabe0859ad5e98142ead24c91167fc072a2c2673c7c5bf6da83fc7d662283347388891ca575f275907d06bab987ee5081c2ec808c81c563c902203f8d525243e20b5963967bbbdfa2e8ca9ec8ed703d8dd66c29c8a550c4676044703bc93f969e35f77194412bfb20441bc5e89b5e3238b766940779217af090e0da162e0f95761f63e05a378d0424af4c899a0a68060d9d0e5a035f6ecadbd550961850ee9345111491140810e2eaeff08d8a817700ab4c148c95086ee0663c4261b3cd53f8ab5b5841ba8cb9be8c5ad146d8549f21750be69951fffcca492624e136ed58a5e81cfb01a2147cfc5ca07a0721a38adcd25fed771411c75a5f7ff37457cab19d866b2da0fc45bc77e122143800546bc49f44909042d96bfdc63ac60f09bf4a75e171ece95bfffdfa73b4e509750ec6579996d0c83d59afc88ce9af26715be98cc8e6d05a14188a0fac6af1e96fdebe8f10b994d50ae6e84be257e6392e78d70441bdc5de30a1a4a5cfc7d5637810651fd471e162df2a76571c6d3df3b227e89cebcfec352d0f1af41a29e993af22514960c64dffc72a9819a6092150bd440487108024f0243db54ea68881d1c99b529ab529ebca98ea690046b1e37f6f1110686f6d9a7a725aa115c5e9be4189eba063d28801ef85973d0e9eb15179cb64378b6a5304cce09c82864bfed361ffe1702a9ff8e51a214b584247b967e5bb7f64b955acf25bd1073179776d9c03790d46f828342b90ffa2a45081184c3be0caf7aaf6c354b698e9256421ea3688c6fc18132d4e8d956baf9b821e64a579b1462ed4e990259867899ebddb19a861b24c20c2b0a6c274a064e1d1db366a293673153752847a2a5acc23b573ce0975655b79fe1a1ccb347773e3b1c5bb3028a1508687d17f9bf86ebbecb3086db5ef2559be02a68f1cabb47eec1671e6d3d35b65371fd5487b413fee14691745d0eb260c9008f07b5ce629c6d748c452c3131225f8c7586d99b2122202860f6e73c7def4401919e02e18471d1fd874b7c728296648b5ab571c517dea55be9f9ba65ff2cb349576a76030789dec17102a375ef8d779f2f2ed17be8fc41b84b1ef69ed18cefe28122127f211ee1abaf2a4044a3b1ee653395141da50db99dd3f73f85b5c0158a74f6f9707c7f62beffd70c068db1d6ef686cad7bb859c98049935e73aa4ea76c3225d4f19b333a4290ed0d723c6192034618fe3214306536741e20b066a6b9190972f4c4722534bf760a07e8d3a45dfbc67dbb8a5874332a4fc0e0a0640ca3999b93d34e4d8731957465e213577bade1f9b371540dbba188674ea205db7b244c77b6a772caf69f8b46b7b05439a852232348ef6d437bf7c6c79a4c0520a8ead1f3c00de2a063eb5a1e162f4db1ee94f1fb94f56f62d951da29f6b3018485c4a5c2c5f8573691aa096d8cd2922b66c8b7fc828d49e92a3d648cfa8ef524199b4bf5a8f15693960c5f59862825ccdda554b17e9c35f7e6a24365508f5a23c6ae211e3db71740fa444f92159c8df59c4b073f362cdb658842466efde20e9ba0472e2f682ecb655961ba8ad7575e8b02320ab6fce9188321816968a15789977084409d89b487253c778ef1ea1a1f47c750e37138735bcd58f6956ab7c8dd1c8a7ad35067c0ba0940b3b091c362d3165007df94167f33e0c660cf02ee5d6ed90c8ab4655ed47655d810751dfb2f1e65c890ed24c976bba0b8a998102d660a05325261b38fdfc82ba300683df5d561f73a11fe6f06425d11ef4c6f32e6de2ee6081a9b772e07614866f54e63ccbf7b1d9a1c3701ccbd1d9087241d8e2987203dc798d9431b8ab1fde5ad788db13c2e996a1d21b1559cffe3f7132e1aa83acf6c517d8e8d719076a36c08b2c6afbe5d23dfb9c5272ffb2af2b8febd51946199b90f98e7d49358057fb881f4e8641e0524c3471c0f6bb4cf59bccc7dcf09ab2c2d8a783710c982a35e4512c30e1c19bbfeffd992884ade3dd2a90039ebef2c23ab98fdfaaf6ebf34ae7fcb7fe742798c50a49d740244e65c49b22144c05047061e592b32ab61733a73b55ae04c9f36273dcb2eeb4872e7b7d009d4a54b867613ca0f69c4e7756a48ba7f9539048d495a578b8a76cac198d77aeb6c3a7dd474390f91faea384c94cfd73486ec226319946fd829c3ced266ab11db84176c7f67502b6d50ddf46994d6bf748f118045457e3ad7192f0b03c2bcb2455d018bd0ab1306b473f3761fee60d941637c562cdcda0dd5d5e86af9e95bc22570c07c25d5bbc6f1ce04be9e7bce5f7f095afec8b7c4cd930f9bc106e85eb8620668b52c9d09897460b1c8d74febabd73ff9b730c291c28f1410b442d91c533383ac3f2f41f0bcfebc9121b00015d8c506b2183b7d183751636da9226b795eacb2a1223004ea8a18a805b272384ea239ab86b41c556591fbabb783a6f909d5a181f3563ff1f9abe58cc921c751f3340497d94b1b2c6ced1e3e4345e73879296bfd9dade021b25436d73a3caced5e2ea070824262b5d6877aabfc0e8ecf6fe0000000000000000000000000000000000000000000000000000000000000d172332""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -a15c38cf5d89e1912b7ecbd269ebc6ac156697942a3b2557f5cb631782ee2ebf3158452ea076bbbf6eafbea078f2da4b969380c279ee4c5133ba8b1e9e3243c30e9085c353bc1210717f47b099d405b0878e0dbc24cd59c6a5181cf07355c10891059c18fd085f9b2aec6df7e6a21ab24094d8357d1b86aa6bd15ae92e9b0929d7bace3d73160d312dd7bb5af9fcdb0cdfd91dda2688d8e507ae12063c22128c69514c8d61a3912397d031549003dc5e2974f6db4238a8c5f1e5ab7d53751e5165f7c3d443a3fab54af972f7f6cb2b154a215ff6b410f45ae17d654fdfb58d0cd19fe75b61aa0f10ee1448d850fc7582b16a4ee6876ef6cc3663921607ce6da3709bcaaa92f15dad54eb8db0ae01f6e093663e0748c33f1ce041bc4566545c0b78dd606991d43fc76a9a1e1fac2c1765bbfd70eef0ef941763f0e32e83258bf2950dbfe8a391aeb927959447a7930dd5a006bc449091ffad53a3c725d5e3b01870cd5bcf9bbcd0bd33de9cad5407ec36b69a7bbb9cb0eadd182b9efa59c1423271217ccc268690ecb7c82c5f8df1df4726bb67ad80b04d3658a6dd1e98201d7c0062bd2bfeab30dcdbaad3b0bad393f1baf3924814ccf5bf6f4c8fdf5976f7b7dfd6242890a7306922c347547d051665c6288444a2bdd918f7346fc7cc8959ee3f8b936011e7e96b2a255af38158cea9df1faf6217d1bb989b09a8de3741d95ee834fdd2ab3962372a2879cfe93b1db989f9503da17e4c4294a6ecaf99a48ce2c79e2ee84c093cfae7bbf2dbbb9373ed2ab1c4e99da39d2b2a25633364c3e08a89b18b82aceed6a77fd805ec3b924f7dc96db19aa0737bf3d5606ba6e95808844a9395995f3a1341f3178159ae83b06b816b73e6e403ce72a93bd60ed2cd3c82863410f1d8e43d9f4c85573085ac80721344bedcafeb14171359a4df9486c844d17e38a4e0006e8c7196198ea8466007ba4e98d6119af88eea0925cebb1f998f988b42961c44f74e337cc693223bfc34142268d33f30e8bdf8480b44bfad1e3f8266d35dc1b5bd6758d0a8d66c7c5a1b93e49f6e0134d49f437257850fd8a6af26fb31b9f7384a7275bdcd69aac0474dae9778f054673bbde6e9dbf441368cef3f8829c45bbfeffbf8d07d7611abe67a5d55c8f2edee611fffacd9b8e1139d39c152a461232c972a8259a8bc7131d1d8b04709dd16e9a2771c95a7e57f7159c723bbf154771d34c7eb85230c57ba06e031da4be80202d7d12ccc74ec2ffcaea3dcda60259b6cf894b9af179f9f627846ceefd4088977911993b49b225fd886185a2739c44b11915896b442ba1ae53777ba23f21cba23f78aaef5a881f92d87827e27990db4de004d17891aeeaf1f91b86dd3f7e1a956f960131b78b3d7eb9789e7a914c4a635ca5181e1396f25b4fd71a7c3da7c1406337390163cff9cd04d74ac34d4debdaa4b4cc212fd5aab3031ba539816be8ea7391ecaaa467041590f36d2a68905e3cf2f5c33ecfd2fcc982d536ee9517069a05f4d6c7fec442dd12fdffb0b6ff021d2f981b44c22d9ea74d2f49f34a43fe96713878f9f0ed43b7864d2b8155dc48a377f93f07a0432c2594ef63c0ec8d26276962c91898643674cb1b11420991deb3fb49650d5c009586519e166fdd0e178078db1554b9484be3313629a835548baca23beafc403e15b89be58810f1eb7aeb302b94d7ef6ecdaff0866c28a98a3d3d283946bed126396f3f3f3f8738e7b69ca9c7c5e856b8f91f325c342dac913098e775af449f0655b6dff597a74ed92187a0bbada59fdb2e23c1c76ddeb19eb017f9c0b0302052db7c6edd11ae1de302f97a4f0f0d95dcc3c2c3e58"""), - TestUtils.hexDecode(""" -22AA98C685E1552B525B4302C943037F668279C224B6270DCAF2B06C4F4AB1254C48DE253829FE6DFFA9CB6BB294F054711BAE3FBACFB900CFD1F0844E55D51EC6F697B998759B14C13392DDB6F7DEBA77FFC22468781CE402"""), - TestUtils.hexDecode(""" -5129dae7c620ef4c5d6b0e0f7b43acd806adc035cfb3901e162be14f2371bba72674649e2004b4d055ab533316dc520afa8c80e5285f40f7ea4ef876e68b0aa4a559ec2363032efe5fd5a1d5050be8221c24b23c403ccf71bde5410b7e5ded038255dfca9439992fddc4fddf96654c78098c84e0182d954e204510bc7e5635ac29cfef21042bd52dde771a500099c75311c8657c5fc5bf303b7769ce8c2de7548b388224e727505c42e6bb69d48d845d9a43e845e7305a098657385307ab23c6bdc70de07868ecc1470b98e2da98fde4636af76fddbde6af2b60b4f27e38d4a86bed60e6f995533261cf91a618c07df0f659561f61bbbd70dd2b020cb04ac1fb6ee1a31ee4f4ae5d0bc2af22d60701700a44f2e8d11b72f4d03b3a96e2fa491e6e61f8dfd3ca678e4eedaac1e6bf418cc4a34b24bddfce3975d84740f7fb92ac2dd7aea450f91bd6ced924f7204754026f649868ccb103100b79d3ab2fdd2f916a76a6212bc583f1f5e541dfbbfb10234681c42ad56a95331c90f5e8b3be82a5b82ed4292094d9d60569fa760628e082740bb2da0a14b2516dda632c007ae3089a2068d2ef48b3f713999a699ab180ca99d7c49c4a0f40b908dc51d9a17db286721f8541839d6acb5eaefcaba5b1ba21e5ace4be0924eb0246e4d195a6eea6e962bb07bef9001a23dc0be7497a1ac79da047ed45b4c38196100b7ce06f466df295655076d14308d94d55103d36799a0683573768bb6baac4a10bd3120e9d47d7798121ab46521d7de8d1c3cd9618347d8947c47676c547231e5be77153f02a3eccaa99a75230e45fd4c1e6a6f951d1a5e6c3be098caf4a16ea3ee88473b1a8d91c0886685409ba9a099bbc0438fedd280f459de3c9c57c92609a865add4cfe76eae9af088680f92a68ab78765f7ad0b95aadfc0a91e175f07ab1f0887b1f448530866f002fc089a63a2e2d33ba63ca1985737ab0b9a73d23af11420d62a8b619dfec0830cf62757ae7f0402a4c0f209d03ed8f1731db5079dc5671c19c5bef712d34479b7f879dbe694e1bfbabc9c05109c615be763dd9ff5ffba888f88b62128b09475527d12203ae67f1ee8da83678b8a4b7b16f7700f919874eaaca48c10cef50a0f447baa17dd19eda59a1f71ad1cdc88e91fd91424e8c668fc93690b9b5914db40ba677a3c71a6d2cd05f42321463c12d55de1a717f69c132dc35e3bddfc23064ee2183e175e1ead1d075c7c1115c8cab91677ad6b483d7151010a7314ad558eafc3128c2dd590aa4e32e8c86cf769ff58ca5f37ee3a4ca0c9f9b2c4a9cdf2a8ae52d1d09110245a8884ac52c597e97b0b0304ee706795abed33f2f1885973253da8728742b54d4e908536c93ee11c1cc36da21d8ed4956255c0a28262baf50ff4a8df767e71a2d920f53b25084ed2cd8069fd13c0d1ef81f6989c0e93609038e9c6174d2a9333b3676ba24886917f32b7316d45dc6e99497f813b599d0bacc432ede0584c654551d3217c63911654b21e0631a5f7abf66d48b2cebff62cbf41ded241a59816fa9ba99cb29a9d000873fff81c689ee95bb9fd31a31863e1bf08fae8b27169c7705344b7085c917bc4434c9bcbaa27423f634233f75b82ebc7adb307f6cc3310ba95478572820973732f4cd3d1f749b728605ffdf23472810d01f6f9580b3852a5c2c7be4f93615960541eb2dc4d5557dffa8646d916370f89e09947e4e14092073357283fff846bd6b83d81092639de3b6ee260770b21275491a6300c12d5ad261f19d8081c9a659bb3f45cff2dc6c04313c7f3fb1b2d4ca96a603259310628356cab1431bee201ef7181f0f9d35e13b6f89a3698a56c3fe08a76418b6ea10b70bb2c0649f7b506f4b15a2578902d6df4065d4c3e79ed26a0d965e97b5ccb47110cf3317b7d90abcc9c7567ad4f2c11c5ca6617e643ee55096894c793d18adcce74c19620b112ab80152984de200d4e4a6ee29ce266b47d662accbb42fc74e7e088138faeb06f32e469d019979cf0b55aec3f420f97029852379417498605cd513fae94c5a5bdf3eec29c54634b94c6a96b0087ef2c8b2e32ad49144a70d27026a5900f9bde658645190ad83583ce8d4a174bf3956f3a581d7e4ee013a4263172d09b3e888299a06a0dd4cdd7e2a118fd753791afd91e0acc9eb1e4d3322feb169e47ac2e9e3e47908f293cb7988387c956806bc4e5bb9f65a84cdf2df9376c2eaf3ebae6a9a710da2083af685a8de79e9e27143c6894a847aa9134cb184b7dc7028b664246dda558891bdbcff3af3a5e0ca8ed06c1402d31cb5afca6260f4cae55fb6a6781768e6a1fbeedaaaee620ec0b7b964a38bf46651de29e4ad7247359df1cf4e50e71f691b73092a2f75f4669a145ffc5a51d51187f42dba767d28a39800789c88752be0c0e0b5aa2aeb3737f1028db4fba59dfba974f9ed8734a57f1f2db29d14f708cb83fbea9e4889f6bfd6f09d714ffe825056215be601bb8b6168d787a6d17335b87986913ff6aee38ad38f571435195b439cd82930a3386ba6e304b72fb5cf04b1ad8d64d8334f5ce0d14718232c613cc12ac1341706f829fa50a5c3010f8d5daf04c3bfde5ba88fc873a2e018d274bcbe85a9559eb224f6c23df124263772aa1262d9932ab813f50317bd7d4a6b0cfc207d8dad53d193d7330c9330d9bf866047237df5baedc69ff546308d2547b5c7f9e0909ff97da474bd3075413b94cf97fe331201f2cb565438182f13acb95529fa6cbd18ef92dab1bd8522f332ab5f375fcfbe01a83e38eef6381a032f9adb60b59e5eb54786f5dff4f5e003b79c7e119663c38e7e9baa0199d3ba32235166936a850c57227b1a16561ee407f7bf09cf6671ce0d0ed0f9d7f916a0ff7f41d8adff8c42b8f4640f1488841cd3cc1e38918dcadd752318080b4f15e58dc7f79aedf3805e1cffc25bb01591f15f54155c59a798a8bb9d5247eeb5d9bbb3abfd65f0bb65f119dc05cc0105475fed4f006e61a1864a29b53770e5b3cae2fa13b5a0d1b05ab9db868a7b1349c9b31d1a1abc19250be50627e8f7283af7d12c57a1c110cbf4acaf5990621d5c04729d475a97cf21c5fb252f5f1514b8d3090cf6e4e22a0146fce697d88d0637b3a60e77b9cbf527c4269adebd5eaddf12633c53f1ff09d869a846d3121371aca8252a5ca1f4fb1b7afbbb3256e53a9f25a3dfbb3a95e9beb67711d27689a28aac998b3129861d9acc72122d43c300bd58d934bd9aaff2ebb55268b94fe7013aa8670a89b19e1cc5d201ce2e73f6bcd8649a18f8caf1af021d374570728690a6cff0f3fb04050a0e17344e7483879798adbfd2ec112325282a3b5d6d72868c95999da4a7c7cacf141a1e2c5e657d7f939ca1a4f3000000000000000000000000000000000000000d1d303d""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -85c8fae58f6c8a7690e2098cdcb1e487e83a1ff669b31724113a0d9f796a68c81164211555e9d9dfec48b46c5eec597bac9fc1fd484cefa07338594b3634b8b58639a8d50a12f76aa7db8ae4c68e733d0903eb94ca3c69012c0b674f198c4f8cd1ed5c345efe6e94d42cdcfeea184fc0bd8986611968503a96f0f2dc5dfd56b6880f211f64d23d4c4e0451381d0a5b917ee0d31a6f782de660381b0f791b371a71506a12b8ed520b9843a34c29abb0795fd661daa226bad6e21345f93ac59aabcef6b7404ecdd11c52fd7c76b5d7e588562489b2a27d039214f41be58f9dc89a6e1daf1d47d6324d96f9dd35e15d83fe686af8f3a65f99a45f918e43d404b481130a1039df8f453e53f7df54ab4fc70006dcc578bb2b2ee96c4816856142de04e43215c0b1f33cb3381ae07062a2698967e965539d435f9b010a38336c303ce8a41591e9cfb9b5cb491faf8b60890a313dde19616a200d844fbe125a25f61495a48af66ae3a490c415fabe05794c841e5e8b27c39e3c05fdd2bc44baca13cbcae569998c172e5325b3f89464d8240273e7a0da097ff7b4116ef1adab1b436d80150bed523682c9ceb8e308b50761ea061b6aa23a0c9e22ab02502f8482183e13cd90a0826698ea63da26d60dd3f7b6d514efba52f351822bb7b2373c2a33318a20f4d74b5bdd17b68e7aec62d80b09278a051c7c769db9a3f416cbc9ba411af50d9ffeb6665cb5b40e0cff170460a6a26e37725f49d1170953a4be705d4fb88086decc49303e761b7bfbea9f289f49378a793bd58be0a34ebd819fd40ae07edb975414dc4e61ef23e5cd503dadd7250e50ab8c6236c3f1b0d836129d735122b6c7a30080347a8140185da8a899fcebf6d8d76387feed318be512d00e9ead0c2d5f8d14fd212019bd68d5084fc4781089d867678fea30c26788f1e724f1a989d542dd96f4d8c30d30dc819eaac63278334a44b4d7b8b91cfe9e3b3999ad77d72605ac293c135061613991403c2fb84367ad98efcc1e793dd717e2ae9e24b8f7ef98f1739f46cc46b7d4226ce5c1dc03b5aa14ddb72725970df13bbf9c7dc607361661d311fec0a6e44f36e115c18b78b9d1949ce5eb36dcefd33c23c53c05b2d17289453fa359d2bb1f1ec04c604b6b356cb86870215c3e474cfc893b1141868958e3707e3d64adf77d4a3c637be8bd7909f0260d91a48f5bed9bf42bd00fb9262d9fc1d40af8566ae13b4043d274ab0a87e9897ec1ea945b88d9eec3beba831999a4acb35e42a3639cf0e8d506b61dce0f0df241326f9892cb93eb1e0dc9fb57ceaa04004ae2a1274aef2596f3daee8ffc4c07df06b476efbedef82325e8adc14279dffdc43592fc8e20ac1f307383defea6e97ae06d96272f4ff56fcd97b15f7fc48b499ab625dde351ace7b3aa8dd6786bb3f376407aa7b1d11aab9a587386ba98fc3a255ba62f00191b464b28cffe3806a0541ddb97308d1172b62353c8e724aa2358226b11480e3d93644bcb552820b86cb46f4379b1f51ef09049c43ff0b97ae65f44ff03380933d80e733f11eedb8001f6ef3bbfc4365f7e1e242f88047f7089cef1385bdc0aa723b1a7acec932884b9df3637bd9218697b91370462ebe8de16163d2aed8a32c9af887f7b282e13fb88c0b062fe2c819217495fc63e81c7b26cfee142ca9568bac3dba7edaa0697976cceed5963697248475aa311a17cea8a24819b8245fb1073de9f13b24804caefd25502940d24f40b5993b135decebe4ac0abfc611185bdc4749646d72f47326b2318c5ce173499a189fad25a2d2e830a381730d5e8c43d3bc3862c6324f8765413468a39abc37631e98bb79059ed"""), - TestUtils.hexDecode(""" -0B0F604B53752973C4A72EF940C3FBA910AA9AF2916D673D69C4AE4DE92A237F271E84921C309B59B92E795BD26C5C015EC5176155DDAE8FA17D7BEFCEE3A23E0201669CC55A6F270CF0D03FFC09BBE4B47D318B6926808EBB49EC8B57A849896E76648D51117E8F518088D66B69D88E09D298186C10B5678EB8AE43E9C0A794C63CA9D597C4B74C959E9C1E8E0F46698CD64CFF3C0FC6174CFC51095E142DED9F16E5B2D3656555D2D42832280164E0C10C5817AE47ABACEE7C3BFD198A21BDD1C420F2EF0776E5EEFA46E8BCB49388FA6B937FD1FEB2BF09D5B9494A534F19BDE4E7BB8A5E4C558C2A166006B481A7C5865069A3DEA2B880AA503B5C020F045A4D9C3E5C590E4AD5375E74B732695A11164B5A57AA665922431498A9218CEB9ECD92700E92BD11E0A8140938C4FB9543FA5DE8EDADD1EDBDAAD11A6AEFF2EA409638B2C7AD546EFE390729982304F35D7F889C0CCC81D67F5A1D6201BC4BE8D1AD2D3CB85815CB9669B56F845148DA0DD2D6B5D7C4986DD3F10BDC78EAD8B4A88B7AE1FE11C634355F60A43A55C88B37954CDA71F4744C8E2B4D7F8D4A2BF60EF0C44CDC7F7059AC48A94B10279921709827A3E1E7A46DD857616E6B737CDFAB71CBD47639245E392DC116614CA3F099B8F2092AD667DAC43B8501DEA9876E5E0B98B41733DA63A2517A49C169A95E583F18F2E1DAEB4425E307509CC6B0B376827F0BAAFC2FB2ABD4E4151A8DBDCB8C22C78F5DFEF0DD1743B047E58537866795D67E35358020CF75F0D2B80287D62AECD6D34D18494D01B4412B1CFF279CA69C18A263E7B862F514A7A64BF192586ECD460D22DD2280373A66ED987635761C3CC34A5BF6A370F9F8B16F98808767A2D9A1517544D869E674980758B15BA7844027D3593432101FBC51FA4709F4D041BE9FF31DB9B7430F1D7F8E06C22C4BF3F8798D50C92641CDBF0B2C88E88666029FC985FD4E9FFDCD779C7F7600D02AE8D9E3CE6FF76F0B449C41BDB785BBAC9CF58ED7ED1525D7C7E885C0D46ADD0F7CC3B14394235B9176B69A222567E6533870EA540F4DED9A1D78F2CB89E6C1DEBE67249ED8F31C87499E24DAB0434FB9B40EA695499C76A1618A37B1AAA5309A914B6574209A61DE0633F086EE4F2455299C70B981532A23DC453939D223BA3A25122AD498795624C727E973C052E69AC40AD465DF55ADBB20FEEE76BF2906EFA7B0D9D5EAE860FE02500E2E0F4A21CABCF963D91262EAFEE814BDF9775874D656F8BDE11DA29327E3E7C7C95395D0DDF766CF34005CE86592F6787D1044E5CA1962C4DF2719308B2D6335FAC77DF46092CD3D5D228E381BD7E5FB4D2EC18B19E18E4748F662AB34C3F2C33877BF4A8D43A63F9B5DC75861AABB42D34EF37EF19CADBA110A3807D1699B247BEFE3D61AB84941ACB227C79CA05180FD3415D0E76EB31B4DD903D78553F2C22563F9B22BB876E81EDAECA4B8FB9415E2BD5AC32CC08775A20E8F90A1681C9957DFC330B6343E58F841906EE3562ADD6AA53FA1EC4AA2E894AFE769116E29AF49D0FBE2D8FEBA215E470ECEA81B258977A0FFCB17666953C29B2F70559DA00610398A08E0A17D69705707569D6484C4203C06B17439E9D4D9DB8456682A79659DAB332DDF45C67E527304013A422E46F2989BCF033DB143676A4EA720D0DD75584298CBAA765CBB0B09EF267D503F2782A427459FD2A83676DEA43C01D288429A82527A69B1EB19DD3BA1AB7428220BA74F79A81377F7ABBC027D96903AF6ADB4644E9F5CE676FC4D3ABD977D6438F4743476F77F3DA6E822AE61E0AD38549BD21E0FAC1C963F1D47F9E6BA6019591DE22BCEE5D5C9CBC4106A369C04BDF633F41EB1D6821B1F43194CC14B02B753584A659EA46C49B983F592C83BD959690845E872B471A38381CF3B2E8F4DC157D9A60FF56EC63B1C66D2227A069CEE7E48DB0E0D5991F96740D364DF89B08BA67098652958A14516534103ADD9E457E6AFC4DE1AF332EF3ECF6897B3DC8E5D6980FC5E5D829D4326F6023F48CFC9D0D787416EE61A0BA3CFF5E7C69BC83B18928AD277AABBDE271EABF8269701E526960460EEF521E83CF7A61A3CAABBEE1F1C99402EF55FD438753790CF56034AEA3292828AE858B2D3B9C8D77FF4545FAE7B4F2AE1EB17B8198F4846A8F4A105CE250F900969696E477B2C46AE786481BCDF85715BD270F9C29BECF4579F2DFFFF7750E375113E33ECABFC52E4DA5405849FE5D5F4A17C1F0984A1479D561943CD1120037EE821A2B57A12D7F1797E64E38A4B71E2FB10207ACECB96B3F3ADFF82EDCB633E388FCF11C8D105C1F6EDD41B553B4B559C3199745F3B0EB7326B867FD4CEDF4E9ABA1FD6A10E1494847FB5DC83C91F7A2DD351CD1AFDF95865701FDC658A41ACCA58E574B67929EEFEB371589374285148EB09157AA9A67F2FD54FCAFC1248F6D84951AB1A676637E9CB76C17C282DB53B1BEFAD8019F51B0400DC1CB012B97575ED81C129636C38998A2E6FC5AB7F0BF1FFDDB588BDE4590A7A0F879FFFC1183A3C6CFB341FB518D0786A6473FF9614877B1B722AF4B2E1E9B5E0DE7C3DB004EFA16F5CBF07870D7208A93A9FCE0EEB598CC54F04B1BAAA992C02BB2D27217AB20A3381EBEFA04CCB1F23E59E4B0DEC700E069DB7620E22235A4C5F54522D96ED4785ADBA7FF95F2A7DB212D3DD05E58C560E5ABD0EC238B7ED01E54ECACA7D32F7C2A3309A437E68C3AC7A9BC51025409A2A1ED05F8DB0EBB647FEFE6222D6F74DD8E4034580B675DEBA4BBFADEFFEECFF4771A0C1CB0ADCC6E9B050B85D230F6B288AC3FC24880CCBDF9C6A6976D46797B75B8532411FD89BE027CD8C81547B24B535825695A35BCDA4E2E0A3A6BCEDB73DD10DD847C4A0AAE059A07F56B0ADC0401026648BA469C534CDF6E2CAB8F581A7233D2F15BB35DC990EFBFE688F9B9AC5AA5C9B3E95DA7B0122947DA03AB9DB58090FF14B736B9CAC65F966206AE7C84B971D83944D8AB61589A28058E14193751B685058E632E32EF1E8C94BF005A3A2EC5EE2CE2FF6C05A67D87E56998E952E4557250E8AB5A979ECB28B0EE41DEE07F919E67670D9CC4077DB0D90ACCFE17CF6AE69DE0C9DBCD3D552A7FB37383574692A267B0A8BDCAF3532AB47887FCC94AEC3461A9257322095F1024C880273222295107864903F3DC8FB353FBE51C4D89F30FEAA5A570979A38B0B4AC9A4AB6B7169984C576BC4AD6DA1719CD0D5ABA03BCBF1336DE48CBBE167E4293DADDE3997061469F200A391646C8FE712EBE087B448F7A7DE437186D38A4CFBFC2919FC888487B15C60E93373D076DF6A60452E62E05256AA66BD1FB771CADB331661DB4BFA47581A4367069FA20E9C6229F79D6680125D0464F7CFDCA1F5C46688D5816CD90862FDABAE753E56BAA1369AC1AD3530630998CEB4545C4404C8B9A65D5A43443624D62DCEC989AA2CB8B85414E06AAE6BC4E219C5A3FDDF8FCC75381F6A0F73F54A7A2B5BA0F546235E71B233EC107900D8116CCD398FB14F32CEC310AC089D6BEC40255A6A877C30B05355544D115E8F85E428087A5F3670D596E31D25F676B3C6FF444AA0FFE5011AE62D6FFF86E615EBE80622BB646A318BC65950889616DEC254DB332649788C07E46CE590C2362EE66BB33BD43807A1336B94198BECE586CBBE3136B5CC809F24DB5BC3069E9C1FDFE53C6D1DE29DF48A9000A7E89D6862A773832DE2151423D9D11D722D923233137DB6F34F8DFA4EEC134BC9EF5A70424D895638D1B09D95D98CFA17308908D65AF00259DFB5ECFEAC55DD7FAAEEAFD4E94EFB36698D2315D795A93B8BA6A3CA93F6B79F2E599149BFBFC6F5C5742A83C886BDD4539BCC128F30B370FFABBE724AA3F3D571785AA6234FD2359FB3468A06A8E74918EE6E87CB29178900B49891F565A80BFF302BAFD0D5C2C123973BA7B9B425973CB3D7F2AFF3059D272A7CE611F5CDDB5AFF3E2B4024FDF0E01D7AD1C63FB47D9BA986C341030B3E5C6CD3CDC6A3DF9D6901E76D31C141C37619F5BB316209FAF8428AF19236DD426D70EC81E77309D5D9AC33CF3AACC0259A19F91E4579AE49EEBA41CF79B9499CD1211AF1E6DCDC70383A35E0ABF7B53A1203AADCD3AE638862D35EC4E441100E8CDEC7F0E6D22845F6CDCDA801111C4C7F261189C7D67B981101C40F21D33D05E336F1C7443560238C72B34E47758927E37F972247F4457EA60B2546F6B5B7A91B151E8B3800CC1748587E0D5421A43648BBC5D87C591B01C229C8104CA87C0B7F0770ECABD1E2A858147B62F607A86E1C71EF73C036B18C01CA5C1BA8242BC4BB7414FC90C0A8372F860F2EE51DCC1E457135776C377F940400AC5309112E6742617FC226EDDF51E95CAB40CAB58CAE1E662DD78C6E253B373BE970129193DAC7DAE372CBEA847248C2E69273B7CFEE70BEE59DECF64126D44BACAB5F2813CFEE1EF89AA3FD6D030319CDCE94FA86E4E64998266082F8BF74877038ED888C16907A8DF99BB53809E54520E4B5B6AD44849A33EC3FA44A7B179350DB07524823FE8384413F0A7E1936D8CAAAFE1052C462778B36AB8A9A14BCCC0319CF6EE2AFF01EF5077A10BC0FD0DF76D9B806481BAD1F49EA013942F38BFE52FB194EF8ACB283B1462BFFE4AC618D6FEE7E25130EC71D68C81A9532A16520075EBC1E9C3FCDF5FFCC150F3815E8647F34DAA814935D0E1AB68EC6A1B14FC7566415CC11E0C14A9693B8711DE2D3F78EBC468269BC851D2ACDFF5E8A6388B73E33F20C0C7621C6B644649AB088DC191418292A698EFA4871224232A7788EFA2D69F9F9FBE80FB8E6B0106405F6406D00A6D6185EB521372CEDF51C2E0876C7A86A90F1F5DCC0EB3187DF8BC62736663F713A1D403665BD5AEFD6BCD3413FC63CD68B3C5C7FDE3AC4164FC3737C2703AAC85E6ECEB29E34A6ED70D4178402814B5207ED2AE12E9DE009D0DE6A0BABCBC4ED41D5C28B1943C4B61D8B1DBF4395F5BACE1E47ECF0EB9E21F9E7F663EAC3788E935A1AF73B19714ED91BCCCDBEDAF1C74155CF235A58485BCDFEA58A929ED1E959DC99345C36109E42A14438466B1F9E728801BCADD16B2D8F762E4BB8B3F01E531339DE79634F43117DF5C585D7D2FB4A5D3E82BC25FD92BB1298AC79211B3866CA1019666AFCB10BBEE1AB63263F2823A86DD3EC57E8632C9F4975155A01F22859EBC400F5A3B8302ADAA5892A320487AD077B144392528F100F0A222DDCE5636AD5962AC6D62A2382167EA977743CAA6BA2F140655DFDEF168BD620C73A47A8831DFD66DC6F2A9F47E0724081681BE62FD15C74846980683B729AF1757203F457FF12925B6B7BC81775A9E5C53862B07D4B93CB2E9FA896AF58D258384115F1C63779E4189832C29C8B142DFF30C00DCAD2328A63C92CD1E42B2A8D2E18542BA3A81686452C83AFD5F6955A708CC1DAE500718C6DB89ADCBEBF119C4707B931E685BAC00AA60E3B5F9F42FDA6EA90F5C77295E84A3AB05D69212C5368E24F18F43B450181884D7AE8BBC61E1603FDEB13797F9620AD6C2B863C495821F7F726BD5801A3D5A36F4609B595B7653799B3794E4A60090D71F5DE1AA5F0CF562F7E722C55AFB676395ED988A491A34B462B2D18AF517569531308B8190F0148CFAD463802AC62C6CB289FC0C95C207AADF82AA7399E0476B774D9B876829ED91EA3E5C40B504370D266B7B3C72DDE2CCB7F3AB8E820ECB5715289451D352D83DB67EEA889EBF9E8B012C8265376C841BAF6EDA4067A400D4C6FB00539F3839A8D0B29906F9923B9244132282E38242257C339A0D0BA8F05F75D41ADA51E29E33BF65F78981F04F397BD5F9580376A8D1C552363D6BE90EC83C2AF748CBB7783D6B26098C641777A260F5F60A712C7A7D1CE681CA1FF969B8F25B90F9A2B03F71E06A848DF3C5C8571C5626D5A1F123DD14A9F90B3958A7EFB3FD522C7E83F897CBA80B95099F1705E1CB22C7E91DB644880F7DAB480B29FC0F8E1D0ADBAA123F1E1FE36835ABEC924531065354B77DC1082DD690B316A7BF104140F6316C46E81E777F56EECE625EA030C1FFBA3A4D40745E77129230A69D76C226A80A8CD31720B08D9207F22F8F3068C169B41E7136F94B73047377A8AC0987490E4DA2B7619A760E3B61369BF762FA9A3ADCB014CFD0644AB1FE6D8D3EFBFEC893E98289DA93AE19D8DE41AB33FD717200B6949AD21B3290C77D5B1FA44EEC7D0C6A9978D50B40DF77823FF2613BC80D0E11DC2B790B332D5267851B6315AC08D0A2D6FC0A8F93DCD20DA6054894F84C88CE254057CD2FE36693F868D812DD1D978897597840CB336223F8A8EEA9C15AC05D3E40333391680C4F4CD5C2F600CAA684BF09EFC8A9B71E6883E9353C22B379BB6ED8ED83A2468287121207D9ABF61D2DD5116D3B163F262BD3D57A23EF2E6154BF6EEC1DF88B961C4505F7CFD2E23E0E0D245A9418292A5AE6E60F3852D78D19E1EACBE9F42A522FA57554308A1D01E31DDCFB7C38534F7B48E0384AAB4B81A93681ECE4C55BEB089092E757A4633B2F30BA83E470B3ABDEDF9135DF22E2B29CCD0893C54C329DA1B16C2FE4221F1C7EBF6B3D6DE84EA1DA57392762FD9C64C0771966B0E1FA9A6E286C23128DF317F704237B97A339A623C985BFD6A0C60DE48EBDD73A0610A22B02D0978E626B50171FC8390B80F37E5E536CC184259D4ECFFA958DEE1A27CF3D2EFC9B218809909B19D573EF86087A1C9BE161C54DD1279E022F98030669FC93A7BF03FB101A3FB5321F654D2B40EF8298844806BB66EC32F7AB3BC7BED2AA7F22AF20759B12A0E3F82D3C3A141F393DE746D5A0D91F32D8249F0DB0FE37D27E49795C648EC6D96E352115FE4F10D1F56C39FF9140E3E87F13AF3C6480D6150E1B7B4AE614A577D6E81694C19E468761039E970335FDE9945F6119F6ADC184C9F2A434C681D593F34D258F2A8847E02DA5EA2605A007B25031DCCBA8A8C50C77411D197E742D4B3994471AE84E2B612B09B2BBAA38C5E71C22A8E3DD1F284A681DDD45E962F9D061846EDB9713D4F925A9DAC0E32D2A4496F68C68448EDFA87FDE3ECD47411AF5DA95D8C48D5CED988AFD72BCB7A81896EB1496F468D4664A58EC3874BC6FF6A85692790BB405592DFAF53CBAC93884A842EB2D3DE9619843919CD9D68AD89DC7A84BE54C406B8208428066011807D722C2B34D4A279EE43BDEB967360D9BAE50F654B2A06B576B803544DCDDAD670CF8D2D7723929842C6AFC4093BBFBB75D1F5E03682500AA0A34FC66CE4409D08C726552ED5ABB0C646E89B35A659C67F6F398D6BE39D9725BB0322D458DE2A62E46B62013F2BAE5E60C3D41975C6A4C6231F4B0EA2827329279459840911891B0111FB4B1FE99FBB482FED56C7BFBA15882CE5E2FA2C73E0B682EADEE6F68E4E1A9CD92FDC2CF30902453A16622AAB1273407B985FA4B7DB40D87812F2A10183464F8173D22D5603C44586B107B4B82E94DD80E87AD49E9C0FAB5C3330B74E89F742CA1A5940F0F329F56DFD40C6869D0BA8CA412AF9C5116ADBB3C22080F93142C7778D52C4D75F1EABE13FE50877C26D7DB429E991506ECF1DDF30A00F9E0B355306B889F41BBFD1B4D27B67952E4A0B53D1BF8B2E84497F00826D84A913F02649D5145383163F3C3F586EDAD06F518B64D9B300C4540A67593B9F3358FF2A22AC4BD7E7B9AEE507D184E039ECA3BBA0B5C584D3359D7121BCCE01691E11C120925A7D8B100751E8ADE99D3676C7355BA4BE451920BC7D2AD6E8EF0A9693F16FBB570122FE5F5FFBDFA490B3C84809ACD898FC0F807C77937C7CEB6F03308D3E9C657F80730EF3A1CEC6959850FAA6C158F23B23D28ED53BD77531F1012DC1753CE1AD6E0A629E14BCCE9D56B74E09AD6EEC9DC4A5C92049D48AE21222AF706B1C4DE65AA814AEF5B7E1EDF2D8A9C5B98853A17199DDC3233C5583B95756F5A9C175FF7D0891010F5D36A268ED5C9F58433A69185931E11BCBEEECAA240C2C5A4ADB4E770109F3F16CFAA37AF98E1228FFA7C584B13F850FED0187FB836E0A01B19CF700849EFF09BE1A57DE41CE1D52EA6F182E0DDDF741DBD2150113B10CC3D9E44917E0FD9717D6D361A88060E202039AAD8F31E4E6FBB4D7FD1BB5D6DC20C3D83F23D120EC98FF4912F3D9AB18D8EECBD7EFD1CF9B19081B38CD959660E8C63A539939D0CEDA897F5ECDFDEE16ECA492B216BEA35A167178F4A0FB76175D160FE2EF97BD6BA0E296922CE60D91FCBB3343ADF477F8A92AEB56A471B0711CAC45DA8EEBD21FE83FA68EB74C8502C81C65506C92C4A3F19ECDC2B7A5AB47704DDFB2E8D5AE620CA0D67197699677EDA3FC4FB821BFFB5F2DB03D4DDEC0BEB13EF84EC372A5C56C1E712C8D23D1A2DB1BA077645C85689CA2258E9B1B807DCC6394680B72938E1B61AC3E8A5B9E84BB4B58CE5C8C2246A604C05701C026185CFB872BA78CEE33EAFD0486A22C6D5CF9264EC134DD79548F3CF5FAA67D8B1FE74F6AF7B897AB0A0D8CABD5E1B2829CFE66D58CE00E68C6F23FC35397FBBF96D2E63825C96BC3CEB22FCF9CA46C93538F8DF566145D06207533627B665E39DD284F4275051229F3CCE9E9E62EDDFA55BB2AB1D1D8E8E6145B3E38F35F90B89C15FE799EC14F7E415FCE4EFA72615EAD26C10C1FFA4FDBA2EE04C4845489C21BE45C478D8B2116C84AAC21B48BD4181FC28C7C21AC9CF95D8B04C0D817C8ED8083D9CF8B81213AA2E3B8BBF4AD66A7AFDCDC4C420945F5B3E8C8AEC5C4F98005A0CE1B3283F5FC0FCF8567A150E12639CA85D298CE8E4F9E0C53817D3009284A5A0BD5D3A07234AF751AD059E301076946DECFED43DB1176A2BBA4B8A571299FDE4AA3574B6C189A721674E004F259B00B26EF5AA90794FD622040B80CA6C5E9FBD44B3DB21290353878F4D8D87496E374B05E6A5B25742A885569DBA2501367EF4C549BD5CE6169914A7F1D311D52CCFBE2091F0DB436506F210C137C2180B89626F52B4192C67ED06C1F9175E44B9468E6FC2208A98DE577962D9B4C31D5B0DCF4017DB1BBB2F80512C89B9AADE69DBD584452D25CAC97A4A7E6F48BCB909907B93F5B8108EDAD38CF7FB541328C5E8AB867DDCADD6A1B5083869E68EBC785C80ACD260C715624360F2F3D78FC1B2A464FE0525059A3D5E04BCCD72D23BC680CF7B25C5CD2AD6A0BB8366DB24B671D5BB3C12554D37C7A662AF9B9DB61DC6C7DE288DF1976DE08743426CDD30AFFDA05A8390A8F3A4A94D7CCD33BDB229E32850A77B2256CC595BE515F9E6854463966D4DB7A946276F594AD4BDF0B9C59D4D38E211A4465AEE023CE6C062FDF4123ACDED834F672C1A724BC17D44DE9632A588E7EAA77F3183E09D2ED55099BB1AC8198C96EC7B1635139980D5CA4B8B3102375A2E08BC3BC754D9FE659C3FA403218BC8C00FA87A0FA6F096E336865DDF02BB05049CDC9680E99C4F567ACD25AA7CC76C182A8DFC174BF6FAAF4D2553A4207922C1EA10CA8DA3E35DFBBFB5F6919FD4088A3A8E48358CEF25576A3A6447980F1C716EB58E755196A672C378F6615E54E9A16CEBA33CEA918768961C244A561164B61754F679856575DDCB32C70447BB738E84CA590CB523C6553F13EAC77461A58A7D4E1CC1E36E7BC5E85860B0E6B67C70D398AC0BABE1F42426D9E7F12B5E362BF3BDBAC42C572730C5F4EEA957FD3F17050625BA9D9938380249290AAF31BAC"""), - TestUtils.hexDecode(""" -d90e5ad6ce804eb56c37cc30b96369f19a67ee324697634f7a40b3d150ba7891f9d8e5a7499781b5ef8f462ce1626eba1213bdf47ea40203aa7b9f6632a02c172826d96683de98ef1fbd163f817d6b4c71ed7fc9ec3a2db3d0bc692f94812d69ddfa81c15292b507d7aa3642b100472acdd9db20f19b60d98e10f1f47fd8f1498cc618a00b8c23ddf109957b78ebb9f5a7d6167fa907f52e312fb333b224c2e1b9b45ffe6027a90efea98d854ab6c6de67a5f24ee28d917caf0014774770989a4816f39fef30dc70b7e068bb306ab404611620b9dcfd40e1cc72400e398cfa342a616fbd5eb075d340d9f1d095b54d01d190b055f21d4de73ccebaec652f982535919e8ec7df3ce42f6e0807252f88d4fae025c68e5dfcd9ac0af5af610608011c630beab1b1bc760c550e79696333b34eab93fa7afc68e900686d1828bfe2bdb57332a9dcb84c66f12638a1ca4ab413efb847078b79610c51ae1cd81fac71319f8e43d356baba173c9775f9dd2569c3699a2cd2e9accc5ff725bc951b6c007e7d7b16b5f3efbde405d7d945dd1fb38724c52958427cc14d7a1f913c2c911fbc50e61a1aea400383561c78d32a38677ee62b201067c6744500f27135fd789e6adbafcd841a2796bedebe47059a8917f5eddc09eedf7aa6187f7f9e91e3893a3870b307a47da4366f767045390e1df69909d50e57ce6b2656a9f9eea5222cb8a05142c09ce230dc49edd7c4107241a4f317577c135a656071335408b809a18588f7dba155bff5acab476e99e62b0249e362d75ac201772552865f91eda373f722d19eb4e4f66c94627667af033c4d4f8e6eacdbb2a6abf47c931527c66da42f8ac3bc1a9c38e88a9d862beb1785ef9e1edcc3aac6477fcb78bea88b5a7796bc6e3e33ff1e0ca1fa73e66307e409365ccc8cf5a0cdba2bc96a7150d030b1349b15469ba21c7d53c641402776d61fca08d0a6268b43c063f51f110b8708251030cf393eed4898e2fc4f9654c05e700ca3e9d9b68274556f88c61c35860579ccbbfbf3dc367a88b076a4618772cac1c225069ed77168bc9e50737d2502d6b102a8904cb3118489e39c31507203175b35a295980cce3f9653330307583e3cbe2ec1d6e5578db4e5fed4bceb20922036891dd58b00e0e98a408f2212c5cebc7faaee235162bcfe6e482d4d1ca012078aa78bc9001a021c14e2ce86e484ad41ddae6c256f05cbbd64d99d20ca4fd0fa65d3565bd749689ded6c835d1370b047dbf1da76cb99f43ce660654725a40f7e8dc99716bd12bc3b3cc140eac2d230ee9177c8766e3cdd8d83948c98ac97b28826918a8835b5b563e887fa2ae18fd47d2c56e7a213d92533f05bb608baa68518ffcbb15e6847a776029809450ff9c0d4fa422fee078fefb04e860f5edc713412436e836f873bca3515842f70841f400db22e21c7a9c1ae25727a39e7e00e29abf256cfd8817115303a40c61577ce6e914b8c6e9481165f554be7a58c22c6a66266222ec80f1af4c6455301cbd80f5cb42d69f524d9a121699eca6d78bfc4db7bebdd8d03f83a638882aba3967f377be4f54295205b8f284a341796b4a00ce517e41ad2ac1d1dec2189a702b957a4d5d67fa1625341266585a220f0c276e339c29f58b13227021b6631cc37701899f0d7a761e13220ac0c39b5f98c688571915c38f8d0a23811d11cea0ff0e319e2bb06ff31990e00aa254e671f350bb9be4a5c78a992ea5de9276b0c542e2544d6a9a2e0339805ab40a9066352e2cf864a102406c4a11268b0ea22d029bdf694cd2ae75d9184920a9a707ab649a8f422ce4a85fd30aadcc07d3dde5b3b753668a303267aa1e43c81617b6aff5c7cdfcdb66eae646146903cf84a014c696473d0c52e19fc5da06bafc475ebbc367cd775676175b4268b42132f2959349a39e73ed553fbb50c8b213e4ae9d8682b837a3d8d938d4a4cfa72b564a39f5137afaaa442b562ff09bbb5c2faa2197f227979a9cf580dcbf01a07da6239f709fa91185e1a0d0847d77a50a4825fc0c2a6dc7140de2d4789b1fb4587c2e9b24f33d11728071548ea967622a1b97af44b51b2300c2c87d1f05b8d0e710a2ea5e123e479717cda447c0d4cc2ccfe753e6da45c38f568a8c2a82418420fa5de3fe08e196f2e2c6691b7774f4d4351c37e974721d4c505a6ba037969034627d05014a543e96956cc991e583abc9125aac8324f46e71345811f7ed8553bab0d166cd8bfe2fc21aa96c1ac168b40c61aaa7ff5461cd2c1339e8ac3c54cb1a8abf0ca4e7edd9e9842a01a91eeb6f3702be5e81936d53f11ae7d191cc6b8afbbf1f78dec898a0c30df889f43a8cfa8ce1d2a324c15b501a0ace8076b26334fcf03bb3db377d285a812f3ad76c0ecd7aa3b76f9072e40b272d514fad2d661d168b00c2b27ed394d4cffbbe38ffd1e7b84bfac69b4fca99b8f316471fd37678e4501f16ae1b2acb472c065aad5b482cc893fba258f29a90e1faa8f4c5235f136b25d1e451f20784e6b761dbe4fa68a41285baa9634f7d87807c407a9e7be6e483f3f224367caeba42f0df19b5dce47630396ec6ac6ff1b5c23e02f599cad3ef117ff74d7331facf763c39ea70c2071087774ef8a2ff268f27d06b96e50bd52eb5ab55a9f5530339abe6f07d5a27f64aa8015b5d2a768452f8ca82484113420464d06d7c61ec25c89a422b788f3bae8e79c0020fc93122f53356a9e678087f80b1938e42fbee9efab604f959b7f4d8c52d900d71b24c39a1cac0831c22907ab3348ad20bd6818023a72266983678edad084a13ee07196fddeb52c79bfb925e3ef4bae2ac564b04956c0097800546e965687584c2738a2009b0caa15183ba1b6966488fdcca6937bffdd9cd6f51424a83cb6324d2c845dbcc9237bde7126516ea59d36cf2b63ce239db57c01bce472886eff29ca612510ca318398aae4618b8d6fd9f6c6e8cceb4b3dbe5d059038b9a6b81e07f3599cb1febf3b0dae4eb9d5e3b6a3e11b24aef1377cd941f94a56f7c7f1fd85807d9d97ea0aace9d94516dd7ee271880f4a7bd18b4266c510e16f95aead24a9d3202ef331028b0f4233023aef2d18aefcb5dc66eea08013463c008b86faf617fcb6929a2bb78ee0459788792c9e3b5d3cf92371f4555c0955bc746264cf6f56edcd8bc8d044c170610fe76edf0e875f9d6d12eceeafd955e0130805963455a348ce41788cea9e2601decc02006907f5e092fa70d2f0f21945a5f24edc734da33efef7efeb22c8b142d86a47d9d5c13f93258eaa396e3ce55b8f6ce736a5010a347b7f9298babcc6d7e4fb03192d4e57daeaf7fd03041d262d47676d8b8c93b0b6b7bfe4e9f9fc0a161e3368a1c7cce7f200000000000000000000000000000000000000000000000000000000000d162933""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -c298f170b4286195747d986e0de1fbb602feb53b5f242a12bfa2b7602b22358a3334e7bc913d08f6457753c611730936fabf6e8c5863a0ad142f8b4fa0f1e68ca0e588749fdc255de072dec16e7d62e2b4fc1a20cedc7879c6fad196e4f6de33df29dfd6df65470515f6be6c9f9273473a6a6daf1d58c279e81b578cf5192b839cea97b8fc3d54048772ce1c009aee0381e37f39f82585dae69d8e03ac9d0b2d9a772b0e4a8ac46456c2f98820d1111a4db13eb26a33cef728017a0d9793d880b9d06a57b8dbb41270cc203a0f4367e52abb424533a426034e6e746a077963aba533cc54004e7a4d17a0ca93904bf1dd4da52908cec4df9abe86ea50290d3c792bbd1d629610669975ec9682a4afa4a06a37b8c90a4bfc407161f1ef6539d104c39b14ccb6d7f36ccc0a573d79c70f5b1d1f049893a31a228e32f20ea84503a1b7f2115a74089e61ad991022b11757f5c361b8bda665bc96d6fc2b999e546e48e431457016de365a50163a53ccceb193fd80e4bcfd658aa2b916bac07052d9c17c6d0c8c94017fbaa1a1f4638cc7351dfcd4b5beeee945f5ccd602fea693a105c0834ac9d730fd0bfb83c4ea5d137bbf3cc7a6ed840d5f6a22f4891d29e8d0ef2146f2785acc3404117f606b20a13bd0912e46bb3e7b707f1cb348055ab50da962fdea841bba33d43fcc2a3dc4359b0f7648f648c2600e3c84a0c9cd58b7e05cd041aea383eb7f0b6e078bc425bbedd4a29d09e095e0e44d4778d6f5733581c29231833871ee121aa2c09e44bbd3c3b8411643b67b86494859623d9d135aad0153949af237eab32f50e9cae3a6c30b2c873a5416e2c9d3cf00cc03f29cacf723f9340810c632db0801a8d8de3b7ac08f6313800f7fe501a5ec92b28bd06731fa1b95023fb635c02aa6822d88a28d595068603def2116fc0405e6d936e327364f78329f194e1d9651d7bb607908089eb25d9dec4e56991f4850a32843f10a245d2c71b58e5b5954e75a00e276b03237b23e9ec3ff258c501710e1f7bc4a03b88754ea03d84adf76b0f5e20f3fe76b5fce6eb355941a2875e2ed797069dc9f4ea3659b55fa3eeba496a153befa37fcf3004a6502717f61754854855f7b3e6b7782099603754f201bd1f49355974bb4276c70a59593e44733cb1b5c99964d4ff89611a55a1d82a91b8ae03ca4a3362cadd29ce9207c9c836f989c09b590f5f070becff4c35b318a974a923216385b6b57808ab3fea3bdf6f17ac0e4e1bc0f18473bc97a89ce5358a8c4fa04859a915f15f9a06725c77517ea112ebad0a4913af1080700b8f700af9fee59c3067ba30fbeb995b0b88eb59dbd45a1971240f15fb40e0a1084c482a01bc773559b6b8e83bdb4ffb70df25cc30212e8f22c09abb514f8152bd1affa3c7856c90bdf8b4024a1a8af3d70c3de23999f36834659eeca8bf225e16f0185409609ae8ea5d861794481cfa5b75a275d9294543c4a257f3dfdfce9c91e46468b2235bb161850bcaf76fa405dccf9918a0e2903ffa5433412ff09ba73d3c3c342525c9f653feec2d5b1596d2b8e79612d913e2c371384d1376f56a2cc9268d9c82e80567f1f27434aef775163a8b162801bef77f299c58a3363df141c63e86c717a8091d7a079afdab2835b11be5f216116018d70b0512747a066abdeea688f82d859a79a5cd2a839a907caf5469d2758d5120d4f9d7f4445f0107645e63f6af7b9078842d034ec39337f17f01fbcc31ecc4feeba4588f567a6a467f8a7870c655683c46eb776853c0f1ec4c890cf408d2e3f808673eb455bb9f333a982e7f9f393a65dad51974b1a35fad8e8077a8ef3971bb823d6f9ab494868"""), - TestUtils.hexDecode(""" -0C39B65F4C2094AC626652CD33CFE44EDB2667CF722443514CAB443DC398A8EA009277BE397E1C1E7ADCD1B24376AF0F19EA50E56C90D683F8EFDE693F0F8834199544E2DEFE392B0BD46048A83C412A14834C4BCDC180457456BC72AA28F2DB247AEE84A1C49266361DA7EDD54BD9B562889131EAADAE071AE5A671646F49B2C1359382F1A3B2A6B437F87CC99A2A1BC821E1F3DBB311B8FCDF28546A479E2F9970870066A2D6447B6CE4FB65ABE7423910B9039EE3234836F924C8E82E1299335E27B0DD642B812480D6FEFC47B121A710827DE1D18DC12064649224FBC4526AE14317CC8E53BC8E9BD42BA444AD9B8B48C3AC807D7A7675F43E3021BA1DF9AC7A42A9E23D696BBD03FB5C4702B55F95854C41F470CDAD8A255436F910C089F71C2E59A44221D78AB81D4E2B059CC92A3841E1431415DAD4E6EB0315F423DA512661E4CCE098D6678F560A4BA19475296A2A1DEB12AF5900FA3A3C188867E0C268EFBF7AC53455552DF4F36E16D50E23048C7DD4E64341E6DCAA0036EE045B82C42121B0B779B5E7FF032F549536ABFB702B1CE4EAA5E389A077F47B1B55595D4888A4C1D17F4E21706779C9CDE25DD1261C8B4761A40B69E2F22F069A264E79CDFD36F307D117FC737D88F50EC67CD07D8FA269CF265A7E7CAC93E97BC29EF95C88904AB2DB61C8865A6EBB23871576DBABC83920AA015D47E8CE699A9E57E139AB7D233C577B46C9C314D084A1674A152D87D2A3D8A5D9ABCDA22E212B8C9A2BF25D8AD22AA3627E6C12C684AD2BE917F094263982D396364F4DE0BAFAB2DB89997DAF8B7E3AA953C055776FDC29F8AE5C28D4071534A9A2E9090CD3F723D3E381A2ADA6D9463FC49B3C6D2B76803F5C21D8DDCE965D2C472389D2BEFF448F2D81EDEF1C851A863AF66B64417BCC2CBBC70C18875055D171BE32C06081362FFF7DE8F8A23B076839602E2368CEEB79E4EA53F42F440D167A902A23ED53E6691AD3332DF5B0160EBC3B5C9567CF619BE2201447EA500332ABDEA9B849C3A395F596F2C96ACD9AF8313E453277B9F4234874E791E9DCFF0C9D9DFA8FA9474C026DD34E5CF3AA10CAB1FD23EA5DA0D0A66E520096C6116944F2E5747A974BF55428A3D2475F6276490AADA25220F2F2111892DB9E9C75A5401BADBF69F31B77535044DC50B1E93849F19C0B6C5184F1B14F68960F9F469805F3843198AC68E51619F3D712A34279AEA27BE4357A99C44C456BD2D9319147285680922B98DBC4D6D2860515D1371D2141C7A1E76EEF8586AFC973713EB89C1F09A84AC064BB7644625224FF1F7316B9DD1091CEB151D1A040F7E60F202728F7862589E7F1FA32D39653383F90C67D96D9949967AF234592903CBB968E0D979B92B5C69D09EF4E767741F1F6E361DCFC8D751CB8C3BAAC4CC393D63F71AA1488491CA06CC20B0BF54C5C225B6F0825677C2C40A395E1B7322288A815E59AD2999D61FE09C95828CE18B2997AEDCED56CA8BCDA4343B1E948256AC5EBDA23A8E6D7102A4474CE23567084547F2ADD9DE77483398D81A9A9C7A573D7EDAF99536D31C3588BB649EFE1495CEDED788EBBFD5775842D91DAAA2F9BE08D63B06DB35E72CD0EE5DBF45DF9B0CA682BD944A733D6875A62F8C53A3FA9337F13429FACB288C73220C29285B2D87DF2CB1A54631AF3D0035C1F3B26A5EDD07760A63576A395827F3D5F9B03D9E47A9E1E6A271021942648B8424234080492BBC56C692C769B5DF32A75F7403C88469E54432A37A895E3CAD3AB110089ACF534A0D78C2083CFE149A2D0A5055EF9F4C943CBE1FD393292518CECFC57E4FFC4D07A563A30528A6A3540636A3BE770B7CF03F5004D7C6F8ADA08DEAAED0422AC0C0C8D7515C9F8BF44195D6DC30D9B3036DA007A910BD05DF06B032812CE8393AE2777D717A691D07E860C1EDA60F6DE31F0787097D0D483E3A51CA7997646503738CDBAEBCC21AE4B984B668FB4020C139D9F581EBACB7BE263A33955DD68C9ED9BD2DD6C0A7BD049972B624CB7E787DE7184023F33EC0A1539C4679D6B4677FB971D763BE17D989FDF8C0AC4E0B5A6CB40A49B5464610A110EBEE9A21BB0D6A2F043015EB2C8820DD966A13EFD18D32367834D41E8673E997B2803638A710580CA08DDB4D90E4E8EE584BCA2FB853A122274142130A1ABCDF7DA6C0056689195099CC3382AF6987BA47EE294353674E7295ACC1C070F1D8E4107AA7189F20CC818F1D86F6D646CEE911B304E2FECD5A14CF5F36331AA86E10C319C96E52996D4CC12810AD7C1DD1DBDFDC78DF029BFDE9E8F9B1FC7D9DA99FBB0304A8129EC58A82177EECB7330E715BB3C0B4482923C7B1EC0D1823FF643014C7D08A8F2D9F9090B0F83663AFC5E601E5FBE1DDBE678B9D93C5A23F564B8A4DD29C8D19106747959E72AFA4B16B879E3C6E7F79A212A144F9AAF665253F1360ACF7DF37642270656583E06FAC85389A3AD76E69BC2735B1C3E13B80CCBD298EE25C29F9F5C275AAD83BA0E7C47526253BB3125EBDF5CCD6E1C4F9D9CD4891167BB4E4D2AA644D5D362C6F790E2776BDBAF8D96DC3A543C72ED46E431FABD737B4BF0F4B32E12E0520E60401CCEBBB40180985948045C58B0017C3D8797E433A2E2C64B9679EC7409D59B3992053EEF2ACD7B152E5F564196876EA0A31CB6ED47F2455BBEE6827D96C6B99E46F3DF1FA21F593E842B26E83D843118F6833BC273E12C7224E00E840B0041544893C6C8A06523DEDE2ACE7365693BCC6A8D7DD81B01310CBB8084C5FD3868539F8B5179519CA6745B56C4A5EEE8F2A8A60CBC7453E1E0990D176446D97F34A2D0BD5C5712E2D82601D0B9FC9A3F2420C65E4532DB3810FBE3635B2AC3A84415535FE41208B907EB3E97AD63DDC4FD694127EF1E948801B5CF651119CE17BEAE3396C098A86548B67DDABADCEEDF60F57D2941815778AC14F78C78516F84C5F9749B433DB97A9283A94697419CF94248B6819D9310324977D47A133AE9F1FC141B56D6302817761BBD52B4A1EF808E0AC761426C99E0504ACB6B552F9550D55DE787C12A0409A9F9EE3674617D15E229AAA98BBF4FE49CDC81DA3AD110645132B332B6D2AA38B35320925135BDD225053D6594E78389909E596C63B85DCA8B3F6C3233A31A1F8F3E900E49DF83F649E592979C9CA4BE65E7D6D1F23A7744626972D52B07B7B89CD90238A5E871666F4CA6DAFCBF34FE15983AEA5BB7F9917736F7BA46F342F0C08F56D19AB9569FD23288EBCBEE7B5924B8C86EF77748F3AA9CF2FB884398F83772C9771958B6DD063162A3AAA42E6A3280FEDEEB7A628A07702950975CD135D6338FF959ADDA2296B3E85A024F63D4ED8A5859786E2BC76C2325F37B4D91EE8B64F30E781BF48ADA774C1641CFAD2D63A59E294B5D99C94108154E38B499E3CA2A29AF7CC77A8BB3A3B712376CD081715EA715305C18B51470D5F3A6A82E9189848311511E8B0ABACF856312AE3916FBBCF6664523684D3C7ACE08D2345A3907C9C07183CB3E68C5EC3899A95430E278A72701E2355A4AF606DD8F8750F7F3682FB84290B2BE23BED99CA06D5E54190A5558C927C369C00C512342EFFC41618CA6F8FE6E3A38D1714FC44BF5679C1A49CD8BC8B28499602E277DC8832F738225920709799DE6961E0B4EC12397E7891AA772627F66F494AF719C55D056DCBF10E8E3DDF1B6C1BB2F0B2FA61949D1CA7D4E1F60EF836B086FF8C03A5916A14EB2670AF56264D7390761E6EB6F638D6FACF56B72A48F271ADE4541C8EFC91D15F69E0AA6B97EC0E9C0C3EF169E4A4DB1C1AF04762B98ECBD0DC374224D98FDF7788435BC154E1FB06C970A914C34DE52678F61ECC1969A2C5B1FF4D82E2C80CB543B4B7C9DB541229CC50CC6C448DC029CA24ECE635233C401D3715671BC75785DCFD929377AF5B65EC43EF45A9B00CC766695A4A5DE9A2E6582F7936B9FE7DBBA6762C41453683146F4ACFD809847F866DDF559972FE0C093EE7C9FAB3CAB0BC2BF8DA19466A96BBF2DD4859E2D1CE122A3CF16AAAA9A4708F72BBEBE285E1B794B2B9C7A699B36F39F033277E8B7BEAC3BC70A572556EE5C070A309D9D0BC35F4B6E55ECC91CE9AD273B0098F64E1327C85CCAEBBE67E8A118669653495D2FA09C29C6FCDF870905B2C8BE0DF806C29D5E7AFACDAC5F89116A3474D2229C76E649F99EB9EC71A2C229764A477853D68C39B8F0BF4378993AE2B26E814A337CFC103760CE92FB564E3A3E4546996CC4D8B6BE069E99861DA9C731B543BFDC006FBDE3B33D2C8C4A3F5789466122616C98F52E5E4BA239E0C3758C5BDD3BAED8809F67A70504BA061409A9D87A499236230EF0F1985DA0D765E9B7F733A154E8300490F458847A89E7C6BBEB7A9ECA7B6CBFFC3124DEDC1093C02C808DA1CDCFF5237745C5FFF51F3F15CF746D3397916A45990070490CA74A55F34EA4BA9EB73A281F123035C005BF6C7B30852665860ED13A2B5808F81435A77A8504B58CBA45559BD3BAA663A571F108685E414FC4DBF8033075E30CD6FCD9B893DA32F7C8D5D971D5EB417F1201B00F65DEF4EEED3B55B7FC7E6194B72A861439B865558157E65D4C2F8A1A93F48192099B375D111370F830B34EAF3225A16006D4749494B9AB9D3B05015E34866A4A2D94B9588A8DE8AD4CF90F2CF422634E8DBFA0FE3FAF27C3F3C2EAF9C1BDF23FDF43D196732E1FA6D2B343BB7D9F5F26FFC31B26C64A8EFE2B2D86AA34BB618FB58CCB54486211A8E66648CEAE52F07A6C1EB5234DA7CCAA971AF984D6050D1A81F10E6D19CC44B5E668CE92F4251924B25DAF41D5E381C3FAE4208D18F710B5F93CF3C776A3D81C608B06CE6BC68FB8A8117CE7BA065675B88510F2E8A440EC363A5983DDC1352E446A482C593A490AD6093258E447EF52BFD189ACD11C87A8B75F08B5D166C1DA69602EAA5916474131E20F704DF84C3FEF2AE99F9B9E8F7315A143A07C7AEDE5797F503086DF7DA971244A61909C4AFB00842FBF4C3A59B991B58AD6C0B8667C449F0D97F34CC41FE935D9F55821299F780359E2F631858617437D4AFE67DE4A1AA382B93CC3FF596726F0D1C071FD0E00883E9E03811FC659495AF2A62B45DA079A66552F2928B6A25C6416F8DECF723623764441E5E581F9B2E36479A1B6CB3DE9B090E3343277CD7F84E80219793CAED4945DF782C4B72B498A62A1F5362745662F711A7E47CB816EC7069D10CA8314845AB0C9FC326C5BCA0E2AFFB4E6948522F8CD9C8DC008855E592AEF1F8239748916878ABC493E33CCFFDB86CC2ADB99B6251F493F0D2A0BE56D133B66395AA695F6298F7F4BAB41420CA9B8CCEDF2719590287928CF6BB3A506D6678B814076B7A774BE9B7029DF9F4719AAC1D012BBD49EBCA6AF124D0AB5C5FFA92B4A895CB76B88DEA9C7105136D78B76D92079A5B001B214DDF7E140861D86ACC260B72ABEF2CB3A75C2BC87B39A9D9052D4283B71C10AE275474E82A5FEA1654EC3ECD468DE4A015CEB67BAE3275C2C79863E2883D46FAE351F0908F42825DC7D9FAE0FC7171791FCAB10E16F3F027E5043AACBDB1F05FCD2B3EC7F6F46AD6DCCD6F9E6A6AC702451194788D14261219F794EA195F2B3778654BB373C68AB4333E224D161A1F89FE440BD8E968B518EEA28E81B89E04FF1A85B879E4B54650FA8DD1322D14B4A87"""), - TestUtils.hexDecode(""" -c2112c791ee26987cafdde1bc02fbb99d5b97ad71d4c75cc36cda559ba853a351b3088a5727856774fb3a100640034901b886b9aad882c879f7f7a50090b1b4372ef71a124563aaa22ed2b227f76c4c5ad691499766556691ac72d3ed717eb83c06951bc8ba4c8829b225aca7eddd999e9e6e9cfca939ba21d2f7f79c750f43719c520b344252a283cc677fcf1dc27a4dfb396541c97d7e948ab873640d1a1a0d941d2677878360eb2b703f727a00cff03547f5516d5e18b07d904e3d978a905c83b45a2a58f407a5778d6e6da955705f0e55931fb31a1b1be5196b6e80574b8e37022d4e7778bce58a817aeee7ce13c07196dfd6c00a6604e40f3d12a46c11bc6295788be5bcb2a39db2bd64780b966530496a23f9e60ab9c7a4a48a5cfc3b1f657e00aeb99eaf8ae38e723cd14191f927ebd7944da428584b23da5ada543d3c071cfe95910aecd65f7be88aa6c7bfb6e52ec3c925fcb0fa4b09d7612a8b19a4156f44d07c77eb229edc08d78b52ddb7bb3e42e95faa1b013d4861ce5166fbd0d0822baef9bb5d1f41956be5cd1efef4bd3f92beb656957c0ba51dfd4d186e4804b71e91bca6f3341ca585f0c48c3cd496a1f1736f513650fcae2379bd1d127641f1a92c0c394d2c02301d29116b3245ccfcb6ae3b55b29503a49fe6357d3f027a20c30528abe22623c53c73970090b12d994f1a69d5a9877ef15f3475cd1b9d58cc38a0289e12a09ff756c7e93bd675b2354d78ec79492051751db9b3f35a58eac539d4c6efb259de9383d5eea913c98a6daa6173b113f8d7bac440e1bc4652d1645b96c4e3ae6697c9e6e7a1332d27f28704b850cccf469f829a6aee604e0906d1b84fe104303cb9e187a19b9ef212dd334f134cdf6256dcdd39e91283e6d7f3f808fa5cebe6263fba31f766bd86fb271a524042d3b42b9d1e7729c00c6e4104eea77934fb44fbf7b22ad80eba63fcf1ac416429df3c012afd4f42984b8006e5ab52b94fca1f54fe91ddd2ba4f8366cf74597dc4c2fb1554c20ca28ca4262888d70f342b55916f6eb5a2e6df5a9d0299f2c15ca37f5cd688792a5c255e2f684035770cf4a8894b750f1f97f9c226f9c451ce0b5701a4486b9feabdd379ad31f1164706a137aa487a25c088882c282b5f67599f8f9488b3c1b0540cdd48ad57754d760880478b686914cc7cbb3f478baf3742382749edb287e867d5863fc40a5f57805d1a7006a2b45046698ce63bf85fde10d9171a618a10da3b20d97052fa9416e56ebbfc9b1cbacaafdbfdfecf18d23df346f6838d90d2f0a45aa650d08be2360ad8b3259541f86946fa047ba2cf05e9542e67307dff451a0bea83f3acd2a328f0e9a7c870dcb1b3ef6a387c208f5128951b4115aa4f58193844d54113a5d13cc6e58cc210cc4865613db00c6c515720de072a9fbc60dfb50f48fc9ee71072e14a2380b62d644dd49c7c8f5b30233434f56ebb4c00bc1106f2f7b89d6f4076480fd24857efaecb3a3921a3f9d9bb84353792bbc017ec91775660c21cc6b7c2c5b629258fe1655afda4bde38fb66d9f5b90e0f70419d06b38de8bf050e7278cc02b9b7d762dcd32245c9776da3fe15af5bde873bbfd1d84e8083a06ae1d030a7d32e9a50be599ed816e47b54ec7b686f5e8c55c8edb7d7f34302f343ae7027234205c8d3943244f91ea9c2e6f2f33fb56af3a0ccc1c101608275ffd7a18201a0cf3291320e8c1e397684c604dcb23953aac9cbd65fb8fa615dfe77dd2b7033195030b57e005e28f14b316e63c6a62d81fee131d3ae71734e90e3ca43c6516996fe169bc279e3b398e8ef8929760da3389b29c0e7139a2d889403b823b3361c310ab668167eed34f3ff6e32542619d7d5298bdf4c9e7b4849f0310f386faee38f5e94f5455ebbfce87a34fa93b808d5eac6a62b1fdc84d3895d8c78e211a7074c78262c24c5153234882a4bc043703d997a1b8ea707712ed46f6fb654758634d1591ee3d79804c8417ace22343bce4d0754f4e72e2f518bdcdff3bad1313b974f7f2b7100e6fdbf2fcc34f5eccddf570905659ace5cecd78ceb88f7fffa03bcdb71a77f975f3d13146422c765a228063cd9cc92f0031b8ba6796025ecd4caa8bab5c48b0e6f164739150ac00bbfba4ce69cd212debadd620242fd5610f3fab75e7a0eb587e4ccdd010fac040d8c0b71673f6a6165b188fb59293138048805ffaa283b9539b947efc6382c929295769bf9d5e434b9eac6d1b9ff9ac26c0a1d1f0efa3108401e4f522579e1bd504a64d1359e44fa59f4f33ac4cf3e7508aab3388cd5be219937185ef7459b9c565034c8d4920d5fc62080db0f0930630d14c285ca11e360705f8ca5786e394842230636241a461966252d634cba8f68e0fc398b4298f4ecc907f5a1fd9795e427e6de785d7bc87130d986b286afcc646723010b329e8cadbafe1a9ee23f8010fa6ae67d1bf950c5f0e6fd53d31ad52ca81dfc5225f61de691d868130bf71d6428474215c9d5236a796c29f983064a2c9f40e69efd090ba55c47313f13b52b5d9edb7206ceb0eaf57198f32a722f9a60400bf550d5ecbdb0e460c791c44e56a1301f6f6bf0d9c1ff04ef6d238c060bc10e75114f7d055b5c3c0ac2961ff42c1145a8505e5d6c53389f04b20d2cbdc56759b861c803897be3eebf932a4877b1c4a0b63c96ef9369445e48f4b0ac34bf1799075db6dbb7d18d28f15f58152b0e2e618fb4551a85f5d1613a0a908a2edbc40e4d7e9683ebf5f9f8879e415e070a8eb52c71ee5451f95f0d351c3013e160d55c1207883c8e6fc20a4aef495c4194a7bfc8afee6af3b82bbd0a32aeab5023169d0361a4449af7a19318d063e4f2ed690b28f5d0786bd6ce5f72b9a6e411d878abe616767fdae52cdac529eb07074ec518723f8f870666211bd427b5253a67e40a318563a8b2d8916a746fc47e3ce26103c437e07db67ef057bae6a953614ee7acd16532d0485ad02b4bec1b84302e1e28c41e508eac18f33f76c150c3142e1c383c28ed902dc79922749842efc4c91c75754ea5e0678a117612dfc7ea07025cfe2e4213780734c4f18e191cbd815619b41b0f2e9965499ae19666c4ea34dc1af69dd60dbbe78c6f462a20699b58f50682e9602e7f16580149797067d0ed1b0b36099a0c5732d64d1efc1f370d4c71a6e77c5d319571c3d9274444db155b11286edbb625b77d1294d6dce64ad7fe58a7808b7c9edf7699bbc0e0342dc74158ae419c01b64c07bafb6452f131bd0f889cc40419d3dfd9c7c4418a37763218498c29f19a0b0d2b3e404b525d707c8cb9ecedfd22303a597091a3c3cfd1f8fd1d252641799a9bb3c4c5c9cedee10e172b2c33393c5054777f9eb5d9e0efff000000000000000000000000000000000000000000000f1b293a""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -53a902d7abe3103058efce7d2beeea878d48063b6dc8aad68420073c43fa5173338893b842805ab8c6b94060698d44b066b008a8209d8ddb3c4c6c0b69ac78166bc97b52b4302e8fcb4a30d102f863b67cc332a2fd4d3f1858613b126a6416e528f2e7a0e12eb547acd956914391edfb42fba61dd2418ead4d0297336b75ce069e3621f5e729d2974afaf595291030a557f5256f63d08c0b475fd47a05299e29f4dd0aba10ecb6a473af5223445faf46c2d06c326d3e407061c4799f8eda4ee8a1958a16ca8a0b8f3cb8658c77429a459a67210cc325ef0b361a8e226ead6a8675f9f97be9556ff40817d169a95cf026b38afe7e28836fb14ebc9aff7c02254ab5256183312e450646885f6177110daa1675d2b2bbc722391b7e55e6d6e0dedaa772715dea46ad23e03d6b11000a187cf51f8ce5154883f80dcf200197b9b9bbd5fa870327e2d173f2ce1a43d89d7b75db2aed4d790e6e452584dd8f525a7d2e8375dc70d4a85520981d36e5378a429ebbbe858f8ce43d6a24623d7b145d29e9660b36b3ab1729b53806ba0fac817109448422f5a7bf366ce1f424ff8fa8be40855af63753ff59dd1063d39314a95f171c72c42a6a9870d09111f2ed626ede30e58074cfd938fe3eb334cc90d7ff7dfa03d6463597b2a882340ff39d018a698a16126e796e93eef162e215daa91c08106526dbfe79a7837743ca396777300f56c3e969757300f2627ecb95a0bbb553578a679652d0a2ad07efc2a55eb6f5baa7e992e6d9c2650970c6e93ca06293b7482416605b176571b1f516e0c9a2dad7fa54c0256f469e98cb1e82ece83bb4b70ee8750aab2927cba821d53f3425677ac92871d0926a2f1ecbc1dd194eb61b408acb43c712f825e153e1a996a833b199a9436384a2007678dfbc76083d51af71e032c42d4d8998a5c0ebcfc43b1a69f8b1c78c98fe57cf0d56a051fada6148d5ae7284a882ca1e912673b6b5df84fc9e6d8a76a7f57f6aef0ddc005e56bb35cd88597a15499cd55cae68ff75c43e4651d965037e4eba881adfafcabf85efb416d3df34f16372a30c83bcc56663a8439459883c6ea4776de4ae02c1f8e038525ee9a862aabd0b4465ab3c0e352ab5094ba58719c2373b3d34f11d1eb25ac268893fd511a49ca86fe7442cac88af7f2571c512817c3f324fe5a4cfda13a02659abe2c35c750abf9d39cde64b81987a177d9ba5c0759d264a1fa080b4681987bb5e5e04a3460a7c8bf230cb26fe9ddd6a97f633259affd1aafa54ccffb39e5da6241ed98a9e95d3388456e7342cfbc095dd2502456ea067dc640eb421b636fc6da7110ab35409ab52a8597f3bae8d34fcdce772c78293c2aa62c940d806dac0e67737e7480fcdd0c7a9ed9e98a7b1bb70c60df6546b5508c5dde0f75a744802ec5bf19fed717b2a878a80ae472e1895333532d7ed13810fa158cb66d93443a6baf8765db2a18e5fa35cf21001215e4ad365f10c38ee777e9cb38efc319ebe4eb106accfcd8182d9673233403f2b55cff98617a1b8be9cd65ab4c79704f082b7ca9f208177fe25a5d79cda75b4b5381b5ec55ddea73c5e837081e34aa68ac01a1412ac438ccd96f763845d58ea897ca67ced998934e310281c3a60c82140413fa130356a7d7974860ff08948bd955ff8b954a03a3d072fdbd1bc772e5a93ee4c9ff1ba44bf47a5e15de0c9746577a21e7e1c16e41c07780969d442ba5d95ceb93b05b9b5fd6993b090ecfd4b75f18d03fdd5589c830069cb32093aaa556f5a8bc49f1c0eab930899e60401ff4503d6aa56a09abdd37ad7b9536de631b0bd0b2d6eed874cd5774394560d0bdb1f5237b7d332bd"""), - TestUtils.hexDecode(""" -214BC54C508E63F77B261DC59588A87CF95C233C22A339E7158C47931C1EFEF775EB3C91A32C56E888214F9F68D7CD2525B23F695871CF5EDC6979A677EC19CBC5859C63ADCE2E38C67CAEF20116508F33BE8035E9C47D124EEA5FD1651D64371451B6B96601E4A6E8292ED6841E483C3ADFC3DB242D1D7B3F036492741661F45232104A528B6FF79AA4630740BD16B37CD3E7C711B76A259C0845D6F87E4A4B306E939AD1C41022A7D5938E52B98485D95D11BE629263E6CDE20F63AE16CC2E32B6C1C442EF108D92495A759D3707AB6CF3ECC5AD7C02F133D689E252A26C014A31C65A65F079C622BE3B648496BC57C462051B17175FF81126B5BBB5324CCEAEDE0B5A8ECC0D710F04DC0C751318E8913F149E701AE0568B5426736288CAFECAB1779C7F4E96D9007635F76DEB4D379918447F30167F257B8BA825A50EE845FC4AF7C34AB200D5BF45B5F0405BE2347ACC814BCDC648C274C24F8024561FB66676534F1FC8041B63114679D9F4E8CB0BCD7BC4C54FBB4F9A178B4FCE64E705BF8FE42826EE01F691479A8815E2DA00111DE40B5CDE464A9F7A3D21BE9562FD9A5C5CB3F4F9E8F0D8D8A20B9A5AC9D7394AE4316181621B43D8220FDEDACE345234E3DFBA134BF54E458DBEF98923C1891CFB8DC9B5317E3B16C740EF373666969C95BD1C53F435D7ADE792FF9E310A191246154064D0E8F20032AF4823A335D88D5C2A943CD4CF313CF2999E237F6EC50F63936D0FF3F2C729FAF0232671C94785B67E0CF71A7CA5B32434579711EDF155D5BAEDEBBB8F0C6922AEB9798356714931AF1070C49BCA507E289F005BE9D8B46AA67CE2137935C7EFD192E4CC24DBC434B381E9A15CFC529D0064F057FC3AB592869E5F1AA5FCB299B2CCC0ED6750E318F6FC969E6A3A08059788102CCE79BC92804B1D08F3BA30492054DB6401EA251191BED1B8CD35DEA3A653D5D546D2EE8D31C2D88D6275D6C7B463D449DDAF586D5E57FFBC07ED5558D87F7DCA82E4ADF49EB9135A578468907BD8A6228EB723241D58BAF3C78C46451D2F11CA0552A05A85620001D376C6194AC6494E337388EA49821C233F32579FBAE6D11E9DB257C426D99516A16DA63A7BFA261F2B012CEE4EAF7C5C16C6331B79A26E79B1421371E574505F61D699C6DF33EA734ED14129608260B1233C387638F7ED3A34866D656D74F06C2B8D70AE60A0994F3D6C1267DCA2001EA781E5D6E17BECD284F967788227E060381ECC60A10832091319F225C972349BFEF08D4DD5298BF7EE11B693AAAC682F91DCDA113EFE0F35CFBAFF6C73DAE43B8C1124EB57713C122F0A5FB03D02C4128565FFAEADC0AC23DBE5BF123CBA024DC2F3956EBEEE95918B87D2EB22EB1A8ECC3B267528A62F2280E3DAEC02C89A01F5829B5891914DAC"""), - TestUtils.hexDecode(""" -8ec19a12690fcc4af18b44a46b33caf661ff986315472e2fb9cbf0db6b11f596b5d540572ff4b722d39e5685205ae44f62645ecb6a4f319b1dff9c685f6bc65a311cdd61204bc23da3dbb96f71ecb3922ac19580212e57c121abe10baca724b0acec03dbb6de182f1bf5090131eb5ced5b8cede5444055d33838272afbf8a9d9752c0536f5b544dfd0f20d4994638157e64ff51ea35539244dfad50261f282ee2fbd5fe3b90607a4b2590cc24e67911927ada6cf9b03fd482df572e6cc7441b6129677f3d3d0c0f5e7212bbc652bf53140630bb0e3236d09943796ef92e7916a2c4fcde8c9af522d9661feb6dacacce83e14a6384afaface04e3c8c0febc6306445b84df88cd91f34235c7351048c0d75b6039a102bb0ef30f6e5fae78718be6412db19dbf7536e42b0e5efd950e764c6a80f70839d356f55d607ef58eb366a840706be8f79e8e2ba251063336c819ea3fc60ad76665cd7fc8ad9e404847e0a8ccd5aadf3fc36dd091972959e3de4a5c49bf799c97fe4ac5e993fccd03994e6afd1562a564b111c52860f564e1b335664d57de6fffe5cc93885bc34ac7d278dd28efb850f3e67e810285f47e170243454ac65a18807dca131c99be1f85e34c1c6c3bd3c1f2a13c0341ca961d871e92a2353d813c06396dd29b835971551cdd4d7fffce4d32facc1026b05ce3ac795d54db67983c5bf4aa269cce8470e535bb2555096769215d3df109e2e21b6ffeb6b7461481b80d4894300400851118abb4253b9b86c774522d544dc6c6c2a3c75ce8fb5c3ff2564b9a696ad05b228b8effdf6f54506e2afd2c284d3a988857e4aa22d9d90feef71eceb135f7d6e9462c7302acde68bbc9a813521293d515e8f36aa5ea94a7727837aca76c6fcab11013eb18921091002701166c586abac8f20770e6df05bc682a19c65dcbecc86bca8c85c9175d5f0fba67b33a383987e7483366793ba7b35942b3627a33c23a9172807b578b536fd0faa8c3d9f3d90b6bad5d2b582634b44f9ea81f3cde12ebcf48999d1da8651cbc89e87e0cc049c4d1efbe3eb625ef4e09c2f879ac1eb7e20ef58544332a50953643b02a73308cd481d0582b4edec16c4f31f8ad1ee6d3575ed3e318a8df9a0bf81eaf7bfc720268c1955033bd16fc652cf68ac5289488532665c4b584fcff68aa04b1d4ee55556973eff4d8713b2c3bb6dfe6614b9e6138ce9799ad65d824159e1cfc1519a741cce18ad822de048f19e01d40287494822393bd6d321b8ec3cfe0f402aabdf03743ed8343d442871a6a56821596144f9005f72f5bb36841975970caf6df22724959ff6c8b57049c88176f61bb1b08543d03a7c872b87ff2fb7a66ac64954feec8343f99dc5a84ef8c207033bb837bdeb64c5d4674014ec3ee792303ce5690f2d47d176037ba7ad21b8d4fa2b83d6bafce3cff48e12e12066be8ec16bb2127a26516afba6a87a1f7951ad2ba40b76a800e2c27aad75f883343ca988862a6dc4e481faea5a6dccc8fefcc79f4970bb831fc514cb993624cb7eab874af102ce5e06dbaf57d37cad159541791afb1a47f9c838db9168b27290633e0cef4446d8765ab5e70c7995d437d1128c0a3b0d5c6da7bb7b3e450574018687549eabb5122a89ebda3de0763497658f160fdf054042465eb25174609f26f4755a50d2df918dfec074aedfdf151645b73461d3eab7234aabe1d19ae9896029b57b44b90654666a2e8847d1aaab3b3525952eeb5f0f8cdbc8e3e54ebbf6be367d689e7140596ba674ba940baa5b9637c685f1a1228acd893478365ce039a0a67155eabc02ccfe8f7731d8ccf754cbfa512e604682bb1be083feb424114da3d7243498be28857f19468e5667f59625902b9cd228c366b684154a47acc23b03ff98dfe0c2d02502f6c5e7a5dd212722f5c06793b86d43494003e88818db45102e790ed30f20eac90be73df9b92f5064827fd43c9be4423f61c23dd661a6fd9856f41a2f65127d555e509919b17b0be2e27bb45b07e39482877651ab5e4222875a988a9f97a6dbf9cdccad27576426927153dc4310583c9bd8cf6fb5d50a2d2956986c7bfac0f552693355d8ce9c4dbf4dc5fd6523cf4d32ff62b4e8d9e281eca16ac706b3b737c0d2c977ce4cd4bb41e5e1e2cc16e63ee0c408713ce2831e68e271b52a86c2b8bd7a9d0fba9706a55a5b62ef3eb8a29c793f7a66e182ba4ea249a90ca8988c00396c2d858e3ad362076a97ebfe8d9870a339c0a12bf997b66ff5367b4591c8b0deff659c133e4f97740802a73fb1cc6bdb46b3f9cb31086efe81f62bc087786d1e984773aa976ac597537ff1b1e84991be89df4c1ec1e29a2d72c2dbc5449af5bb95090d1159d6b80e2c5936db148aecac22d39803cead75e78a05731f382b09b51b9a9b79ca9d5bb51b78e591bde312625e52b4ab6eaca92e95edde3baa07b8d12588c7bcd8c2ca4a7e6e5a776eca1168694da493e96fccfa6f68e25cd4d441a111d8de31a0914e19900b218ae50f21ae0659f8f8dbd7f301a061b80add0697f6201ffb0d8c6d42e3926dfd98897d967e928802c9ea3cc2d3c3b9e36b1a29e95fed603f46d990db7034d53159e5a5cd7a72f08e451b5d7dcbe0437a2f20ba5cb69046e218cd3a7b491d1eb47fbb22e2a3b103396bc7273c218bd0eac9f272e6d01a7ded0595b02694981cba45020c10aad67735d5772078099136786401282c850448fbf27e71c1233e5a992a47cda05c1946c6f3cc6cec3899dbd435a1d016b3c771153f44e46bf55fa7fb3c39d8fd1bc14244fb70d4a5b8823b39e449e4d5237e0d99e49e88a85813efd60296b8bdd24d27725f993850b2f66825b9c469f212d6ea131ad96a089350cb76f434e1d2054fc083571f857a36a93f0e6f5fb80ab74f9bef3c5bb7df3f47885f3d136acea283085b4080dbaa5b555faeee52948e6a5e0b0d7c202fd036108998704022d7361ec72a89ca5008f48d11814e8420b453ec202cd6ddbbdbfeaa03ebfbba50c508c5c1a81f6f4367a9f817c39613713c6ce439cca013e1b645854e10256f48ed38c50a7e4a76d01102782d433e612ece1aecc1f48ce45b1da41962c89e811e26895a4a953c38efb620d2285c05a99c27d8e02ff419924c99daad70827ba815c68b0165fd7c4b6ca77d3db1a61f8f95d2c5e93ed860f90abc418791dcd1f95f29f4a45a8bb637889c16c7bbea2ed4a87eb11d4c2d8a7ddc6a68d1f83b82f0d206ddaf76f796c21e0ba9dc3179e85dae4d7b3fa40da3c65c0d499b38362e179e8306b1361f3212b0df9001f325a747b808991969ea2a9b5c5d5def00b0f3139587d8890989ba5bfcbdde2e3e4e7eaf8fb162326354a53f0f2fb080c1c25474f5355627b868a9fa3babfca00000000000000000000000000000012273041""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -8786af4f2617911e937b31037e66d478136009c090bf4a971bc2f286aa31c2525c8f9b56e09a9fcf16fea34672f563b3155acf083bd828ebecf0efd3e39064b9711f3211e1f39634a3725df3096e7569d1ddcc691b199ca2c20e578ad772eff6cd0d68c97043e2530efc0b1905e48a3edfdb51afdf8a6b2742b63784aaf511e29bef9c39d5fc9b33aa61e95acf13a7109e8a92825f7fde5171ca31b0b22652f90325f96817697a661ffc0b42180be669d2065a0196a2a857bb7a3c79fda83533392b10b9aac11b0ea53aff7c323a7291fea59cd8df052f2d3b22fb268b8cce4e081bd2ff05c57f7434b09d26d222c012bfa3329da7d6fc00f69fb1c162ceb12e4b6af61ab58b0f8ecc0ac3aa1d87c84ed60afd0711c550a29fb13f4e9388dab0cc11eb0e2bec3da4a7e80aafd7f94443ace3ff4aff51c12b79dab5f05f736bcbe3dcc4675a5f339844671d623bc4964d6d771e1696ed85c5749f3b2c4face72cbe8b93d500dc6a056fedd1798f8b01798c317b5a977a4b9e79f8ade91aee8b73c0af3c06e9347b18d797c642303572e168848d60a84d3343fff120edc804fe79bb34065000e316bcbd0c925fa2487e8f10ec89cfb986206f1c6b2d6aaec470b2354df70dd5ecfc396f108b78e0475f2617ee65fab93080dc0eb31a0e12df889aeef18b97417ab5deea3215b238b2413f8d53b22a61388a5364c898eebcceeaacdeec1af995be8f32942797a9863a5ca675864f563616fe52b4c349360f4a9b823d0eeb22d3ae744306f84442e75586b6b1c1f9c205e805805f2055d4d7e836a957de5dce2677256a51b7ab6a30aaf660344c7c2927f180d231120dd9540c968da520105a524a2b141ffc96eb9039bee53da2cacaf5b9b5a750a95fe2b32aab89236a4eba885042c97c61cebbe18cbe34ce20792674be6e32e605b4b2e7461e1e7a95c67c59a7da8e8b0561164f4b8490bb7255ad58951bab2ea936e6446d115de213893d27ed1282304794fe889a6b7a523a051af7e577271ffd0a532e056f7c22b0899f8802868a2932f3d4b3697e769a406e0568fd3f3f371833a7c89cfd035536b766abb9351c2d3a09ab9abb6138f0cea3defb6001aef54314bcb1567cda06cb68565967765474ad31631d001312cbaa60ee16794e26e1c27bbbbf2bf6f2d08e48c0a910f3d79870d6de87feef4915e52f65ed6893d82e03a3c3c9f4d22deba3d9dd8cce4685f16e675d95e2e4254e46bb8d72c553f114ff041a1534b34ce7eb9bdeafbc3e1d3271ef774a8154ca31b068e89bcc41344be537226b57ffb5a7a4e3b905b377ecbe87be3aa51ea17e3eab7561e1b71f40709f9590e8b3fbfb8a89622b495a6356ac1a7d002bcf63ab4774db1ac1e257af66a6ac4175894d3b637d23aec12f57d1004b7a7a8df5766bc78a5ebbe1eb1ee9f84d496f83d6de920503d03e7310f401e6862e63f2b39dc2c899ac5e014a90e574f96c7abfe7a08475d34c4bd8053883a379f362a34cb062eef2a1b2207e50facfb47d97fc111dc887b23df7022186113aaa39caba060f58bed427107de9b05afaaac1fd09c5e86a799d975e3eea727082106b14516a06fc8fd4563c7f7255be155785d3f3ee486b15fcbe0d7feb27a0ef0468ccfc447fbe04e7d4cdc2a28ea98dd279689c1d5192c95db184c8bcd657c436387e816170d8f1b8d0fd970f3761539e29f2a41d73316c6a6ad5b6e1f59804237821a16800072f7bf113c7f874761874223412e533cd5f0d601e18792c17599e535a9accf340de625feee6680ad14b84f33efaa35ef3e57eb11b4fdaa855b91314ec966380e76ea352b4967f4c222dad5a9dbc456a9c"""), - TestUtils.hexDecode(""" -E742D452F392CD3CE405908EB380CB0225A4725065AFCB0C91C5E4823471376E6424AB24D57FC4265B24DEF6CA73E28FE20468B6E26BCC9267AAD2B7B82960C3FB5A01960FAE078D5A54BB324232B6647C9DAB943533C865BABBD3DC0D1E7A1756212980D75F2C8E999DE9ABD1874E3A86DFD53340B6E424DAD9F53C3CA02B44FF8DB9906D3D4352D0EC4B1A57A33FAFF7107D38637AA410B196BD1BB1FD7AE4B7414E1037454A031839AEE4C796BA98F4A739B785E3854E9EF0D5B7415C8B7ED012B0123C335730C7021CE8C94200874EFE783D7C4BF768538A448E76120635217727C81D08976CE4B5027D4BD9D9E27E4BCA4791ADF6F8DACD1BD3A03BE5CA7F68C2A2247FD3184609EB7243D2366E5EE4C95CDD869DE41A4B47F021DE76CF27464F814837C648A7A7CE2F91104322BE3CB1160A0D10CFE90ADAEBC87BBF14387C8387F4F5AA10FBD469ED5587EEF537106CE0F3AF4CABCD4476F248C21D119523B680067B332A1CA4C657B9DE1360FD23ADE58C5538EFFC8902281FC7B5C12C22CC69E7EB18E5F6F8352B9E4935D06C96BAFD834934618D9E6B1F60292352D064A0EEAE80F7B721312FC1B6C58D68A96351431A8626CC117BE9DFA33A1625BAECF12CB1DE33BEDAD584A91546DC767D0E59764FDE3FC29052CCE23ED28CA5DA4507933C0A7702D9A1225A48B71FDE5D27B12FDFF16AC2802E3629E10D5FFC2FCC6135243A9E2F3E3867BAA0C0F0C77BAEEF9DCFBC723C7A2BCEDA39B53B415BC21A397F9A8C4DC580EC512DE4EE4E0870DF1C4FBABF4906E0CFB08863AF2A89949F8E0FF9385ACA3F588E05781C49DC563EE9E0C5D6FA512932B7F5568C1E0FF1C9492ECAA5465ABFE125B511723998C4071481BF1C53DECD59B440931AAC640D9F78B1B40EE46AC0A8FD18B4C8AADD734B0F03F02CAF6A7BFE3DAF100703BDFADA7DBB50ACE3D40A05AE6E87CEDC0B08C44796D7A63E8B5BC95D97E3EF706E1684E791D3B3A2BAE1E7A92FB70A33D896219E80751A41E16B506FF266C4BCB4346578BAA7732CA745BCB01988AADBCBBCC45C9FA3A5D38F3F8E04005AE777910032D992D5EF9DF2C0422548A980707050CAD9DE56BCE60EF74EAA4465EDE96B055999F81A2C9596A2B35C8AB3CBDDE9D26AED44527DEB9A2AF3BF6A853FA51DCCD913876A43DA3E0E2C5B42571101B7B930840B0AB64419E1043CF56AA3C2FEF5B39CB582971A5776F8FA9696CD9F67E9290E483E9BD1698E961E849A513608C3F20FF678EBE0C778C2A6DC1FD3AFFF89D646A1AB85F005AA14A0635E92191CD41A6A46CC283D2FCABACD2FA07B7E2FF97D17B36E0B222D39DC1EB61BAB8146F147579D02A87DA08AB4ACCEB32AE1C8CBBB0EE0D90A642BB76DEF4AC8C7E477888159824349EB075DF0BED236DA9B2826E67EFF220AC84AC99BE6EEB0DA904887E3A84E5208AF49BB31EAA1552EC79E5BA02458106B5A31D0AC8AF392A63947911400FE78F6C94B3F8E6B7C3B98F6548E7894EA22215C87E121441C53EED726AE26394C825517EF8A477A6DF33B5315C8DEE16ACCE76ECA60835390E65392B9FC5EB88EADBF336FE361D190ECBD0B35B22A6FE6A8D48466B5E70BB6C5FA515CD8672BFE70054038C5893E514E23B16C39198B37B06B21275C2994EDF7F9F921B320B39E29444E3D621F52C9FCE19049D403AFBF1C047C8B065543BF43A25817533A33DE6C866FE9D8A73B2CF7277CA0E8D78F4F104C5CE6FE2025992E26E49D4C49F0798278216453C00C78EA7BAC2BEE71E5273FA46044B4B5578EEBC2A9E42025A8A3526B11CEFFCFF47191109C56AE105CD70A04C3F4EC43E49346203347319D8986D15B3C4A49F02C02994D8798499DAF1E0ADB81A9AC79FE8EB55ABE2BD18EBE18A9E5F35D2F66B38CAD6F6EEBD29AEE054C05D6F0B5326CC5B86BB0FC7CDA720838593238A2FB24E0CC36DB193FB7FA66573B064497F771DB1D965953477FC28989AEA2CC004640524A6DE8270E8A5B12BFF87B3F63FBB7DA25337EE34E6E4EB45DE9A39BC9B95ED37A6A404ED2970F9C79A7C2953420732C496B855F19BBBC8ABCBABE1D26D5BA828EB060D7280046AB93979E0BF90B6F1C07CA70833BEC83DB41684F1842A23417B3BBA0A33D7AF7BAEEC14C9C96FDF30BD201C05AEC6D3D2F539D511FBB356DDF333409EC16411DC7255DF0791BD67892880A4DB082684BBCA8B7E55B421C17DF3B68720E907C1620B142C3382AE6E738F8943CD214A847A6439A682D62CF0AE8961B5F020E7126C5DD6258CA0E8F5711E5472A4C05ADFA9A6B8180B741F382090CD1C781F7CC7F23E041800F42B228C351AA21E4D916BA5D9C56CF8E9507065D729B7C3653A8BB062C0463BF0B97F13A1016BE4851F5A489081A2AB3D2AC2744008BA734ED38DA10F372D97EA0C278C709A23ABD4B07E91ACF6A6F2DB9AF7806820381845FFBDC4BD30A503A0F74F37748E3624BB2AA478210072FCA83AD1A43ACE9F2943AC1AB6CEDED67938AF921FF34F2DAD4F224EF7498BC450A67CA383A9DDA333073286A22B85570A11FE03F55119794BBE8B81EDF1966BCA5E363C15E8E8673C94E3396C9AEC28D110408DA5561296E2928C6C111A4826309F119E5456675AAF935A17E80C0BD82A9CAC2627D6FAEBEC9A928D33980A86ACDB35686306B57D466864A0320F21751FB0041BA0F4F1660774A519D3ADB304438C1709711B982EA84D1B193D026081A4663AE69C5E12C3E4A683FB356DCA618191B29290C5DB4AA6A069C3B8D61C8B7FDA779E1F34A5F62EB7DF5C563ECF1200D3FF499DD06C2BF44A2B4254318BC402EA3A047FDB3570EB40630CF1DF84D1E2BDF5449A1F65A9DEF76954B5814691C4C12BEB10A1C006189968F37A4B236D9EE0D39AC340852EC54AA64FE15E1A4433ED48153D23B2B648C8852F3E3AE485474AB2DFD58A7F0CE6691ED36818DEADC8973E6ED06AB841B0A915425D7B87E41E1E68B00BE2EB725C287FE575736F6E1AD2AAC61F02A3A00ABEB2C0FCDB35564E8446C776E980636D5D61740AB2F0736A021D82C1D66864E5DFA98C4648CFBD9C7AA865F6C97038656C9C8767898FB43B0919BC98C1D0F6FA4D90F711E5D009D4C8FD8A773B7C73CEA654A2CD52A276C6CB62265294869A052FA1634D3EDEBA1F69DA09F0568F9D2F6C511F6BD6169BA0DE25F09FFF63AED2FDD0F6D89BD01FC5B088D3EE5344FCCC0215B6436987D6167A0F2D5EA47A984DC86D45534BAF35129488F3BC2D05BFFB84A51A87A1774033244277D0F2B45EA43500F4034081711CAD67BAA9CB0A58E1D01013032EDD5EBC7095D4BCCBD28A5F32BEB685F7901BA7A839650023B0C908FF33B37D038162FB96EBA35C2919560267EE5A94035825938D168481D8E59813E20DD611E4E23D8D42C9DE1D2398CE3CCB3DE5CBC4BB16D555985F411EB5B56508C6F4E75621304DBA2F4F1A2D8B2BEC5793478E5AA0DAE6F52C43253FE7BC91D3FBA84F8525D002CC307CAFA20BF198BD8F28CB579960A1168A1D26340C8E26CEF1261F23E97B806E9F27BB51F16102527721BE0E8B930A1ACC38F0A63EA1F3FBCEA1031E441FEF4D3746EAA37B7D4F8AB354D5F079E56FF4446333C8B8B7B589CB36DF40EBC5A75D2237F3FB874E7E0FF1B96DE43BCF229DE1FED3FB6D01752B3271E1F98D4134114911BFAC8351E3186E90DA3DE2E7FBBD305C822FE6F06ED1D4774D7A66DCA0CBF740DC277C62FA641ECAFBCBE359A28FEC48D62E1D3B6215392C0F8DB601E35A6CBD978567E806168A9F5B4915A80DE405038C4A370D898ED6441F727985037A040163F14DA78378931D3B96BA486958AE8902C98BE75BD0AED53CFB609923C63615917EF0BC6D07CD183192DE3854133F701B9D4B499F958064ADAABF4080C4A019DF1E5B98C8CA265E031B8CEC355C8FFC3BE16DC3D01533ED17C9769365D023CE7F0384D40F7B6179612B5EC382982E244E2510B4831F2D53F26B142A33877961EF1F845370CE115CA5F0D2FD6926482BF3BA1AEF3212DDF36705A210D8076A4428C7F9CAC411DE590452C761028469947BEC31ADCBA229D8EA58755F2715AF6D51E581D2CAC4182557E6815BFBB84BDC54C9368764CC29AA9AB49EEC37364F85AEB3295E60CE6DB2639669F55CC49D7934BC8566AB5E207B33F29128868BCBC1DBDE1089317088EA3FE1D595376DAD3BDD156802F82B63CF4C5ADEF9A89D94493BA152F9F07A9E9CBF8D821F1D6CD602EC49B61AC4F7633EC810F3D01D4867B1F0F3021D70897593303CFA6B5A3BD0303AEC32105F854C3DBED373760DDEC9B9E8EC4AFDAD00FF2E5A05A0113522024B86F1AEE6F250AE3BF0AF1E6FB7DFA8E04E3F9D5C876731D9C33460FDC13CDCDD433B45A6BF17E98638C264DEDAC262BB03714E020F4576DCA85DFEEBD6D70E557DF9321A8AAC519C419CA20E33DA37C22047D4CF925AD67545D04300A42B22DAC098A912848302D830E06CE5BACCACEB6E9316F9B1DEEE271BC6AD9D74927CAE725CCAD0C596653731869E8071E23BF"""), - TestUtils.hexDecode(""" -a99a8d52ee69a69d91581ac798a7b34cc594801ad2f15e8769de6761048ad79b7dfebfc6f97cb7694d14fc315c879de9029b2b5331f64ae72e36833d3e5bf3c4ab64b8ad225d7b17a146f4d15f05ff72a7ce975e6558d11e3dd0e24c5b8d81ecbf96c732ddc2af021f62ff48719eb70ecef5e65a3acd389afe3ebf1fd6bc218dacffe07c78ed1ea343b603e61d5af9f6399153572549b29f88139d08ac0899ef084a847ec0fa58d0ee3856dff6262fb2355873cfa1426eb3f80ab52d3f6cfac2bae2a1abb12a68e6476f7593f5e5694d541d7d09b02a39832450c80eb785fd1cc13b441a96f22910a886aaf3ff61df7ff9f079cebeeeee218495f5307da9ce916bd86698560f758896675af604a3bfc2721e8e3dd4bd6664950d7e8575a09d439ff54086efa2405dd362f03c6df688120573884b46e45970e65934b5baa1255d6344fb115ffb51aa25b1bcdee1020e754bcce521ef28bf26d7bdfa498a5a182ec8d202d7dd0c0926b71c12eb74ab4b541c822f399bb4f4a50411ff28784930e8c9a6e77afa420a958528d4848f6255067d19496a23b39b21b572158178fe1e4749b3292133ecedc0db2038fe2eac7ad1fe02f426af8391988e46bdc8b621e2c17704360decaf8d6ed08ca825b1b3b8ff95024f174949c7a6f9d8a4a079f2fab1fa0132c01f09b7f7abe7d6aadf9c53d58a97d270a1f9065b295b5c524f3bfa0de09ae02ea5b98ce4403418af601e5cc876b4f0c95ecb7c1b8bb2f72448f721d81c13cefb99106251d4f37e47dc57d9449b405a132d25a2f08ddd8dc77f0eb905d6f6eb0d0cce96b95068d669286c02f1cefdade77b3dbadfa7cb912c62279d0a4530cc5c52941b19de495e2a2a3713537b584b2f7b76e3952ead9ca20b7bc9bf26bd36176521f4347cc8b3c2553d37ee02066258dadf33306a2743917287c09ab07cef7bc4435d582e3cc2fe79c272d719f133e6e5ff1341cfc139257d5a7eb146327c03e897b9668567b6cd9fcb74711e73df074ee139a57229879b903e55a04c5c9fe9b6cf669998444b93963f85ac7176a3f021d7c9409d7ee827de8a11cdc431521c96ed22fa6f13759eb03687d997a25a9bd60800f3f534b3e9c9dba97206b7c2f326b34a087be1798866d1914e59c8eb2c77414be030f8dc270c6ab76a6e1515fc70ce50c497364fc55f0ee4f49d3d22a08c6b9348042d904ec2f8862ccf5ee0b3d22d2f1a99579d35a916748ef608406883c53f18ef4caeddcd780e4a44c872bf2dca063aa11cc715e23cd996e4e3874463a1b4711bbcdc2418e4df10667930cbc7af5ed9b629ed452c240e02b58ef61ee4f1429a6d9aa57471781887f2e1890e70f7589f8d8b4e5ad223ba9d0f73d3ec74d8249b82596c8ec733881fdd0c96d2455ff5e340298a5a6fc91cbbc1ea5a8a3908f6da6ccbec88756874de1518602557d2df30505dbdd6d59469a6f2bfd240aeab1099c350d6730892585c577936181bc9f7fa6ef3dbb0c1d39a082b1a35a86899cf26261927d52b373120225752792f02cd2f196b5540121c3f9c0fab27b44b9462f6396195e21f2e1f736095554de7221f3c9ba23b72b480852c86b179c0e4778441c3c5242d4feb9851165dad83804c7ce5d534dcf918d27ab36ea1faa48149307b95cc3bf51a6bca256f115e3c618b9787a21941b58ce52abe359eb1a5a19aaf67dd56950a6d0179637ed0ea5421b899325ba05a26771b9449ba0de0b3e674d62398e30363d1d885f424dbbc200af85c87d28ae8a3054d82d4be0196188089d180acc7197f07033cca984e20732e9029e832268ea405cadb00dd002e3506e621d3fa7b023454329abe1a48f7dc35730f5f352c25694eb2a0650f9505866d9013e8b88b19b0c5dc12ce799ce8de35caa4b6552f399f8a7b06bf1e5bea54092b504d9ce81fc3fa2a40dd9ba5a2b8711d02dc46ecc222b14655b151499f4b537260b6595a89703ff56ff4c976a4592dd53d12b6fa9a4a775acba17a1b3dcc5ec0a4e03db9c9402ef6380e62d7f76aacd613a482d31cc17a7ae99311a01916a3abffc336959a491995183f531ca9ed0af40131a28da068038649639155bd12b9d3a06238cd3c4b754905b56dcd52cd213a2ea369623f32ac7877e6150d0f5ee25de926829beda4ef67cd3c4323042aaf3deecaa4d404426f234fca778826dd3f29b007d369ff1a0af66ccbbcf20d9f33565b7ed745c160cbc5242c683588a67223d81409d77611cdce68a0478bc50422da24632852862319f20b446917557588d19d8add012137959e6791aa7ae19597a8a2f875bb8b78b17d6f5d5b10c1996414ffa08e698c7789343487a62a98474a39cac820ecb1a855dc825d1d7bb9c302f9945b4ef5ecf2e85d22fdb7f440018181ce3c71fd8a6493c7e0ac2d38ae115a018a3583eb45abb5542e66cf77587ae2e1da41ef8b98b2c2616f6b62d3e2c7e467955b0ab3431d1f5ab617adf90334d87b2c01e450c5750347c1c98fd4fd4109f13482e11e2a6ebc4a362d26c6ac9e4d112d18c1e90726a2042ea3d5543c33d32ac108dcc34999db8488895315f18fc0d359714eb6c10b0dd405f6baf03c0c7a3b89d6ec2593c317e359488ab2a1e85a722b2ccfeafcdca2e22718a17363634036af5aadae7bbe6f48ea36ae216b827aee084696c7094dfb6e4fa563b51cb1fe41f8e72db7cd527c363bb00bf8d22896f438ba637bb7fe64054d69b628254a4cdce5ad92f753cee7889c460af2fc4cb10ff6458bca2547193ee76e816a39880f48fd2e246b66efb3056cffc0d233a86307e13e7fe87e4b4c8408cf7bdcea51d189dda4c4cb4fa44b222e4d0ed51a18abf77b49fa0280dea06852e864431c1b4473e876e2fe4f00d423aaffac81b95f186467e409583252662a0761a63ac3511058b4b0028d0ad1b760994c98fd7ae64bbbcf8e615e416bf0c1a594c0fdc46f760d5dc394497cecbdbf06d7db93d2a711756a3534f7550dafa01954f291bbbb511b652b032eb00b804d654698127e2ef480c53f47efb10c949f50168b1d888c62c9bbc422dcd07ea4005d751dc31d374357c10af8991adba9e139e75e3367bd18c7e1ac9753b2241960999e6a0ab795c475f5a330baba955dd34fdeadc193d9a6ea7015b44a04d0d5fea544c140c2a419c86f89ea54e4cc2ed8830938b171514a189e5517949c94ab77a5e9521a38560f3bc4e389c7fcb0b49da3f037ad53f75a85c0fff2c43945bb3d3ad65a197c6db5fa9fe3c78293a2a499ab553af3756ddcca3892133c1ee40a7b73bd19262b33364c575e7492a5b0bcbfcacdcfe4e9ec0e264b4d52576c727d9a9da3a7d0d4e3fbff2137789499a3a5b6bac5d4d7dee0fe0317192e4144484d60626f767a7d8c99aab4bee60000000000000014263549""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -194345a0607b1df8fd01f58d30010604261e15d712806f9fb99d3dd6afc994a917dda45b8e4e58058632273a75c00a98e026389b18ba7bfb412cfb510a335d5f7bcf8c192d6e4e643404f1fba8094a76c16682fc7aa910a572be4500a034440dd666e6c1a4f0ec33c699720a44ea8ba52eaf34dab236ebdeff18516606215c8e8071d7f40443253752f9e7593c754ac2891a640633d6d0b1178ef8e52a40f840d78c972b3040eabe17b5d24f99c75b7b949ce2b4d00802b1b0c14c786483310ec86a6fa24d47283c8f3ac2033ba4745830b26751897e121a0b190befe243f034a40f43817308f9f4d37264e99f43c9a6e5ea7c5d03787a0f1e288dc24d93cd0354b32004c9891a11845d07dbabe68ed9505beeda51ce431b38a8fe8f1499b54116956dc11532c6598e0c87e7dd57422c0490f74cfa1d084d9893838b115b4241cd55ad6eb382b0c287d2135d8df9b5d026fdbb4bbba19fcaadb38e26c3d14f844e22f870026f7bea480eaff61bef74ca4d304a5b49974de22951f069744df5cfcb0b8d13d2a8e2682184d79bff6e492ddd04b51014b205a4814e2953f8c94b080b071209187678d9460dc1ae115c83e6e597035dc3578137d781d4ed549f8d66c855022069a86cc91f0ae27974cff924ea9c5e8032c4190a384f9e1eaecb7821497cb44c4bb411e107e6c507d23c877e6417fc313695c99bb71e7ff5c3f8a6093d08228b8342ae11fcb09fdaf38698b98895f519f5c87e754a4dfbbc70867661c5a6a8e6034f1b3153e779406eab5681f7697cb3b2e95f0473405b0126068963b74a08c5810310dd41058fb7180119b5138e44ef42a3debca1260b60c65daaa004616ca73d59bfcc24b18a96d72eea6dcfd018d3234278b56e398cc24367ad598cb1defadcc6e1949cb7894e7dde1e4012f432cd3d3d86e7a8ba4c96dc49002012655a11ddd17d4eab510d4dbceabc40c8bf2879e7e1fd5ae4d6d3d16840b026803e1e06116bbd74c3e3a864a2c72f4b758392377038fcf436fb83aae85c0e56676ed444248f0004d88cca4ecfb96fe1e4ad34e723a5d4a33ddd433c848cef1a65cc0bf8b16cea1bba4660af54555b48c4b1eb89d189419c2bc65b6681c1673d5998c2e51436080d3173229c84ad475b1552cbe0f937e60c4fadf3734683347216908e93cf2d41594a41b703fe7005c6bd7b1762d2ab3f0fe7e69dc5ec4f53e6460f7e924950584ee44fb3354edcf1f971f4c05c8a7be858f601d70435603f7487c9d7f51e4644aaef76e9748d8f2ed2ff6d03b4df231d63e563726eba99e549b5dd3cdc811093d255ce0b59b60e68d89c38bccbf5d37df816a286eeeea5eef12ed8e04f2222d71ae0fef9d901042b22131d7f788ab9d53a6f82f3c0fa46c9ee90d2b5d7187885fdbed61247cd44b80065a543f9806657f0e61d8e27050f817121270e7871c038377b97d3dbb26b6f935a0eb001eca6800cf4bddd0758373583e78e7cbb26db88ac874e4e183e7a0d7e4664bc573728744faa48d83c7f8fb56c06b91adb52c419f7d73446b9ac7c7c607bebb424b7a86a3a8ccc2aad419dbf7999163162facd2036ad2267e34293b710da6e6fa31b904fda337847b83f179a5936cfeecc03fe121964642d6245e63a4a5d264631d7b82278a4a689642fbcb9cfac6af2e9d81363fa46e1b71725779abd771eacfbf0d6d92e59d52b485203d568b2a6b55819a73bd129e939b1095770861a43d0f6cc44b53f50949c755c6b274612b611d5418bdb7753c337c48ef6ec49045644d875960beab7707ae7610c1382bffabefd20eef4c68eecd2c17f1bce375048b236ab98f1fe1db575475db6e1bb"""), - TestUtils.hexDecode(""" -7EBAAFA6D04129716131907EAD0832AD490D09E97D865B4AFC5D6B0FFF4EDE6A52E961ED88DB60A325AFF2675DFCD6A87984884AFB8680DFA7378130E44F205398ED7B83B1AC32D2580570FD6603827E8E4F5E20A27758CE6D1299BAADB8A895AD586BDF7B64F8D7A52BC15455EEF240F22FE98CE4CEAC03CDF7E8A983D7FD1A59C5EC594474AE77DC43EE4E7B25C556BC1D91ABD2015B99B1AF5329DCD41B93793D791A44AF5D83DABB8E40675EB32120C57D9E6B7757D3E03008A2F788336B8355AD2E47E61B39BBFC2229D53BC9BA514BB20F3F9EE9266BC0015FE81980FDE5637B3018046DD3D4BC3D549EC394E190F1BB788619CFFF86C532B4B9F0F6F951C0ED691C59AB0CC438290E9D6FEC9E75BA4FDF12D2BED2CD988AC411310BFECBDAC48A61099CE0D0CE4B44EC9C97108A44E5C5EEC1D3154B4E72B8397CDB0F7D15AA358076E25B7F3EA1E6E80A214051C440EC4189137610450144641B1E71B5334F0DDCE9D5CA30274E0237E45B4D92D7D458ED9142CC23871E56411382CE40D9CA4358B417261C2E7E845637FD2E9B4357E7EA5F4A8076A7C2F40FF1F8AFABA5393512F690EABEBFB73811B974E57C2D473AC22E747A0EDD39E99FD6E5D3668F3DCA1C795CE27D1A155ED9595EAF9061CAF5C55F3EE97056AF6ED90E05D41E90926F69044746230C990118E4D0BE4C12F7A4AA0464F8FFA7CF64C07FEF171B2E43A917AAC2880675F929583E9040BA6FEEC8262002613AA91A2B8D4DBC1D36F23FA9248A2D3ADB1DC5AD669EA219D35DB17C9C25095AD7673445E59DA6CB2260C8FA57639D6BEC8AEE307BD9C96EEF00C93318DF7DFEED970DC1F61AC5C94D4086300D91199C90C95C1A24F7F1E4292A60AB67F30BA990D58C71002D3548A412276DBEF3984FAB312723880ED479080EEE2B636ADC75AD4423A6E0C5CEB7EDE528F871FAF21855C3164469B9EEB47B6D37CFE4222DCD0B9867B00BEE12C27590DD77C24FE640DDD34E9138E70D15F52E94F3874447CA5CEB48573ACFECA3554E2B76CEE4E31060BF132CED8AB953F0A280F7916810A107AB5BA66047FFF0003B1CF13BFEB77526265B98E54E76B891A89F3AC0ECDF71406674865A0936BC57F87B64424BFC8FDC41E471D951077C32B5AF960457E97CA05F3C378D94B60A9735E9EDCAA96E413FA391AA687FD07D9D021B1014CDF241E5460DB08D3B336DEB4CF0AACEA57E4DC6C464F698CFC2AD10CA72C102A25787E0B89249F63406A39A2A792B2DE04710C41DB36B55D2FA789004E593DECE9865771D8B16B5436A792FBAC9934852B1F55D518F9A07CFA56BCF488D61AE355D63BDC27DDED6A56154B8BA3AFA3EC9C01D6593C83C315527F5FC61BB169723346AB4075D09701789268EC1F02EC4A1CD8A5F2584E29F126B1ACBEEF660CBEF16A8E9FF9C0B542042EA76684F9D70F2E3F3C18606ADCB1D695112B129B301008EDD5E6121A8948E1165D350FF09647DCCF4A1F8605ACC750A0AA8319A6685153A7672B31A3DE785EB22E1D223D6271282AC18AEC83C760190799F082D7FB0F238F627271BE62AE5A36A34D65B5DEEAA12D6B14B59BD0C619D8D9A44238AEF1FF83C30118039E834F7716CD59E138E2ABEC2921D9FA92F6808A760031B2157103FD2EAE988AD6CA4F350F488261409FE91B5667A9A2EF1E226B8BFEDDEDB84ECF993E9A71220E0253D2C4B918C5521C7953FDFA00D50A32879FC0A68D2AAD13EE181DD47DB9E3D715574CB3D566BDF30209297B01A666DD7DBC5464F913599086AA2FC6C8541592CEFFA067B287EEDBF4C9B9D6CB23CE1DEED628935CB2D6B5CEFF3BC442B2BCBBEFE4AECFC455A3A64FA117CFD9289FC27E6289750005877DBF64CD562E2E7D1C99830F5AE63C70685B3898D420862A8C4569F2CFDF564EEF4F94FC34CDFEDED8854855F3A4E52C612258DB5EE4D702BBA98B450D070264FF86A440129DA2C126978DAB3341C4079A66F9C23445C5938FA799E78F157656208BA7C7BC7F936AF49D11148856BA55910A6A736D32E0974E50BFA608975E37AC0601FDA7551204EA66F524DD03F44F5DA28EED5D126C32794F1CCE747DC1E9B1FE287CA607F81FE7C795C96569E66B2F3413DA810035D472B7F5AF74F9CC70306A8EC36F1383617D0FFD92F6DEFA7EFE91C840EDF24430B197802979752FD55A8CA85FD8D4FCE774F1CCC540F77C02E16F1494DF170CD8BA57A86BFB086349D53E8A62E1DBDE03369757EADB0E985A038B31DCBEF513D4FF9A3BA6E8338EDCECA7C3E9417F9E133BC399F2EC0C72E60E809F79D55FE1A917CBE28FEF19D6D08A43F74DF496EA9305072C90AE3BA0D21A1AC0BF040920D3F5B8703C12A32A6864382E9CEE8D00CF4F93830623E76197F7F52309824B08B8E0D5DAF5662A36981D50880FD3A8D73D24430A1CB201A9D0BDE656593B37B8EC47F235B5CA251249A04507DDB81F8E5E4E5E414B3750AB168BA51A8873E6ED153E302F61F7159B658E316D6D183575D87ECA30185CF72C67543CDB658AA07B1DB220032DF80D287E769E3253C80F43570AA538EEF49F45316E176F1F9411F3C085257C6B8C708DA7B924B792389A7EC34C7F778E6100333E8B9FAE75A4D1A32E306AEE36D29FC6823399FF37CDD0D11C8D03F14740342B736C4EFB5302C141A86C857309A70BD74DB6C7C29C839F8D86F2A136F67A0FB3A3749542A9DD8D4A062672C75B67D3BDC3FA6B56F3E79008AEF8D8E04CC7781B23D0DAED64CFD1A91DBBAA2C9C4E765FE2FDFE6E8533848E51FA027B86AB05A0530F15C1B7B6BBB268F09A7865E202B1645F8B4267CB1A49A2929410823AA9B834101E9EFFEAAF6E406639AF7D2710E60A84B6205339B0719E05BC6724FC2892A017AF86D80D361A7FEE8C284CB84F5F09B90CAADD49CFD396E6AC36052F5CCC8E7667CC762A9F173F837A231D57584A3BB19671B8B71907E415A1672475ADFA11998F94F28B00903AC551E651A3F9485DC0ABA3297E561E0B5A5786BAD9EC8169CBD706AFA60AE764BFE01EC514623BAC6C4100F707C5E8A02F4B0D6265502AE4170AC3EF95B49ED1A2BAEF56F63D5667C9FC0AF4C0A8648FB6AC5444EC8A1FAF4715027AC9F5987735D1AF7C55AF4C838FE9FC84FF71F929758DD52E2BD4A34237350642C0E641B6710A66C9C1EA1D9BDA80198FCC56D45D67C3511BAC0971AC9B6166633B1713A969B8DBC3CF60FCD6998137AD713EA3ADA84169D49FBB7F5CDE362ABEB0B71D022D9ACE7FF48C9EC1A7E0C72B564FD2C620272A482941443838D0506E2294B760AC9DED5404D3C4D2898315D3E3A82D2E944D537817B9901AFEC343B95F2844CDC4AAC3836E7713739F4201B95C42FB7C99AF8667628C1B60115BCB185754148B3C7226DF14B6DE1AB4C6043329B176C9DB9B1D73B3814FEB89E84A4C91C84993752B7AD30CC707A71339E8A277A5586BA85CD090F799A6B75523A62C6DF1549D787BD8722D1F26BC2C150D6A38951F3014B83DE665B21F5D9D97F2237333CC10A4114796D56D13D643364306E7445F475729602A11F8BEB002BDDF30E579E26F2BE4AE87DC666974E24FEF2462120B6CD8E79D65A2E80542A9240D4EE1F616326AA528E2A1282EF49F0312174B67D40FFCB1370BAC5D1444D75FBFFB6B0887F4573A8C4622082E1FE349B2C73CDC92592F684769FA7D7CE6FB5AEADF38023E51DA4EE3EDB10368442B218919341FAFB22EE80DA96A52434B184D499A4C49317C62F6D6DC9EC1413D01A1CC3DC8853444E52718798EA158A12B72AF023079E5E76F41AE685494E947618C4AB3036ECDC74F7A043230A0BE116F2B617818A2C94C54CFAC964C73BEF969591A3CB2B7DC9CFAC7B4F9B64AB70BD7FAEC138E42908BC90D6ADFFBC88EF473CA8CE7BC960C4B3EFFCAB92E8259CFAFA85EDB7832B3E630D6D2CF031B8CB570E38C101A56B426C654464228D152ABCC6DEB888DFFD7FFDA974E60CCC2AF7531F38A813E263D9B20DCCB50229E7D8F379F81A280CEB90B64BA3657F1E50381B468D0A6608A4B5E107C4736FB4CAA10FF3045C05453EE12A9FB0B79845E077803C69CDCBF7CCF7D6FE6067ED152F67023CAA6095D1748414580232007AB3426FB2889E1BCDDDBA539A2D79CA523A2CD1B1314C87502909DA849BA9B11F9104772BBA27410018348832B0BFDA4F09AF02B351927F2B6D29D9CA9F330266EC035908C9D4023CDF2343B177F57903D37AB89D0F9E23EB0C4100BC6421235CE5FF2729C2ADCAC24D1151757D8C6D6DE53DEBC38FE866142D1BB593974F4D3198C03DE4625F41BE3D488575B25007C2D5970BB152BC1C23E48A88036C070BD38604C5844E4205F1EF3D7FAC0B4B9FB51F229BA322D3355E458C27685130FCBDF591C0520626E5703A2E85871A62AF0CF2DA3468C401644656CCAB33B2402074C59A0EBB57928F548B5FA4871A8B2AF0BFD9A871A5C257044C17E4967B70D0DFB59F1345526FE59B4BD92A1C06B15E3A6226A4821FD614D8DF612A3D2DDB2DB67BAA3878C68C16645CC747BA9B366677541171A9264B89EE18D9D169D341629393C5526C28B24CD4CFCACEA9C42DB2B1CAFD7F906FC17CCE16612B1261E62E2A700CE74DE73174D3A1E06AA31AA05044EC324F026CD39F7B13399D9D86EEB53A6DE84914719EE31AFFEB630F3D8F08B4FFB10016209C13BA2158ECCB4B74BF04EFA73222554FF5EC49709F7F8DC1D40005E91245F3A5E2A00B9F64678B2D8A9E6BF1D011900D9D12F7F3BB023D1E5985BF78F8D6132AF5C0B9C330F361EDE00473DC9EE7469478FEC02670E8659B643B92C5546C32FE7B0AD816A5080B5E3867DC209EA15AEB4B14E42AD58F34CED65ECB3B519A54BC25117EF8D392A85C2895B5A4B73CF93077E360A828570FFA02ABA84D6534F3EE0C935D97D1D1CFABBC0D82E48937797FAB31704588605082A950CAA23D6569AB793FDC31BBA561E729E80979DAB84ACD4EE6B2CFE06D2EE8C4183D33B9F894C6865D9CD405C7665E0150B2B649159BE684839BD12CF0091614E1F821046238DC9F538F769FCE51E9B8DEC0E98442CABD3A4296F1D4331A16D33CA356B11E3DC13937F814D3D6281A746F054606DC52B737AA40422471139867624CC8E9C559BD25C7C6D7F902677A84BA63E8CB817820048C1C0ADB6288000EF2163B51ADD4D758D1C87FFD574354B41CA5AC72228A7E9E9E75BE9DB18FED47C32E3C561C972A67D50A560017BE794AB9BB6B50CFC43D2F6D57E8D73CAD6227C896BCD18E0D7087F57C365FB9EBF5864DFA4A13B6B5DD7FFFCB648C1E1FE40B6A10EC0C45C74504CF2105AD443DFAD1E306F720B9CC37B4A30198D3123FA9FB2A7A9DB3BDD98D441B03E0EE6A8180989E76CBC71B0E8607C3A9E5D20B6008B010702FC5D59847AFCE122F3FD4FB5D89D3A3331AEFB96B593F724C04885B574A43B5EAC70B543BD191BB818768C67A10AD6E2D62AA4C65FA373A19116AD86A4F9A97064E0C0BF80106DE6654B4A3945983B7DDF3AAF1E14A04F6D3035542B0F710352AFC20FEC78B61D8548B9669F10B3D6E531AD07A84C493264DD49759D95A6AFDBEA5AED1C7D7D2AE6D2FB6747151CB6A5C2F9C1AF5CEDBD9CDE8D5993ACF080A0008BABC759A9DF035C648609E610F226ED128E2656A057862246B65C70774B68F54D68073393B85110285FB463DFE394D9DA0AE85985FD6882EF5B11FAEF2BAC18F9D9D9B5CBF0F80AE7AC4418EA658D68B14BAC135452DF271DD3348BC338BC6C789ED95D5C5625762E4CAC6514866613E6D533AB9814B7C337260BF16716478401689F4079644DF4F734281C16164D19C4ABA20ACCCDC517EF42C19A5B1CAA4658C27B61902ABF88EFF0795D2C971608B0570E016CA0568CCA3F7B38FD3DF5608154A33C1F0D70C2AD0EBB134A8F475A8BBEC8408D3B9B0BFE8A6F10FD6C979B13C3EC73F191B788A79B4D07AC45172950689584C909247DC8A4CDD686186DEA16676851B8A7C311439149B1A963B0CC60E5395B56ADF27C25A51BB4A2FB19E14CE66B6D11781E89B3EC22CB854A12D46970D1A009AAD071C479D9C731770D666CDF0BCC381A3D328542F6371FC6F5FF7C4D3BB06186C048B2A3774EAAA3CCBA1342927B498F2195213326C9E393153BC8846AFE2120B8FF4A455B59AF6E65BC0CE9CA3502BE73D74B6CD12A760A9E0E0D26BD105FD993DD879539CD666CF2025DACD481A122627594CAD7C4FE30948412C1C6A160C358E16B6B67653418A22321DF5B1A9EA0DFC3C82DE3B8CB0F48EEFA7DD6188023D1B8B7632270E63AA38873A2C4472F9EF1E8DA56D5328C00548DDC4D9FD79115C5F6168AA98099BA1AAD606FB92F8D253C9A55773E5629E84350F3BC3B00D803E83CC2516C6C29476018ACFF2ACF61584A175E67EB8952885772E6C2D7F9C2B79C8B2F2A77C73C8B0230F080DE716B2A13DBA5FDC8648F17573A2898E72B8850997B6085F98523F00516DC7A90B9C2701BDDFE505A6C330D1118AFABC731A1DEAB813AA0E17708122C0069FB61A02FF6D5EFDA990A23E1D42C520CF1975FF06F123E1AC0B0A86FE666F8843C406F5F1E1A36FBB7A0B41CC641EB49416D6F0AB03CAA6AC0CE3A3DD1977B4D16EA33CF75A37A6092003D097D0ED8FAEE89F761B40F7E600FD502887AD90BE4BA311B9F4CD9D348DF230A2EACBA3FC356B506ED8C357E228970A948FC4983AC3ED9C3ACC22FBFF56783A73231F7E0B91DFED20E754ACE7DDDDDCEFCCF3ACC76554C269D634DC228B38C284AA35C00487D7873C8CFE8E8657726FA845863719FCE5A9E32406E2191B791F76DA035A4C862176040DA9AC0F37E66FB84DF89CAAAE9D8804824725FEDB95E5380DC66CC72BBCA1E131E6B785EA2B2B4A05BDAE01B22C3D47CA85092802A8EAC42E963A62307476FCF94ED7EBE5538A8C6F28A6C65914CF48299D3BA2B89B3008D29CD874B79A72AB840815827566E50627C2C332B1BC60060BF2FDA320FB040FD14D52CA59B24E325B5783BA1BDA3B27415C9DBDAA01562466322706CDCD0307C3305DB08D2663C57F6D3307E1C73832F8CA712402C7402EFEE0F1BD77CDA08F5F6582540D34F1B2809F84EB2F540558EF9ED46D5C636C45856AE57FD9E4650359635BE72028D1CD37CD876E0DC598E360CAA1DCD1F9F2BB4CA27CDE012980080E91B1C7376622907BA6674F1EB9E80148E6A959EC74950A2B934D42B84D739F1DA528F5C6E1C90A238E5167041D4E9AE5352B74C89DAE368778A90170461ECC0D6B6C6C53CE36745A72F79AAA1C82D494BD89D719800A89127BC3FD55247C1A29FB8387F1E3576E0C45F4D327C0B24A75FE25EC6147C890F25E50AB3C43B94F451E5B5D67F8D3BAAAEA1FE211FCE8622600400F73C1398459EA7FC59D02582C2806D01023D84BB50E99AE9ACC217B7223EDAD956FE155152E7F35B2AEE1535885EC048C6E0C50D395B0F1C9D767048E9D2DA7F15BDE192C923F1C74ACE06600628602D1B0189FCADE0873880EE8544AF3E29314E2B5DF87BEB5A50ED72FDC093800B12CB2F870304289A73A65D7E2384EF3A388EA9F0013B2B5C92149E2538542D95FF020A23E976A7DB3E2C9913D87D6EFF12BB51EE298F1D2CFF18FDBAEF56B70CBA35EB9273F1E58A6CD38F1E682A759FDF8D8BFF60E7CBEA948E25DF0114BEBD4AF13E4E0D4E7C9EAAC2C5F579A1AB14E7FECF9E13F20DF873F8D0E090905D32C8F8C0033F5D8E9F1B9FF17EE04FE3656EB66F5E4777B60B047DAB9BDD883EAC31A6455D1719CB475D1715CA0D12762F94AE78CF3C8EE90E55E71D0AA4EBA6216A0E81566F7813E7759BED30860BF22178407783B9A8AAC30CB4D53AF140E33A47ABD60F33EE700C323277E751E5B32B221E4B9815FDCD400DC544DF845619FD733F164937144FC3D89D8186F8B898418459811B3E66796DE51D1373B248A9B3B9609FEA374784A33989FE9F5BB26D2148F7282E09C35E13295D90BBC7795DD72CDD4955E9D148BC779AEE9C7992BB85D8EAFD102FD690F2C679CB7003FC4E182678320738361C361747F49AC6149CF4CDA4B80581844F5EE4818BF61750047C35A4B10697892A80F07E946F357574527FD2D0187873BCE78EC99062C70CB4ABB72A104A770CD7ADBD20894E7BCE2874E45302DC0BCB9645EF28136F36E7B179BD003D5DFA68A572BEEBD40EB9AC1F9228C74A788671BBF4781AA31C7F8699813F32EA8B60414C3ECB894DC7B01E50924482E5C068F0BCA79BAD9F469770FBFCB3942D1A3E54250E87B3693329479217514A8D7B734D256C5D28EF854FC3F234BC671F5225B1DCC20E590D8E5D09C07B22EF0A89A5B863C2E652CC0B1623579541C63CE9C2C4F66BC43323D7000BBF2923F5B8A76933FAF950D2172C1D90F522301D9A0C22F470EB8673CDA0A1B494FD7EE9AC1B4597B2DBC26FEE33A08CDF91E3C59BA4F93E02D010FE3F1C1FCD694F05B7A8FD32D8E7CBC2934A25C481D9C58FED7E0AF3AAB527D6DEF43D53756F0C95B2B58A426F7F61D09F4FBE55D9AF053B92818ED9FEF1CB41FB5CA23AC85B0241900F73971558116C5809F565F71333713EF5BE87B0AC95364C9FAA80DBB9EA84B5A5790D20343141093F86942817D195ED8DF4A2DFC7F7090CA3DB46A92AABEEAE2D7DD8B9110F23A89E4FA7B5A1DA27D643BB879888A2238E221E2F67D9DF58E73C46023FB7E999059D3B81FB753B2AD333207873831AE42FAD8092AA04C0E4103B1CE0DCBD6B06CC2F0AB37CD1D10EC4C83428CDEF84041D12BF9ABEA5C80050A853CC73FFF3076BEE68078737F6EF483F486215118C640790D0CFB4C6E5243691FB73B1294E0D3A494A4A538B94FDD2746193D9FEA24C1C04F5B20D2D40B638CB932C35D953A9D31260B76DA878FD52EDED058D1DEFD9CE214D14C3112FAB00B7F2DC88F7EBCF79EEB1C9C8607D6919B8D32CC8416E2B981C141198DD9884DC3927EB0192B6361AB556EB3977E5E242E5E26BA60BD42892F46F3F2DF684D0D9FB41BE42C04F0C248938AC79F110075B42181DAE62801DF76AAB50AEDABF4361C0EC597F31245B0390CE2629DB933E450E09DD39E6A1B644B0FF672B52ACE2AF52780D3F6505551F52045028C4DEE6D1C6A34BCD5E95E9DE1BCE849643BD07E0E6FAF8B27504F859D73BDFC07FD2034595AAD85A9DD9AA5B3A72346D6F3C4B21C4CFFAD8247C8CAF0DD9A708E11450502BF3C28EEEDCB0E1D32D3EF1A3F6237E34C0E4D0222F496839B7374EBB7D786973E85392AA8FF2A9901D076DD4C65635286276698DD4388F867D1ED18650FEDA9B03C80A3B5BD0AB3A62A45ABECFD55898BDAFBA58137D4BE29EEE8B3B3D1C4467B63DBA1EFEF2C81CDE7CFB101B1E65084A0E92955690C8CDE6F93E23FD79B76DB475CD24DD92A7504510F8DC3B22EBCD0288B4E479F8DD835297B196531D2DC759364306EB6780FEF31C9E34142B55988F81312B310093F77CB89C6E819A7CD3450D0790CB7B5E33A3E5E51DF05A3BFEF63320CFF072D450D71E7239AB24E4D83A8E8E501A5BDBB041219E15517B15EEE237836672A761D36D11EC973BAF65320B368906392E2689A9936752563172B3A5ADD90066E01EB394C77E40D57553B883F446C42EBB9CCB47FA56816B06AAEB62C21C8F57F926420AB7C1D5E97E73F024C259011CD585C23D30F99D22197B569D67BF5965887AECF553A9B48DCA0C418778AAD65D4843221B8217D2D61BA5A46C4F9FF5B00B78CFA8B6496007A1444503DFB8D7CDE7A63D5D7F54EE5823A33EB3A155C20F0011304068CE0385A09170606FF6895A6955C211AEF5D13BB93866C9CF00A911A4A50A59133113A9C7DC53409097808A6D0DC44A7776B41A7A43818C77CB51F3E20107F080F6682D90399853104B8F3AC4DE8521048B22BCA58B5F7B5EB3E3503F638C1FD24568F23EC8C59A3359A5C9CED0305B1B81677E20EA35F9E896E665D3CBBCB6155E1B0539A0B26BF95396DB8548124519B71BEC19A17DFD4AA2A2E134BEFDCA352B01E1255A12377D811FAED7809C9B881B24C185F1D1273F405F5BE82FED08F26E6C11D39A604E88A1EDFAC8AD3DA9FE8B1111C7E038A14CE58B9598AAE96B7BE84C153A9B26993CECB1CE931E0CBAD5F7F6C18B68E14E83A6BCFA33AD2B3A707118D56803A1E55CAC8AA93EBC47F9EFB"""), - TestUtils.hexDecode(""" -551742a530ae4d15d68f1e222c8865e6fa59541a5e4b6e137197b52a5cb84548c099c3328b28865c34e90095e8959c65f68d8e4ef9e9cab97590736dac647c93cdec474c3e6d1c934e2eea593479349b6e56b95dc356cab1e2a2a7a94dd6490d9a186879ab75f16e0bb792863a7a8a19ed88d74d22f7c17f3b55b4d6440fffd4c24d814d3c09cd80b3d3d137882439f628337061253522775d68c1072b8df9403ff65679d24b06f1a2779ed76ca3ce153c264a06cf04948eece4f06243f22898bc815a90344479a8edbee87d0c5473474b1b588006f6dce5be82c7bcc2db7b50fab4c2cf06eefed93110aa634f6691e9b757aa8a01ca52912040a3ca6cd6f9c596eedc0a9d49f1bbee32eceb2374336f07e74b425d6a894f8c3e49a255068d08ddff453dff688f9c74a2be872e2a205018fb3e0149113ce438a7b83e60f536ac616d748fb2c590f3ec7e4c81629a4fbd993ced51995432cb8b3778f7d4e375fa54c9511e8e97323ac021b7cb2184bcce98f87a2712740ea1bf33670c4a718b475b31249ddc1a9c2b216efa7b5bc01f792cdcbd07f3e7719f71b81c3a31d8cfb7dc07efa06e0740743c9bc515c0983c845b1c7b2cfe7745c8d0e6967156cd36e88c8e3eaeb3c96ede6f94a53eb05abbd3ce8abb9f4d2c350969a8d5fdd673188cf5f8da51704b7390d8de842a18f5d900da6f0de22b9b4836947acd4d49de53e6bf96295c3f89a01070fa3742ca5070b56afd534fd4bcc280bfa5233ba58e3bcc46cdcefb5a07904ead0092cc088e8ef1de2ae418a8f977dbba6b23a634b93abf5135504ec8adae1647042210be6e6e0c9b333c3f1d0dc906ea63eca4697823fa06cbaf999ffa6894353d0b886bc89b6d8b80d88a80b570aabd37e8bfebb692a61ef6e344b4bc5d10a4d4d7aa2b2c47935ce37c1f2143be5df3d55f9a947c1d7244d80a74e92822a7e178229d703ed770a3a2e8e07cd465d6b4fda758867bf09dcbf050203796ca9a6926196f13d8a5d034f566522954999ab327307189e0791866385a3eede8b8485d6c673ca69452d0a7ed6a32142b74115cd39c797e48f38111b309a3b5a122fff1c8afbfa7eac2dcac8cf225c971b88a49e845447ccfc634341e2eeb214ab57de15ec8de38300871207d8bf98a4b9a44642679a67fc1792a46bc051cbdceb15b4355f56233ea87dd6613afa535b333104292e946ac29b73d04be3b83a0a6afd275fc02d99fa0a0b1796275b45aee6fbf801f5394fd5bb2670d18bba553e533d39d0e66ff194a7555bd23ce14ecc97ebd99facaaeb8a0d0e088d2b9bebbc48b4fe32da39a310e28150936dc5e86bab264baed9721beec5a6ab21db810f1bf539d4e6283b7a382984595eabb42b21aef0a1186d66c988132b0fcd17ebf0bf9347d64e334e165d1e8107f6b49403d77516f55e973469ec6d3ca2ecfa2df3c7a82d08ce5875e4a0997ab9c4189e1b4c37b5567fa7731d6981d96e9fdc35abe9ae1a4ab30c5b329cc617a2f92cb91109738a7a41da00c48eeefd6e003d3e25de538bf85d83a4610c0f86e7af160703666e6fb525122ecbacd13242679cb02298777001fa2ae853ec73eb581229400c93408644bd64cac57854113aff1fff6855e2632e1e47bd145865a142c9ca2000b2595fd4edc7a4b4cced9dd87a596a9e245c25fc87a91d676fa0b02a237f895df9dbf2eb099a60fadc4b8829bbf7aaf94d1fdd10dc560244f0d6f5394318497eeac7cceef0bfd8316914f766396d9a5a7cf907866f85ac6e188133614490e1031dbb8abb003b2fe2995a28fac84d07dde5987a981101087606d6b4d4fc1bf7b3cf56f667ffdfc28adfefe6dfce01579859b662a189306cb048bb4b8d66fa9861e83fb28c325b89abd6838e71e5ebeead3e014f40b48a36f1d468a4a24954f571f4972afdce0d6f9dfea1cb500b6212bbac96e7a3193691eb0823a48e6f49b63eb4b571dc1b60654b6a882d84ec4a10b5faff8c0e71bf1548578a8bb4b772a9dbd1a76792e4186ccaf692a5cfeed5414be448da61b1abed7d58acf60c60022d6f87f25b291c226bd22c9445d15e2dabcdebc6fc91d780493865f4dfe420932d9a106e81f254d97b91d00efba45517edea7c8dbf369a32c9d04a5d141d3427c68b19f189af86b3e2fa8ff622a14947d4a5c4dcd12d3e12c714b32075dd9a9c35e8edd715901559efabebda589fd123d0a7ad33bb67f353bd01c4ef51b26a187986edf0ad892b4c71b2ceace37f103dfa8e933bc422a2799dce9b7ff3de92b578e065b79a8e7d4c028002f5b667886bb783bef181f4040c5b03050f9ce2b9cda0787ce21675222dfe20c40640a37058910069a0cc037ce13a2bada74027901a186b5f194792105708877eecf678aba0436c2dc304e8fc040996e488f764f3d0f52056edc69b5a6e901bb0dcc75acb8acc9f22249961cc5df3d10992a32d724699120a264cddf1450504feb09d82b0181e0148f7ea9ba61e99bcaadef0912e1c545ba9b97a93c9cf5a8c29d3ef2a2608a32684b30ee7d43e6006e81c37b636616e736a019e26079d3025b1c5a3997fd9021634627964a01786891218711daf4812cda28892fd4803dc5ab334f18355cae65eb68924ea9fae67b74ade42b96ebd43010dbd0536f7224fff388433de015721b73c60d4dfbe1101100efe6e69965fcbc8eb442a233654b94f79ac0dd967612fafff60141e1fb714a3e88147072c2b44ac434421eb5295a9ea7752abfd6dfe4e10760f0f1e6e486172d8d4b092e043d085c800a58f5c6882e37099f21565a04ff5c12ad4d716b30164d8951f6cfa56c93388fad772ac2fcbb80276a235fb4369f01c77266f2286b61510eebeccf4a610f995c850b2ca952c27875801b692f8c1ebb61758c44f97ca4628837ab1f6807b57ba56c1b2e39e1a002dc724f06a3fb1510f18b37b0b48dfc21d453ec3a576fcd3302ce89f313ff2aa895f0103e11b3c01291c112a4d9b5f67b48767dbbceb8e1a0393dc8fa7b0b7304a02e30612cee891cad631778726124860518fae5a1b162aac95a6a3aca66e1dfaded70547e4d934bb01034038a23f63e2695f554cda78d42808c750ea5dd3c7c34e74fefaa93a91ca66a472f2c1f8a1de3c6e876fb7721105685639cf82ee003704637125e9177cfd964acec7bc1474ecbb0283e317a03696bcff64e4bf6e58e3893c7fe4d41886690b29c2d6f32ce57ca25559c3739e14af58af1d96f581e469f146d727ed4ff89425f4be0f5384ccfd5941f6c859d6d532126dcf4529564be166d880b4d5b5c617173778197afc8d3dddfec020c17373d494a5461676c7b8c99a3eef2f3f52c2d304160696c7a7e8384919a9da1a7a9ddff071016172229405d707cadbedbdfec000000000000000000000010233645""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -d7910e2ff97acc1d1ab59e023ffe199ab92906dfd6ab2e463731ae484d0393edabdcd6ede796a718c4421fb97c22ed9634ee00dd4b97beb6045c3239c48027aa536f568fe384526ca7595031d0a9f254a7059f5f9654d6bb94535445cac6b0d0a55e26160f6d8dd8bef00d1bfed6c333946e5a23ca8ffdabde68ffa4ae1792cd8debce255f99a305d4cb77145f929d4fda712b0f595486ab1b2efc45818923fb11c1d96faff901f631dfa41a112e042b57f5ee2df7a8924888a22de6000d749babc1662c29901acf7289c893694bc3b09d4148438f8bb532faac79f335287c54413924682b3ab01c01082187530562ead6ac24b7a2a1e91f1f3ebcdfcfb233b22a2f250d3aa97240ca78e21be8e8709807b2c7ff115e4e1f5cd5a899f3466dbad9bd1ed59d305f5cd4d84e4904cc9f28d9930e799d745c3e6089804182e0c18d6a3db171812f8ab1ccb08db164f43893477f6c3b056dbb043b9b3e4e6164688436d6a9384d6aa09ec8005db3e5e490c2b8a8445d8b85b9afa01cf9985c17316341b8f37d2a35aa5239a4fb41a4b1564f7b0ab44f01915e1db94ae448f20f295fc3c3aa5fec745f434d1b9990701fa54f2a18395b15602952b18a10a1aba1e02c53dd9ec4e736e9c3289452f0c179c15ab49ad63c87bc1d74a1ac5405bfa70e21bca11904991bb37cc3e5d4c6efa43f6e697cb761a85e3c0ee987d39e2250a5c09428ee71957575a468dff29301ce72c06c5893eeed5d3128e8dad4f880fb0ec59ff3df2b0a8321b8a3015cb55b52c38ce16a8f49353ef4731c38ed0e747ddd63348e89763b91bc6b4e37616978777a5f57f021868e0c2a75dbefa8eafcffb53fb9732d3439c2234a913cd54ca5d973ac9f07086b45c62ab7ca99133932f638226e31e6aa59f458a45ea8f240e95546b069329c2095d9c9b182094adfc99a1f800cf3894c9a1e034bd00a635c5847d633b6e4d99b7ebeef00b18ea44a90809676feede9dd62ad8585cdf4f8ca5e9c5c236d88c9d19a9c5bef612bb815b4c10b782b40cfc59768138b3336ca4e5a9de60d20280212e17f674d524a51a5018dbc2991599b6547661314c1f38b86b6eef5f1de03a86d95bc919e6becfe9d2c0d646eaaaf173938b7698f4cffc9cf33c189f6174feb11073b4314ed0cf5154c5813c353c06f4f18fb36173f7fb543510168bdc96a47f0c088b9de3d43e63f13e4be4d8e351bb3e27da62c37df0c5d461da8d30b1350d7615f591205d3a0308427498da258658364408e1e59849058a1708f7683a07b8f6daec05142ed4c5ed5b9f59cf6fdd74138702a8d799ce3331b996770873afcc15de2a546bac34f866483b418207ba6e5f1ccf126cbc0456def3c1cbd2b5ebbeecb61d37c8ab2cd413fe3e42cebf8b0bd903426a682977a7d81f117cfbe82a75381af76a58253dadb8e1f2d3e2fc20f6b2b3bd106950ef08f8cfb140900cc29d00265797ac8dd7727e354c8caedbd2f305139127b3d27694c53243a25ddcd67c2ca83f9753acb061c1a0ac52295c28732dd1c4437b6b4fe3480b6b8e3b15e2bca16a7a51492105256f1504718a1954492f6e340177a71989bf5b77f24e608674b550287aa8200a96469a8fae17147d802e6efccaeae8195d2cb5b88ed045359df4820326e5238e376d42f69600b9a7ab03fa9da7f8e32eac544c51aabf8524a108900b8ed928d36742c3ea7824bc2f8f25ed52da46852b728d36c017462b337f4a21ee33d7ba0e43fdef3aed3bd07ccc81f36c62dc3495c22134eabdcd3ffc75ad8ebd59746497eb32ebbb964f50112ee4cf76dca1f467585d372dcb37132770291dfece7be819cb092ea229e"""), - TestUtils.hexDecode(""" -3F1B179FA452CFFC1F4776B275BC9DC61A4448989A5C74AA4F6A42748E49DF12AA62C5DA238BAB9F4309D563EAFD739B54E8957C0E91DB05F63B2A50F11205F5AB60B0E857F1AEAFC0562A76626AE579BA3387943E8B735A4B1CCBD23A6CF56D7F38CDCF772ECFDB7CD40781EC2622C10D65BCE780852D7930281726CC2B83C8D8179D842CF3DE761B071A6B04A383624398FEBE34CD841CBDF9C256A5EAE3973F0C256F89665A0B23F0B505A2EA73F37EBC11AFC2C3D4FD8626EB86FF0267D00DBC567796011E5548C08208CB0B43A880C1590CBBF0549683BC71A8BBA2CCA5F98011E592F3B5D7C8CCA0165A58BAF8CEA629CBA860511EA2E86B4CD9E721E8D7DC608504114EA98D016C0C0EF67EEF084B8FDD8BA4825A0615F7E09C42D935D9AF0DD847C2435D84B4702ABA573499C9088EB21CFB97E5B5A847476FD25EFE2C2763429048F797FDACD8238937024E5D66B3FB40055C3DF19E213E5941095CD8FA62BCA591007D03CFB879388983D6E7A189782F36F88EE409D490C5FA66B62510AD0D0EE9EFE6DFE23139944046C62EE639C0F82E6D850770A69577DF6034084DB97E4FB2BD206281A79CBBFFFF8A9E4B70252F6F03DE8FFDBFCB0A5267877FED3893CBE5119F0C6930FC0DFD82C63CB1E7DE66DF2141E184646151CA8A927DB49A3EC63B3B862AD60551B0E562F35E109594E4E43B192BFECF066B3C7612BAE0E170F0E1D7D246CCC3A2F94D3FB08BCF9DC7DC44735E258B1F9D0D8152EE79FF9EF095EEC3FCD872D9584361A44B9BDC88BE2AEF1158D1765EB4DEAF441F2407039E98DB8D148DC8B7EE9C44D5833FFE4C52A077F57D9E36CB220251C58F61759D18E4E449E72F29351F6CB08F9D996005A33EA695C21FE883E1C3BC3DC3E8239F2BE16FE445A18AF83639156521188EDF3F15ADB300A17F88C829EB72275F6F35D2D1A72B79A01A50F1A63741A8B1ACCC35E49D331DF670D30DE8855FF27C9F6D7BBD16CDE4C4C4DD48CAA971758D714E89DDEEC7CCEBF2E89F8CF03D7E631B9A18ACCF19FF35AA24AB6A1E10DF105FFE2603C30E16B7194AD615038FE96F4767DB8882D48C97514CEC057EE636C9FEA31BDAADC5CAF6239A805BB05081962A2A5054D9DDB47AD9D3C98D053A5199A687668425139998BCB466364F656B1AD9F13FCF7FDC50652841EE475D86AB89D0CFC01C6B5B876AF9D0312A43DCBBC71B2714B0C3226967A3D1E0AD7E9368EDDEA9120B2C8641EEA203F2E943F43708EE6CDBC6748A33E3DBEDA2AC492A6DEBB9751E7AE4AA33F6ED893AF7054454467E29D7EB7F2163FD24F7B5607C2E77DDFAF72E983AB532C6585AE8D78757DA904D1FDBC10768E3E70D582F17708B51D561C24EE0D5A26559EADF5463097155540F26EBCE03D89F49D7033AA00E1DA5ACBDF148DDABEAB739EDDF99A6B2BBEB48F83E3516380FC7AA9FFACA8DDB53388485061EF5B94E92443C24DDCA823E44A29116F346A22BB3DCE7022C3E2EF35ECAA91CE5F65D7C5EEC85D741ECEBAEACCB39F881391EE2A06BFD7B72173B171B7D11C8792F0A7D9A125011294296B157591A675649716F92234BF074F78EAEFDAE1AD79E4208C6338F42F2A9B105EC5C717301C638C63555AF0A81F63D0CDD04F9C22E2FF223CA5AE1A01C7FC61E9DA4412E80D493A7C0DD49CAC10C62A7D3ABC1B9C74EAA2D8AF248946EF8A37F1F7017E49D11B89EBEC111D85D7C1512EF4F99BFFEE68FB588DF3F39735169D1B5A647D71F52F76C6BC09F5703320DC92BBBE6D7CA592566483636957D235F5D18150B6A4641CED6276319244CD8EBBF74BC5DD3AF82E6C1118D19ED291ECF84E4EC2FEFF28286898E9659B01A37F4612460B34DA8444A4805FDEDCCCA5D6D8013335B4139101F28090517FACAEBBEFE59E44A969FE3B8402D690012AB908EA590249BD9354D456EF65331608478B2050F985C5903FDA5AF0D918E7F7E167C3A669B727DF0CE96B63D4D944493C5D2BCE97F2827CAF54103A18CA8CC0483BC8B98C42657349B8438C0274E4401463CB55E93023BA114FF8CF3A718740756DD8C92958BD07A304FECBACA3CCA8135AAB901AF23E1104E202395A08784873E03FCF2D07AAB003E6581741389C238942D7A2B9FB30B53CF5D0C408C0EDFB1C4FF448D745FAFB0D659B4BB76B16D5B61B0A38039488682907151802A815AF220F82680E523E838ADB47425369CC421DD36C2E60100A9EA7F29B05D985D644A7FEA573BD24B922396A481E33306AC41CEE9DD8ECCD9DD7833F8CC77477EDC2E97A72CE2DD930BBBC58FBFDE78DDE34CA1F8DC758CFCF2ABCD35CEDE0657B35583F9C016524D3AAA5E698BBF85AAAD01D7D3CFFAD4602858BD7E2F173D6A24504E448926DEBA1F70F3B0D5B454B02AFC4D0C482BA8019A0C209ED071BD2D5B341EE06FAFA7FB0D1FFE77FC6F6C49F78EEFEC44999E4330BDF33021EBD91DE8EF2042FE4C3F19E992A5E66FD9BF8E3D428AAA8FA51C7C761C2CAEC8908DB3066D50BBFDA98B82387E92611514605D6CBCC0AF9FE08B39AA1DEC89CE77987BF3BBFBCF362B4AFDF12A8A1ADEC69962A6FB26610C816F023D87E648A77DACC3997127AF770658921DCD300EE2C8C0916593067B3B31ED1B6B73D68EBE68CB22386DE39E57FFF6AD766193F99CDA751316A5B0729FE5307C107FAF6DB4CEF4B1C6CDE957DCD6361606A6606BAEFD9A1AE08A5DB21991F022C4BF758D16FD53D6CD41F637F5569D7357CA048F07F53C850CC56A07A4C2F3BD04DEAE79498EE10B366861EA82A7E04B9202750D4FF4017239BF1BF7088A3F2E2C79DED5A12F75CDD754840868754428BD7392E4F01F36E3B450A9BE5BB95FBA71C960C7D09DBF24E6662C86D8B5C3E37D76B16845B0F88C40AE7360545B3304DA5CBD2B58C29F6EDBD794E9AC779227B0FD198EBE3A172FF4B8896F0C9BFB7A4FD9FE6ADC73E097046FA25CDFEC45CA1E7FFC4FD582DDD8C79A9F3959A4DD7E3473D6F242B0A6AD4DEF109C12DEC994F2E313EA1930ED25CB401B82212E86150BB53BA88138AE3269157FC2A7A919E21CC068E0B9E934701B572AF0E20FC2CDB2B7452CC1E5545AC4CDD34EA0097CF531FD92E3FC38CC50E1FC8ED59272FF3D631FCC239E4AE0AFA46419863A166DAA2CBC63E24C26ED7EDAE476A194F8BFDD540D640DB3A8B294E0DF0AEAB7A735589E23CE524F534AC82D80CC51DFC08EAE4FD02E6F6E0BCDFA0FB23697EE1AFFA735566223A70EAD827DD31881A3C2471677F905B64E6AAE00467561FDD6C79B45016F1326D705A854877DD91D0B147071B00C5F8A600116487D39284F6334FF56F124951333F723D68465B765B32B396FC4C432D51E8C6A9782461EFADC2CB93EE38D4945833435E2E27E17CA98998F9B33057B1C73E2E43B6A184868DA05559B3050FF42C76D7440E1A5B803C8D4B0CBAFF9FF31C7E98FE2D011B3F87416889A81DF9F48643E943336430602C5B44C1D11BC7F62A0D67BCF9964815CA0AB83E7A87DB714F2C1872E5B9F0843B82846516E54A3F7FE311839F4910AEC6CF0D23F86BF2B0B05BB71B5B47E93B80F7060A350EE4D73EA09A6D489BDD064763CACEF5818B319CC973FBBC78E01A505A2F6C4F6812819E02A573AD8F7A345763943B623995B0634562479072D9E42437FCB2D02479DBAF2D088B31EE870F11047E965D04524D0CFF90B943B1BE969DE752249E8B48C609F14FC48692BFF40EA6095F1967DB766C8B4E18FA73DCFEF18F2DE1D295B51A63880E288ACED85B188B3D10A0B025BBD934BA43A5AC5E1829DA836EFDC88F4BC6BA0F4F23A4AB16DEF3B5488BF6C974EE1BBA51D17BD472C731DD35D5B74EDDD3C9177A3503D783968BCF8A1F2549F70069164C965304DE2434530B3841A2AE7DD47DC5FDD9DE046840B4D65A08A71A3D15778865CCA2418F154403183FD44B622982C64F771C87E18C09489493E378476B3B1C8D14C8009ABD3D1A51CF806189496A4D70FE857822049D3DCD4CFECC2F95D2A8A16D94DC6703B4C4EF3E8C7EB9D6859350131E1A03EC8A21E13F045F822C48EE3E3A481EECCA508F189954AC267E6CD19C80F8688410E2E97C71A6C792DD6E33EAB2FD16B82214588B923AF6C6069387F6A72CE06033913B50F0310112DC2143802AA2CA066388C96158AC154C33E9BD72C993B410FE5E9D7CF37A30EB85A127A7773ABFB416419A5B4DDECEC10E2EDB312C86C3F3C8BACADA66D057FDD40740176D137B1F1ADA098D978CDBB938F45D4B7814F2C5B894CAE249CA8E1FDF31E81997F7C55B7A43461F5C7C9893AD0494F4F0272FBC20D80F327EE55250F9560A301078BDCDE94D72A7D113ADC7C739D7AC2B8775D961F89245C5AEA8ECEB1732FA345FCD84A0C07C65F091B4B32DC4E117D24D782C404E8FDDFD6E9E65B3633985D6DB8CA841B9F9A3B3C617F1D69FB454045C5024AD09C5C1080F3EAA64202C08838B42E218F56422722536160F97ED3C08F285EF7BCD1119BDA59DB5EC6BC8E9DC1789B3CBCD469A4BCBE1CE237366A5B51B062D0A08201D4F0EAF6F8FBFFE53F35999763DA2470F2F9FE79BDA60285D052D65DABFBC43659DC76602DC662A3357BC3E4BD07BC32AE5B5E94D7DBDE4B5117BD5A9E3461021A569E200CD3CC518ED6559BF2539D8DAD74920DFEDE8DF8FD8333FA17F0798A17B5385A9569A640685D7365D3DBCE8411D44B17BF79B852B1348AB31335AE013B2877C1D8AF62F88C5186B7313F2C8736472FC5F2B4B38F761009F7623292EF14A4A4006305CC419A3ECC73082F63BB2CECE6A624C2A6DF29DBC6A4F0FD3658C58EE694FA58741DED54889994DC6A3DB4FAF5998B577EFA399E58D822B99623D76050736C17B5218671FDA3BCDF7E81B3E85D87200DB9150253ACB07AFA8FEAF74578125E1E26128116A7446C804DE54FD2D2B1A48E684F73AE91932A37372DB66A230AC4CD54869A0115895D2CC494E6D6E8B12845551B4F3DE0B3A4C114979F0471311434BB3784FAF7F9A9B88D536235543ECED732289B383E8005D98192FBBF41EA8026CA3A14B6895A6EF0548EBEE58C25530F56E0EFF157DF6ED0ED0D5565E9FD474B38EF5BA74D24B82219F317AD51F3E7D6F8E4BD8836B91525E162DB417C87E36B3C0FD874FB4BF4136926AA6D045033C94FD1EDCD69835A116357F341372148C4601CFD84BC36A8E5B2260B90CA797CD5A41362C44B4488399394AAA431A63A74B774E68025D7DCB1963911F2BDEEA60DFB24E87196FF38479D235C98E83F1FC419C87F708677F98C84F9C4848B255DEF2D92E3506A533D36E56DF81F6461AB5BBE9D171ADDD39FDE7552C5D4351DB59543C0FA939ADD6130E25D4326566FDF49CDFAA240BBA0B027257D2ECB83209329944E8F44AB785560DED2BA8EFBC55CA31E48F4C94749E4D205A50BEF3E3F039DEB3EECB213FE92C1C3E98A9F72B6CC316D6C0B87BE7F688000A2433E3A184A68722D44C7F6C90F2AD0B248AFC9E57448E3450888A875CB3006E27C232963740B985484E7FEB07775F4B4FD89AF6F627CC56CA1AF23E3BDF61443786D3F04DECD3CF71E2C6139B584F52B6B656CE0737F50BB270830B102B781E621B3356CA16019696A23EEB238ED74D160269A3EDD35F7ADD9E065F836A61A0CDF99272956555106A349166B2C299B8D0066581DC3608048DD8BC2F267BDB2808E1ADCD37A7538B9435E9E5D7ED4389BD2CCB6E926A927BC6DA19E8E0E946442A6943F65C56E5AB7507FC6EA1DEDEA7C1AD087CC005914CE80A241D42C88380A49BC4B6850536C5A99B6423B77A75FAF76CB17479EADFEF1FC90B832C8F36D92BA3E927C9D60473117267AFE4B115E39D50AC7991BF248DB38E8C99784848013B48D4CD6E034B93E643239E78936DAC6283DB748062220071473B0579FAC64510D033525D786778C53CEBC3BF95C4FE9406943E9D68E17EAB3245C57C00D0C206E3343D8201A2F6C278DD61D0CD42B71CB7064ACCDD38551DC554007F29E1929EBC81025CD1A5AA41510BC5CDFF340F42C4FF6DA37F8E97F5911F37ABF457DE3EAB6114DC858C0C14B9BA5B652DF63D0CFFF4D6F8103E0FD15D87D8EDCA53FBBC70E3B42C410F379BF77DD17F6FF57D7A0D01FFE0044F226F8D65DBCD1803928B29CB6AAB703A0EFFE4EB47329D9D373954F0F15CEF2577EB8F34665FFF2C774EB07F0CA72ED27AFE6EDF158C3AA193F3B5CAF99F52430A3662997DEB386DCF0A6781E42180ECF44E9043AFE95BDA84FD1F9EBDCE26EEC0A4A08D8423111B320EB87156BFAEB3827389108E12E7AAB3F6CC8EF67A7C877BCE3192E503608D6F1E5697941FC1418C16093A55A2ACF2378590F4B0702998A65C8127F13AC98BADEEB32B152F3054EB7D0F200322E40CE632CDAE8F0E6C22497BB6D464ACBE9B461C5D39AF9334F5342FF31C9273146D20F5D4BFC61F980B1862BE4A147474DE89A1A3278004F2CAE293CE2709748507C5DB48D98B484CE933DD3E925E1788F2470C91177ADA3869DF6FF81308DBE846F50C51AD66CBEB2AC91DF1C86EC22ADAA6C702F1CB7A141778BF957663060725A5AD6478E22FC959FE5C918EF1A11964E66B1910018DF4698543CD3015E9876AACE37988370135BFD7047FBFD3996B45EFAB6FFA70A4191F259B8A27EFA05E7E1C75285CF70910465589B41A9D29F51F7BBCE06457A3DFC540608157479B499B2F0CD9D8A8D6F2C01FC79E5079597FB6E2D1C3394B8D8AF65DD133F9D9300DF3DA3D740CD0E7E13EF62BE1D29A3DA6745A5A87558F23D89319BAB09A15F8FC01AA388E1FDDCA117A27426D142094A11E6B49E2C541A82C685D41D6E2520881534012774B4C01CE3D2FD8FDAB8C25E4F0AD1292974C4C141173CA219C07314314FDF94A05955E210DE13F0165C990227EEDDE23A52D7F4C8A181C996D0FAF6C313EB74BBEA4C2CEC0B7B01698C63C2E1D37313B637271DC49A7EED8542EE8BDF7C7D791F7BD59A029419616F9C8F478F060B855CDA73418D0AF090844FC0066DEA9DF8D4F3C9ED58CFED2A78B427B42B033C46485B767D75526DE8682D6AF0BE91169650BA4ACC4D54E0D357E993FAF358BEEE3F7F988381EDB31FBF174239A345130BAE1B0DEAF27BC5E1DFF86B29712CFFAB670D35D19DC5B25DA43D481336C0CCC2120427F30326FC74503548344B585C082A78F96F072510D50E1110EEF01617282CB681CD352A23607C3CF7AD9AC06FB52B38294DE8F87894D25C1D278678B048E3E3F4BA0D884154C5E16780BAE2322C389667A15EFB0B21718F56767EE942E4BCB190CDECA74C92DA8848F41AEA2328D29B10C95C6DFA74B0E162591B1BDC0ED6826ADD0B04C7495FC30E586FBC03D4E871915AF71866278F9CD1B4F1AC56E8E1B7B11DBF0C9A64F608E1C3958910829654057103BEC687A02AE9A568BE514187A3E27F3F9928EEE29519BDA0065179423A7242EDDD8CC337F0B7E7FB7CF90FC682C9E60253BD0997F34F9081FD785712E52262CD17C3508AE4D2FDA3BFE232269ABB185E635E659D405AB12E17A80AEE5BA7DDAF1FAA819A284A60B85B49F1A57DA72A0866B2B9C2D28178995E79D4458B58EDB187B0CDC5C37F111D20371FB8F410A7EBED95474859645FED6F451A396781EF7A02E6B52593189EADFB1226316FE8DF79B23CC67BD2EF973CD561DD612D0C3047698EA0D3895A28B4111938F0A0354E4DA7484697C85908A3BA3E80BCCCAFC73303C767BD3587C1F9D48FD4DB93517A561DAA10F53F330ED14CD65B4A54FC43E5F5CB421B8B6CF7B83D86CBD72A55791588D4B81094BDFE45E3F32A2C3FFE809F66FF310D66032AD6BAA5B33E79F1C476029A49D49CAAE427D8A81EB642B15EF0C544C9EECB7CAFD2A854BA79E4D7EE01A96CDE9EEF45E430EEFD8A16D5D22B751F981667F36DE2E139391980DAD22462BFF4896D277D89DCACBD5CAE5EE90BC2D5954C083AADF632D9051B782190ED4AABE8FFE195000A6BA05115EAA0BCE755B23B10C81DCF4BBED61E6D31E9292DC1A7FD6B453EBEFDE55D6AD8866CCD50473705A24F519548172D3D9F92E668D679D782B7F1041E5A558A625D65E679FC75B15499BFA304435FEE6F6498138848BAD0BFFF6942029BD0C5465395F5368692D6B21B2E22A638D6EBFAF3A0EF1F9BDEF8529C6D0BD328CC82BC66DCDB2F5AE20F53B8AF66400D6C2C0A3C6BCE1E8D2B222FC54F1896E58F61816E301365E12866C1BE7C4BBE0DBDA2B504F0628A4DF1EC7942BC58C0A4CED0046D73FEAF2231FB9FF61C0F7AA564EC1E10BD65B693CFF56DDF3596DDC85CDECDF7F123F9DCB27269A7F65A435ECCAFD89A211C829BC7F5916DDA61959AA296505F6D46543D863F2D3F007D8960634841CB317F5EAC3D3A3E4561801CDFB269257FBAA6A60E7A0A1980C9BFD6053BF2EEF7414704C7160A051355CF48A0C0F6FFD683C453513F8212364775B7424D9315A920DCD5B140A8440EF7E5908D4061F580022399509C0ED416F945705A19FDF8E65C8802B67701FA1D15F06013990C7BB8D0D0404679713222924DB33BC659FE58F82A99BB1AC551426A13C2CF316664AC8037B41755F110F6441C7BC9446430D7BF917AFDB8FBEF84E895388A68763E0E16F89FF630BDE9732852B70A4A3AD8A29D2A4670757AA4202DE5D53E653848FB26C6031D07CD010501F0785D1B1D69BED49DC3B07265D51A15A7C432C3EA63A0B0D228B4F8AD4060DBB8D54B94BAC7F2179829C8D9F9CE4F7BFCCB472EDCBED73B0D18E3108156FE659CAA40B45016E0EFF20F81C29EADC8B638364FACA6FC85F98A9BAA9BB7E5261AEC6786C18487B14B77ED2B62B762D6B8B39AF5A870EACD236CC53C016158DD1E71382475657C512EDEC0977320F1BEC79D0CF39403975210DCEC3ED5B58F"""), - TestUtils.hexDecode(""" -e870f21e348b630a1326a0334c872302d0a6da460dc9a0bedb6daebc027b22b9b332c967a2f5991252bccc646e484b83d4fbbaf2887629032de5b3e1b86002cb089bbc58e35737f8c07a694b5cfd38ee3976fd25244e6acb2ccaed20d926af4c9c7526475cb89a72a26ee9b2a25c29128d53446f797344d3eff20d91eba8ba9d02f939d38a775911604124896569964fe5f835df7cbf044f2565a32e017caa93a8848f7c4fff257b885374a6af0df150b79488551200332d176955f304d86340a6df8f98cf93dc12909e1693ce62de02192e63b8af668a0fbb2c345bcfb9b5151131b7b4c7d7eeea48666a8219d5f8b0cc430443ea3d531dbaa6360e51a842fbe1e40ec5fc9ecf9bf172570bf8b31399ba8f12f3b83c40205953414caf7324182657e0fbcc2fffff801c52259294f0b23eeb5ef14c34d955b92ae782739a9f9dae5eb03af4bf4e911c7e758cba1a0f1d0ac1c7256e5d5fae242312f18f6747c5b56d907a49151080485999605246550a6ce8e6341bbd1ec122b179b3102a2673c163ed7174089c10b29cf33b9b5fd1ba22dc73a164404804faed60958c6faa6a09b03dd2eed0fa8782212f1da486543ffc688e37bd43621ab857aba0b13c1e0969a482ce92e00d62ebec1870188734135b0419cb3b9f3a9fcdd68b5b4a53169ae0bc4959462b8eed39264c0b0b34e0595c7a719672abedad01638f3ebfe9e4a460cec890339595a9699db82819723ba08c7bc82080f8989d3d8709386ed1c9fc791ae0cf954e3a897a93d8e235eeb69ae131a912736fecdbe1ba34eb03206110fdb1f81e71dceea673fbb98886ee0d94cb4d76e1e94278b8f2501fea2718466802d3d4a068a2ec53029018df3eb088246b767043f843f79b5ae5537924a9b5e5bd46b19bd7dcf7f14d4c9f4dd05b2c941377434cb37d80a899ee97a5d68345cdec8a43cfef1f286c0102c2d8c9b0d07adef966992dc7ce8b9606917e238625707393552ba9c01c4e72f6e3b533a734c0d60e3a2aba08a823a12a45263b61402d8e62da3e5f5a5c12e0cdee0d255551b8af7d500b547699f72b31a91519891850e4109f4ef380757013fd57a0fa0ec0721dbe825d4cce624cdd8b7f7cf64fb31332f374f6c470b9b8a5171f25d005da4e184665430e7ae553caf2ef9eba994f34b04ed6886c1b768f03868522959fdb164e8ee825f08c4a4dce01de6686695b5dfe6102c7463ab54b084c7fb1366a0b292898c0d7499a3a6ae1995bd2139f7d7c84a0f96b497bb2306028389b983f2e02a2fcfd3c5f8a0b4d2e334d4f3a460829efca41806ba82f2e5ef585531a3f1ff67617ec112f613acafb8420a1cf6230468601cd8b0807d975065fd36aefe77111a5a72ee622da403a51194f8467a122e408a0c3998a3a7f18c2f7774915289a1522f5670527e63e6bde7ee0a84750099d949ff87c6dde67de9cb220518ccda5135d3bf58a42b7d96d14dba0ab87e79547888f6e87b4bb9ed754133d16444eca15045ba54026767e93114e8a3a75a1ff65d0f03c667a8222248119fc8994a84fdf73817bc2d61d6b764d86c69d68b7ca3ae85031181204c39085af1c7efd687fb91d00255dcc934d47228c714cbdc66d4b418112ff0ddc030dab0f4edbcb0309419120ac944e15ddedea5cd3a1d62abdfd8729edcf40d43231e378b2c69670c59c30b4218e7b7f2dcc0ded133b585ad673bed77194b98965fd4a04d93db53ce26128e481de6053a14f40b34f60a169e26e99b4b29979c03e4880fe84474f11627620d196369592c0cdd88c3639c1346d3ee265e550d470b8440c5676387769382ad4b57fac799926cba49f042833301834033d668a4f0e95e2bfdbf295ee9732e30a75b1a76d7a4f0c12029514252d98bcc4330fc2a3172bfe72c8f8202a308de53c4587a17c5e149c92ffb88b79d8b07962cdf91f0310d457c7eff09485a01481313b2aebd081c49b47558c252202b4639dce456a4e786db6a91a24a032d47d1cf9d37969d07e2acfce0067a20994310948821510051ea1ff97f0a5e88f0d36825f7a9b71d5c64d42dead04fed5f6b63dd80bc0325bef6d413644c1b5ac212bf9da2edafef2e6b6d99354470e25c5050703e524dfe08af14dd431e609be5809012ff5d0d4dc260f10fff302168b9d73c86ebc71c21d76ed34f08b12a6dc7ea174ba1c2790ad34a7b5d2e55607ab26eea6289fef0886187f43d5b98b7687b227b58692d61e6a8b9bd04a9c3a5df88e03b20c66d618a6d5a979cc0e33ca400f55918a0d2669c19817e9bc0126a406fe4816a24d06e072717435576868303e961abdef730d973768373b4f413b006c137d63fd1a7937c0ddce317078b610a5fcc1a49d83778260c088cff2cd6e35f58263d43edcb81692121d737960b77b17275765218d0b686907ddbcf0f681bd2662451dfe012db5598c061fc03920011a245c3d8fd3a8b0ee6291959a01e811957dfca6351df838ad3cffc5f28926042c1919a446cdd525d0a1b56591ee9574c16f88557d54b97cd4e077289ee304537176c4cf21e63e33203c076b00642665431183c8b6ea4c58b2d11011d1a1fcb3325a1f7cb148e0a0c70484ebfc6a460de38392761da4f101a2274b21dfd8a5b6870cefe3f1ac9fab09c49acd26de288d43326cfa68248fde5a5d0c2adf5ee4f7a87a570374aa40c904bd3052836b275feca785d29a5cf3af7df0ea226d5fa5aa33df234354a84ecfbc2e2a3d2b3cd2630b765dc0d6a7ea00884d7e805cd5b4d7219b7f5452e27b761d2734bc68d6da9b45de8b69007e6a961a73aa42eeeea30700474cbcbafb4304fac39b6dbbdd2f2a9eb5b959ef1a6efd9a41661265c70db1828f66147fdd9a7865dc9f0a605081ef41202c731184d754e499c95c19af4aaa7a018c8f1bcb1bb3ec4357bb7ccdd227f37179eadd63b10c2c10fff271a3765e9470e06fbfd3e5195ef39a52b20041507f3cc360c37608e976bc29797183feb75e61d4653e90c4a82c744b952efa874c92a675191ba7cac12479bbbe83b5a4b2e919b8e318869a9da789be9a8ae806081bee3c6376f54e5f687a2900a9e610094b6d21e4037066f9c85d65fbcfefaea7f2936aa95adf632bb83b1d5630ae48a2b8c3ffa79e44296a60125d14a5ad30e70f97e072da5b00e115313c0f3e572da51faa8741e98bc2741c8c44ab6d4d60fe0a145eec8bb91c742a0a8eb133a688d322a836a2cc4663ebf2eecfb80fdf1f95e83115d10364baa9357e1e133338b01d6ac2fc08910f7ca44ef8cfce5f5d675346417a40010b2c384a58626378819293aeb6c8cdd0141c3c404a738badafb8bec8d5e3f026405b5e6b7e99acd1d5d8e7e9fc01092d3031536062646a6d747879829295a7b8c0dce2eef5fb00000000000000000011202e47""") - ) - }; - - static KeyGenTestCase[] KeyGenTestCases65 = new KeyGenTestCase[] { - new KeyGenTestCase( - TestUtils.hexDecode(""" -796732acba3efdf731bf7c242aeeddf5eba5b131da90e36af23a3bce9c7aa93a""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -60d235ddc4f334bfd91d6b7df1a4fed84c88c2933806f13fe06ef15aed96c9e1""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -c14612e7a22ec88bb5e9dcf865776c37cd5b1c6d1b18798be80b9562ba4752e1""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -ed5bf4a40e4ce8d367598819be8ec4ed706df4d26819f69729c2acf274515c8e""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -78981182b43d78c40b828554c36d70b960a02c66490c15a4caa6a7d5f1e9ce34""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -917a2234587c5969cc1ed10d51b0dcf8b3017143ebf31687930f3e2c610a4850""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -df022c3c86b725c5f2b54196b7d68684b9fde93be78e38beaeef18195321f4e2""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -865f638c38f0852d2d712a708ffbd7d96f0df21071d8bfec74c2302ea4c5adba""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -741a60c9f1715c42a5a9e67b4e69e5f128372002a6c4f54ae5869500171e2541""") - ) - }; - - static SigGenTestCase[] SigGenTestCases65 = new SigGenTestCase[] { - new SigGenTestCase( - TestUtils.hexDecode(""" -36fa0dd4a24ec6fcb09f2302dadf25bb8118be5ada70e1eb7f57b93fa96b1b84a7e94374f9fdb9452e2748558e6f5a787b2dde0cd9d68747ac506baaa454bfb065f1e500ebc68dadb6def405dad689f5d7fa5772765e8576d5edc6babeb42a69374bbc305ba09b1ab4f9820ce3a63bfa30f237af73c551924bea0f171231a1c7138517400832116516721081381534111864540573008215505304258180167218805633031837711834125446757374064802656602288551324300464424570070430775604467700373727218654382113085402384714385137710073132881352767634653213083382164661807507572063084014331381071513408847516228741575401075645618078474251072366778856403233687514470818323256487352405414024741457321505602326684655106051751226763771126438165164374510847344324473582005510013087276273103305247274346862062415125625613058163863147647838223024704832800525016847583411847321486547525343755162746617268246640865568078283725452875420148460064305561603552781415016532336383827535812536128531582855048732745734304562153661720882314551774378733337650373165711441772228701657277386017735824150430521336520550036374316583310125155614734342460731628214452004760130486772345084803242082312015236540131133778828125485315367333404602814074230332231645775734006082655405074336518265056780405423405171643707672231357803711010227186374560188573728767460207070474058460834711808584073145111570274757730536084417433361080031773164730537111576081735558366046746463012324065660876052137008052508762676453141806072122540753112240128218525337055738681721237286528627580731113241785778878812404656335421440725752111111156405682027841442788638820213821775468455868881572107124844588501722102737751182078020774402721847287133760733436178462865784183457884478713270388562378112101074746047443670038258180805476134351522560745400142355780715532180431550238645138105666571424718347700224316576316240153341251132303832382487412204627864764456730060500534645228115033152663747635135007237347168666208148716707533808368153357853523066243657213114358240560560762242824400720503468848503214451133047326042414766776505632362566828364757557628727414157415555332465830353045707545360708480663616301475251681455722668010152887031873716282756337882326408515168141310476348177234206113218677788287661680051776170836537302227562814480456821237427740234145435547342505460352122655426431817848535455552351110307364674577347661170167232588300102408838001733245265836505674067103567726335661342615280304861068871308556030576265263455076841315203671823018446077528186184441157454628072317228030475837445608207541643840387761867421333788142240721568555218641850673185763821882055574358025326482476866447683505537318274722216107033672426311407351407766566165264047443754760608262846715247610402653383732324630537084112247353840248444247113603737643465255683685837537448132411273502758336260275317671716402152714475531868478637736432604357116462758307044401162120081820772432707307585501206687567887071026881271434401570353027344416280106317363532310068331157303265448711314613062006813077352761435726341110116125784437040253348451460505741467381411200515685843585007382002820405613751758033727624146204482040301733053d1bf1b1a1af54c10411e25eb7b0de530b1e7173975fc197ef3a8a750143bb963c1e63e8442eed45f9d9d52c1cad3b07f6ef7b0b63c9ae6bfac1b846a6cd055a7fad31424db4074dfd83659df20fc75650d6300abbf78efcf70e634d1a172707520b52dab4cb90361801bb2eeb5d29c0d9f3c7679c2319fb7cb91213061bd97f48c649ea13ce226fcb0673be270f7169583ace40af1f03a14f4d16f64ddbcc68f6301ee523477248625f3293f5422241eb08ee7718bcc25a12b923b9825779f1f4f240789fd47a484e319d18008d465f5fc08cc504af12f4ce024030e148423e46e3aa78ec7ee132724d003304848675b7251d500380a613c31945cb3355761902b15d5c8a0ff5503af2587c2938f793ce14521347a2cc4be9bc8d723e3878f0e5df30801fb98bd95724eefa5c16ae55fae1d93b1a14d14d2fa3ebfd811078bed68b485f30f05b66507b20fab2b00dbc9d776bae1b3edce5d99057898491629d6d5b5229f76cdd1b3fc466d322743e43ca3b002a3d4542648155a71e274b42ccc9ea50a1199d3e72020c86c8a57d8a1e3798fd27bb505bb23818c9289d847097ba3c83c54874f2abfe416b14942623de55d874317dec351d88d97e163d729a08e7edc1be5c66ab0f4505dd3496b34271da51a8f8595591adc55cc13bbbfa9683948e511f4db8bd3a458150aae844c72bce87dffb11dd52279598f9750091a3af472666648f69348d457e60cd4d46d900a75bbe9bca3417a8eea32eb8fe46d92b6181b093ccfbc7598289641df2bc0bac8064bddfc801bd1cfdcc8e2b37edb726e1724a2c98e3a4c71ba8e389e30e68a92b50ffe7119c8c6948864f24b3a64669bbcf515aedbb4b1702147aa0e9302de84e0a9536d9528b74dee3693c21f3744c56936bdbf7cd8ef7541dc3afbf58cc3c7638762a09cd88a3a8684bd3af99640db653fef63994e6636cbe2eca91ae3943aba282b24c070b55f8a7326db2161ae3c9fc784be0ea8db00aef4eec5a468e700de2db247e98566a690e56cc8607c29df308ac4830dfa98eee2918e387df0e57a62043bbd35517f4b4c3d7fd5890b8c0a013f533c53774949c7003549211e34df5c1a97f393321b8fa8d5689c3a973c01ce454ef59a6a65b4a04a2212044c69aab73d0ecd69d81a0a275f8fa07cd50f53944e416654b47061100e89542bf9bae7224e098f934d90790296432d53e59cf766839ebf6607e712c8d4fb07a620072d4974e398194f099ea90d1a8cb78286bc6b3e9cd996f03be3ce22c3fdc96a0e01004f5df6343c84a910d5b11bd8ac6778f8747c85b59ab5db48d31cf256f316f0c9d851816e2d55661926beea6c7b5547153829a1d2c1b5e8b94d824114f7beb05780b68ef086218f3ffba3f7a471e6dd89ad3b78bc57e9d43b467c7a82fb5402013e8d99ab99fe7a63fca0e4304059d2c7906d72a546adf05294ad33d1ffefb733bf10c5bd5728ee38a645f433a7e8993c6d56f168117e428318fbb591c07cc0d1eafb990dc9a004428f4cda912bb1892ba329bd00bf7db39f2e3deb80d0cf4d3a875f0852e50dd1f6d06e440e69aabb4b0857f1b4496a5361b721b28195dc3b5db38339d7fa2c2b702269f87cf95f65194aa4de80241eca399fe71afe2e92dd57ce509f3a152036b42d058a5f1815d5764054155ff2ea857dfe894b987d9b38e59ea112a35f9618b43a7244d6006527c740563733203b6cf80c3b8aa13ef9863bf88469c1432bdf582ee1934e31d9b88aa8a195b0e491115a30b2d87df76c4c0357d37f2164db21ef1f7e4a70275499d215d2a8e345cfab9bddb5b66dc2ca37f0b5e2ea828a140ca7a4a31f5ff145d6a5be068ef2163bd93913cf837a6729f1b3009bfb3ab1fd45212ad12e2564042d9a7c27b7be2f2607b84acbb98619c5142c6f4aebf56274c1c6991a773f9170704ab0a0e1e214c94fac9fee3f2b4afd09dfbe57bece690b7849b8f7e6ed6c8dc9c031c97deae660382656d5d9fc03549039e02247cd237954380cd6b958b1e4e4f4f2fd06092810835e10ba9f1cf0f9f036445491191fe580c307f17bb9a3c9e50b8aec761a13ce38aa0271d7338a699bf5b85caba825a45e37b405e247c7cf6f0db6ed834d0514272ae00d25c70aa18d26e70e3ef19b1b9cfe002563149b4239732b9a1d3cac31183f7d588aec578b9b816e698de982da0bcfef2c2998ab639938186339119f2fe89f39327f7a77989d7bdc93a12e26e9548bc2fa14cb455baae40d96baf3749c387e1b7c297dd4c179298c5eaf0c5dd02f6febf37fd0ea45a505d9df9d32d21fe34d8bf119cd77fd469ef396180947168daa54a317bafe46e57399ea395fe8ec12a636d7700d882306a2cced9ace3db9ff5a0ce8d422cde201441f7045637b9854b83094a9b61b92202cec7cbf0aed007330e59bea1d641de6b8a0b72e175d11c32333e85ea0534d6b7316a8726b37ca55d0b66456e926d43e9396861f5ac04a6d235537d940cd765b67abce6d600b58b542664ffaf1afba5750182ddf1e965a70298fc01f2ef1b6d80132650762fcc2da1502a97784e84e9cc0096c86de42c51a07d8a20eb1e92a3e545ffca4500e1a23c2bfc220c7e02592d6cabef6652870de97c7e5dae28712ebf9361a74063320c8d90afc4b9d65ae6498010364c561816b249267f829e8eea99223f2a91ee9f30260e11cba163142f736526b97c70d7317ac2241a82befd6823351efe822cd632d1bf26cae52794489bf681420415cc70b201645bc8e4b04bec1f8420a7f13e838c50ea122fcd2f0b39aedb50a42ac99121f99db7ae23a43f00d91545c7badcc8e23e8acd366f71d6a22def8b4d031b6aca1cf59cbc8101650950a3acccecc2dd308479d7303b814ccda9b72c885b9b1f8d41bc381a3f4150f59802d24bf58b2fb6d176f4a6b74b35e4fdccb7e3e4d04430896f0c9170e422c4fa2d5ed57e83489e777ab1083f4835af038271bbc8943ba53a5247083519f21a5781b64f9d29ff49324f302dd71d28d2c02e0be75671082a31a9649512998b8d5ab1f9db850c664c878ba4dc67ea99d715e4b1d5e451d186fb51e1e57b9dade68e92e61782761ba17fcb69e522e9febe22363c617298e76d7b6e575d177e1ed0ae4391b9d5dfa4fe86c3ccf6994cd51473185cbe666919d27aeaa39453018008a5b10bf32ef08993e1ad3e27bdb643dcb9f9021567868c90749d31bfc229531779c90b695b97151011e0340a165295df9a339321ee4bc1e14c459c45435c2cbf0605b975299c6a29974cf6f6236eb5ff6c39b1d497cb030987207e3ad3e681edd3b16a91c9061cd8068436da3b157ddbc1888a6580fdc1d856a2b78f73565e7fe68b2f2e083a93966151149619cd43947c4e849e2ad613e222c394dd7b789b86370a040bd039fc95e246ebf175d45d8c0e07bf895562cfeb44a33c2744b8d52424dd0377aaa1777d0437ad04ba425552ecdb294b610ce744faab39c4e20fdd8b53ffbd66a8af0eaf265d23f9f8a"""), - TestUtils.hexDecode(""" -E3D54DBA675DE7530D3854C8CDBD581C6E392F69CF9793D8C0BBAFEE7334C5878BF13B3BDCF1D993A47A7E8EDD4B6C3EC915A5E8FBF2071F112AAC41F08CCD8CC731143AFC223213212A5BD6B6A4026CFC9F7A41C08CB99F2B375D0E04FBBE00503533DFB869DE43566574B49232566E38B13CAF8C1EC1FA11CCA3DB66887996DFEE090D133B1D394F075F8286CA6CCE13C3977D929DEF5943461BD5A22D4BB5E8FB7EFE016932D02ECF4D7B7705412CA14508B13E61925EEC0B77460C4C089C83D687C8F70D141C75D6DF24FCDB64BB8C2721AAC9CE8C6FC4750C1686A7A70DF34957DCC0CE53C3F0D280CBD056D4F921FDEDB35AFCE5DBB348964AD105EEF5A1B07BD0D586B87ADA7CA7AFA93FB75AC0DE1C749C48BD6F192D6279482D3F9781290B88B095D73E728AFC186BFF0816C1DE78119D701FAD382C65ACC42B04D69412AEB255793839EFB9E5BBF6F69B7FDA27A44C04D3AA2FDC6101E9CEC6F75745F20E077EE23D652B7DE547A0FB0E3A153473BC824AC8A31A2C9493DE64B6D40185B60431B1B34EE32797CC77C45C71F4E04E849BF8DDFCF640B83130208DC2495C0CFC6C031B63B80FB45F47BFE3D25EC5B36C2700300D8223074C156C5D9887DE8C5A97BA36A84D7585CC065F20FE8DCE9E8EB814A1D5B7A3B7A3AB68D93EDBBBBF67BD70A0FC536C81C8D6E8B139C6B3B5EEAA3953464549CB38B78A15CE3D5BB4B798E6B142BC48C70C5BE61F82DB6E2EC03616999073574E6FB35D441B78DCAFF56B8CA8F473EC0543C9C69E93B97F95FCA58DAAED511F4440DB252EC18C90D2F97AD901716AD34EE103EAB0B7982994E21ED1AC4BD62ACE6DFE12C8C2CD092E7A7E37BD4E61B4CD51D980171F8D4253A4E7FCCABA0A513038276325372527621B0A3DFAECCD7CDFE98CB79C0662F5D0234AEEE9302438B778238BCA409D5908768779155D659E92D12CEEF3C2C954C3F1A4C2912E9EE994209B608A604D0CD87F79665A25E774E6DC1D8819B85852D9ADEB174C75D982DCE29FFDD24B7AAF5946A74C14A301AE09F1386AB17ACC341D6DAC040FA6527FCB8E095CD4F1651E47CE02E6ED76C085B2FABE9FF5A510E63E73EE386AC17D5C2C94C2D528B3A9C8902D10C1610BA70BA616C58D037F148E6332107DB9F64C579064F19481669C7888C21F0A3374194FF1A72FB6180DC01D29443BC52C318AB03843357A5A98B3D5CDDE9BC49D3ED29EF73CAF44A7849AC6DF4B2D353B6A562386BD480512108CA0ECD63BB3D3A0695679762F8254116D8049488BE6389FAC08916E6407944B1526BF03551504E40E6A3266D4E773E892EAC4DD5128374BA341EB4097E20A9BBD4E5EA26BE6FC325D9B71C232DCE1974928516EA2519974C82AEA5247627F802C6442B67FBC10E359672EEB9DFF768E9333A2166336FF0004DE5E7BCA55998C860FC1A86B75CBEB3FB5A5A2519D5227A6B5A7E0EE058FEE0CAE2B4AA75099FF098089F0261C443B13911CF3250CAE2F2906CB6454A20D0FFFE8C5AFB1DE7C5BA8CAAE00CD7C2D7219FC83FB158FD6D15EDC2924AB41C9B881566C538F5E38978C3182FBDD0C0C532A77A61E5B8E666B3C540DE976098D2BC68C0CDACF57E9BF1BDE8A7BFB13256BC69F2E386D8F458D303BAB781E537517AD7D0F0378D2F258B013AEA01C97A7E8CD2C3DEB203AA8D59084ACC2B09AD3C97EA613A2FBF297038B4E721665D512DDFE5C13F11DF4BDC0200BF610D57EA7232914752F75A544E01D5AE0DEFBC9E18695824058BDFCDDF4D5884840D2B55D6C2D6EDF475CA75F3EB4D0EDFAE99349684BC9C533EAD591085BD1D6D4E4F9B00A54C97244322D505AB52B2D4E0438C6AC5D2C3983BFB2359FB21174AC02156AE11EF233AF40A695854C84E620754419CF7ED9EA4FDACEFC8879B2EBC7B29CDF9C4CA2921E084486477C1452BC3BAF529DD92748E2B1B684B1103CF4C6EE11999E4121CFC7E2F3F6C7BB9C055F800DC46D78D9D94C3B20BD1B697411FF0B41E38173D2C9FF1CCA77B27384026ED2EE25223B0007D2930D700A20EC9159A66A4BBE0BD84DA52F006D7FAC6D59AB2BDE08FBCEB76A57FFEF59C077F9008A4A231FCC302E4DDAE9F3DAA55707C1EDCDE8042176DC7DC6377BEC58B236990AA6C5876D5A27942FFF7FD74B7DA1D2EC470CF71103A64FD2917AF4C45D4C59C13F58472AF408F9C5F907C7C6AE0F402B404AA40CF8D962EDEF7B7654EC8E36C645855BBECC1337EC18F0EA65933F4D07CEE15294139F479A16133D2BF412B5E46D5B06FB170F0C93DFB8AC3F7478002CA76B67A272A3224C8172CDD8A616A4C52F5FDE946CF5733583C53835EBC90DE3ECE34299D7E5434BF072F08A44905818EE9708815CED10E9043E88B6EF12BE72FC1169FF2F925C38E03B827CDE77740C7C2848AA3B09F555E2712B341E248772EFCF01B99CD5403642448B5243F35A3073A6DA7685AD42FECB05D46FC99F7D6B8EC56F39A7E7B3579FCD587E07C05BB7E1F5D49B9015375E09A9A14F2CDF049AC392139EAA3C2547426B8CBC0C4BA76C55014FCD3940FEA2631A75CD2FF5C22B8A65C9AF2DB1B831C30EDC8EB79B797E76D045EF0B8EFF8D41404F626DE8551FFA445885CA1E3C9BF05B5C39CD40E3B37CE3B58514BC70E2EA94CD694CA88C1F47AACF9B4FF6622C555AAB7C71EA210FAA9C0BF9089DC9C9DFA77C2C4A92F59BD7CD24EF4F8D5088DDBE22DE854F8966C017FB414464ED6B991E289F7E3FEA783831CCFB51E227A6DD4F5EF50963E80847FA6B350A2DCDA3C875D176342ED73BB42B416E58D1612C4D066F1207B6E16A955DCD557A9EA37A9F24CCB20E74AC4D6166ACEBCD7D651450E5D4AEA86DC89528DFEBE07B39A160160FEBBEE5B11122B4177FD04B0A49803E498F1BFFBA898BE3B26320966165E136F7F517FEA35EDF01D36831F9AB478CFF8241E01AD7570C26EA62439013F61D48797B92964903802AAAF356C6AF7645F5F4338C7EAD5AB2898C600123888AF42A2FE06FF03D81320FC08E7589E19887EC86CC1B08204C29E86CCF187B1240B81F7D375F3762CBC10F3BADCAD7431E59A4DC136440AA72628E17D2BCFF916DBC8A66B8A83A3C6400EA0CC57A82DB41BB28CEA9E9CECA1ED826719B9B62B6CED5B52FA518FE47274DC6E22E5F8398D42AB23572CD6623EC307FB7EF61892AE3196C48125605F4F09B9C0F0DBBFB9D9015D325C546CF3B1DC886AB0DEFE2C35CD39E2AFD13AEA74F787B410883EB72DB8CA7D225E6FE8143695BC0FE556C6CDDA493F92ED62A38E8F90CC4C713A4798984007A5CBF68F0CDCC01274C96A15C3C4355ADFC75F7DB0603918ED6CB4E4491A8569FB1A9AF32528F6E26B2303C7987E39015573521E024B2230BF1BB803BF2B358880F2840CC58ACE31E551C8E2A0F8349570741F8E93066C8F17608DE35AEC342415A4BFDD13A9757501F5246ECA49913D0F02EFF35F4B3D40DF97A64B0FD02709C0832C423543A850776ED9C0574C26CDAB8DB371F5F4B731E6F510BC09FCE3DBB58BBAE1074CCAC284D5F8068D2435E053A037E3ABDC957B74339EF0063D367F7556E49D2C7A7DE3616F5E8B703B7585F526E9306C59329A18E76B85303C31E3616831F2AA2B173CD0A43CDE76AE52EFB8CF3C381097D7A7598EC833A75E97AE4DD539C31B3E45216EF9C844008C28D12B12D3C7EA7FB89B3B5D20EF5C7636A8E83D6A9F8F7DF29C9716B7D92313048A7E14B9EDF77FEBA874B9410DCAEC4816D2FB57050696F5D4F0DB47C6183D447C5AFBCB948D09944F4271368542E377DEECD006779F6F7649B946E79BBF2E19AB4E93F142BB24E6D962F6648CD0BF1BE876F6F431E883105C3E86B973E30735A6FE17346ECBEED5D101EF0AAFBBB4C072BADAA2F4D517C272F2BD2190F5F8C87D961041A121D6B319EBC959AB0603096017BF7CBB74DBC74FB866358EF8C1AA5B9A10B2C524E822278627C0AC577AE9383C2A529054528E58D56699540E4931BC65A125EF4B459A7A5FC10E0324ACB641BA33C83A7E100CB00FFE0ABF6281F8942AE5490DCCA37BF464D0B061028E46E025FBD5F6DD6CA1BEBEE282B749FF5B002210916B9CDC4D903A95972FCECB9292A554AEBD821AB4CC50D5EA0A33A699FBF07F2CA520FC44D4A9581182290294A8FCC66DE3FB5B7F5EC5B267D1A0E6F84C27C02253649F5903389A0901797A7EC8B78AF12BF2B1CC22D291347A0F8D6EB2698AFCA7CB4C23EDF250A5B77E51EFFA3C675F1FA951D72467EDAF987D5B63DE4177535974BB2006AA9A8DD9E624108229B1C5735BB039CCE47162EB52DE88703A8BDB8ED409BC01DABADFD31EBB95CAD9026705DBAE5A2D06376320BCFAC17A7DAC957BFEE98480C7A111B5ED300447A21FE62448F62CCFF7DA68689A73A2EC70BD13130337EABF26A00BF86E52077EA00DA46FE7323780CF98B3E998BB30C3998017F4BEA455568FCD567086EC68ABC40113DB474C6C88B1C1C7588E7A8C8D2082D4C70DCB8FC3D8FBAC53CAE95286F13254253861567E4715B03E682E422C111169D96359EE18265C3CADBAB3AE61F03F86D096ADAE9A6C4820EBE3B61015995707695B42B67802FAC2D6FBB2B67801A3E48843EB83288AB52C29C1F112F9233860612BA015D4B7CABC19C6294F8871E2ECF6AF334DF9C8330971277E32CF1488F04B4B285AEEAA83BB81D54B6B8426439804B027822373AB99868EC068735C816521BD75DC19F79D2E2166B1A551C998318FE19F5079BAADB12732528BC8B522438AAD252C57D3899400913CD124D2DBE90A891D95900C0256D9DDBF939BADCF6E37E6783DA2A2BAAD872F6C8C11878ED6D5EE2988135A39F2DAC7CF127100C36D2D4E58B3A9B1D7341120FFCA0EED2E98E020A46F1AECBC809A21EF79E6DBCE76F96B6930107F078A5D4464CFEAC414CA41A5EE4F87CCD8868E7922A14C247885F0DA9E23A7604EDE703C2BE3633AF9CCC32B9E5F51CF51978F10A06F5D77C67927D80AE480E7E5E005401ED95467972ED87029029DA05DFBCF2F0B9D50441E8F15804B0A59D23CFC2E3C0FBFCB10B69AADF0B37C06DBF972E264C6CDE4142C04FFD9FA0AF2451F8BEC3FDE9723306085ECEFB17C591E691F9B4D4F796E293C0CD322F02B96938A5F7D1C8A7FEB94C031DE24E71020FF37E00590AE7CA48CA876AFCA2BE3723EAAD40FD27B90FE6EA039C9F3F6069FDBC70F16626A41678A31E8AD88DE9BCE8A25D43B86EBF80E5E426FE21606E67545FF8E55FA7D9802D65AFBDA79EF40DE924FD0DA7B5C8F6A2CF993FA6D27B2861C629CC9BD2E1E6AF04F88065614F7E24CDD19C88CF2D7D2B93B7408D898525E5141FF71D18DABAC186DCD432F3895A1027C92CF8613C80BD46E4758CA26C8CD92B74EEBC5FA5EDF9C9FEC54FEAC40F0944E3FA165E515A03DB57C205D383C04B2CBFF703939EF321DF8A49BC3F5B1409EA491062B7B9982277825B52C6CC8313BA05ABFFCDFA525445B1CFF773D28536A989D257967B50D7BEC4FDE5F338D2AE81BC8EC592BE93BDA0A7DD089057E675674E8B997B05D049CA3DBD60B7F3FB23BA5F4E5A48ED8535234E5C66C41B157C25B5D9EF5C8C0ED016D6B217F4B60BFD0DA223A5D40C2A403DE8268AD5E6207C54B217C2F009C5DD052266722DC21D4AD8314DE498692E3C77C9F8226A14F27D49E0DA1101E32E5B86BC0F0348A20A360A919EC863695D2EC318A61F654C9A1526AF1538F928DB76F9B14EF598F2551EE85D6E0429192C5F18D339DD5A280DD5B1A8F59EC1F2947996C7E190C87502FDF5004772224BBD1C4DD62A8DA1723EDB41176A9AF04B1F30D09050E73579364360DB4F98034FEC1B43E6E9E0226409E6AF1609FEB862D845994BC20E67010237B74DF1AB59EDF14B1623FDC990B87B929FB7E837B1ED905286A886F59B023F40B07A989EF7A99E974EBAEC49B45FEE1F405D11A641B2B150EBE854F7853F06026CB1287FD8BCEFB15D2AEA623D7C3ADAA00B35A105ABF2D8F9715BE65AFCC1381D29C5EF398F2B76FE1651348BAAC147CFAFF34778242B32A1620E0332EEC7AF5E750DFEC30A899452ADC530DD933A07748DD522AC20AE2B2889FAC3237D23C4472FC8C6B236D4A4D19F67264F54BB9B25318156B30EDF273BBF3598AF5B34BAD41585982F6039F6E488308B47EAEA5D21A91E5838F7D9CCC8F726EB2DB82D022BAF103AB2DD444489B94E8DDBA71E62AB6251DD5D5F69E44F377674A5C2B032150C32664C96C072867BB7A2DC29033E6BCCAEDDEA430E5E155DD0724FCBC0415B2AB6DFE68A2E59403B206BBE7F421FAAC53F66040C5CCCEB19F17BF000AEA7E775211E48AE04AB32B2EA470FF97707D9C073FE72A7B77D49FF8DEA36610C2A83306435861BE01DC4B20DBB8AA6CB780328DCFC2A32D74CABA83929CBC85E406E74EEDB727A2FB5BD9D304AF46225832858B295A17B9E710BD7B0B5D19DBBF4FD021EAF29F4D1B6BD7E78C8A3E3235B5D0BC687BD5B428D2318CF4330EC343566D42D17BE838EEEDF70F1E409C189DB1AE0A205D222C92A1ADD33B8E3B126AF62818A2DBE3E3C001098A986865C6B57D0B2F5579B97B6F101EB56FA839F8789F6774074185A8E0F383E9D8813CA1670D8B7586A3A1C27A3F5A3874C4E743EAE21BC519DCC430E281D2F73C23BAB948938A46FC24DA94647150DB72783AB3FAC01D834A8544F144779A51480643CB1ACCA0BF88D203F865664A5ECE18A88CE31B0D8FEEC585F9531329002D4FFABED01EF42AF52DDF08400C58D07E98046D77C7A142B513DA0EE795DD57EA43F4CE36C8F6D2862044945DC293C8D47D9F207B0344220E3177D6E17A4B39B22CCAE3C53D4E0DC87F70CBE9BF743CEACB8932DF8F84A527C9FB84C6CF5206EC2E43D1FF8E846DA06EBFFFB87BEC09C63E9633713768060ECA6259AAFE7C787F3947D5B94A6B80FF0A7A4785836F9A1396833347C13034040D1C6B1F83782AA6458328160FA04971DE04A16B6C031B2571DD131912CDF2515DD56983ED6EF3BBE5B3989E951BF0B99C5605C38181E96690487E87240059DE21BD220059E5D7E3C832FD4569BB7DF06437197CAC141E8FE5B369B542CBEED2F9025A030C54F0B5D2B1E79011CF2A0A0DB14312E352D07BC03E654AABAA95AFD30F1483B57BB1A74A0CDF8C9FDEBE4B0E156FE86BB1E21D861F8EBE0C4AB2B23E776EC01A281F6DA9BEC4C560668B4EEC71856E6CC41741DF2EBBD4E95B661EC24FE31B1DAABC9373CCBC82F3C13C31E478097259850221928C7AC6BB933A5631C896ACA87FB6F5E3EEF36EF5B9CE59F5676813A1A7E768FC9B8AD4A0A072672BA23CC21B21A95C9BBB1A40FDFEBD2D611B773DFA55F87E9AB1CE51CC42B0FE2FE15DA2D73F656CA56279AA16722ABAED5727519EA258794503F1808E4EBF056530B318B99A74886D05D042DF4D829C425C908B58162EE30A073D4BB7D27275B548E7A90E6D178DD27F67CD955270825FB96300C4645E4CD9C175C1185707D4D365955FCFD245A55D64EFB66308A47FC85592BFB755EB4AA8B78B541274E2C225DAD649C248E7F2792A56BFBEF704551588460B192DAFB9BF6798B7D4CECFA424AEAD675DCA081E60BBED670F9AB2316F5012E2290770D3323403DA5748BE6681565A713873A5386A6F1299F0E1EDB341FFF08325510A7F2FE5EB0302727D7355EE48ED5DF4316FD34833238690B91D47165CD4CC0454DA33B87569D38880AD92A92ABA0F24D99ED4CC977A2B4E37954FBE9B9320101C80A858122793062C7AC26E71BE2608DBD2A97CF4E884FD3255D008700FF3531C045750B2EAF7730BC9A51C675D94179DCFCE9EE63C1473D15B4319AA9EDFD19739CC05C5C3C8AA618FA9096C6648756F8AA74FD18A8CD81A2D248B856902B4D30182BFC2F392450F902973043EA0F5E6C872AD43A2D319F99F095808D83A8B02BD380D6C3F3DD227EAE2B4A4867713853D63CFF405621B1EEEEF00D5BA2FF254CDF97B4226334A9866A2B5BDF1F8E8AFDF1238DA9F48FC388A339F79D648CAA0A0A69D6F16E297663E5F4CF1AA95427E68D71E74C0A2FB6B689224BD9978F7A3A4505334774176FD87097D8AB454CABEE138F2CDFC6EF0F3DB14B09DD02E7FABE9F156654433B75B951AE3C196D670192004DC1924D1950AC597682EAD1C087ACB1461247DFAB3CD42279F9169B69B33435DB9D8994AC04B15D45007F0F98334AC5D783219B376D9ED7553F52CBADF159F69282050A4C843467AE7E4C4A142A61CCC4C48DC3AAC6B8E0A8D618E06C60DC924A943AF9000F896446CB62EF4E47AD6D1FBE2B8984A48ACD7C0519D6E87A33106E9A91C298808BF04E1267349334E6C2AC015A9F704B2DDB56D27A8B00D876AD00F62434095A6F7A5E9CD4B27FE09FF69019AE5F27330792CF9A1C07FBE98D23C4E615332A77DB5B6182D277DDFD7572DA75748DFB3B9315294EABE4B6D0FC3114B2AFF5537A6B05A7AA9ABB4930E17B7FD3D8F81AA2D674DB69AD967C8306FC3E1CA8BF78F446B26D8F2FD1AF6F7FD7E52867BCCC3B4DBD7227EA992DD995D77C4A2BC808C7A3E68FA433675F489BC503DB70115A824669E4B1861CDBD557A1F78F1A4B3582B2553AC23F12A4326EF943C56F847B8C679695614BBB1DDEA9CFB7D799CE42DF8B735FEB9DC119DBCA306DA4FA84A50F79905E5C2AC1F61241D88359EE6F62DC9D3E4A1593F41CC5F3C02241CE5EB62C28A547FCAADF1DD688F3DFBA870D9BED723B02B0B1CDB4C08D093C48977E0621930A668A5CD517A0EFFBE248B4AACF3009BAC0D47F49378F30A3D2C2800CD16B3C9464563DA4A7321082FAE95DE5645FCCBC5569E942B5F860A32F04082723E9E53F2D18099BEC5E23A916354198325FA8DAEAA3F6B7AB6AAD6EF12A03CBDC27B83C818F44"""), - TestUtils.hexDecode(""" -7dfa6f43cf7e66cb9e8830871ea48edb07de9845daf9433d74ba10cded10ae8fb4955732aa5f11581322d945bd5b0c05ca195e5373453435602784c9e386ad0766d81c9c954614533a0ab7407d4eead99582655ed634e9a7db1458e3f91bf0c4ff63adb0b62c4e813c396d8a640d0464aff2abc80dac7a5d0329e31eb34d00c2d90142f47e1dcaa203f730de8723ff5f6e9db3dc53923c1dc413ce54f5049496cb69e1280ba7ecc7cb540a62e441c97743e196a0144db65e3c0022c9a6ec621eb1ef79c93b4b224c4a1df88afe1c4513988a9aa4d6aa2a440a9d2b3946dceb5954b0f5634af19cb9de528dfd8bfe857375a8c903b124fe6b9584fa68f56dde10114aa62aafde3159db334294c06b2774fd660a13e997403f04f5027bda9745e16684edbbdcde4155adfe34e0febff14bb05057ee9188c2f7ec829389e7fb24c24d3ceec6f37e53b592b40fbfde40cec330639e585017f79fc86c68de2d24e49b33b5368fd1c7d027503f12b339aac9a4dfbe711918e9eda6bba049154d4f3aa0519078e9ae18f5a94f31adbcc199a72a7b09de94c7a9ca94a04d016fe4051e5b778d5de31f3fb76fa68a71574fdeafcea5e72b563e99982ffcef751e8422d2750809786b57850b832c34a1ea88176861a4176a6623159d63535b5897ef1621564c1882e2ab954455cfd5eb080f9e979a580fd8ed7b02bd504c6ce24c55c1e582e524b6aaa8ef66c666807aaa994d22df7bd5c1a01b128a408b9dc762f2a5fae6a61da1ff4a2feb7e4389bf3fa4357c61acefdbe386b6e55eb3220eecc005cc0047b45bff02e87f1f55177c78c16f142c27e6e9c3ef81a5c5cc77e70695a7ca57e93da2b5c0b32a8df6a77dccb47f3c9406ac58bcac1ba5aa511e417648c4160979d7cd710d35f4b405e7b3d09d229d011013e7c84ca8d0693696b4028eaec2993755bddee22be25b4ab0c5541d6379a067b9fe755955cf11f7f83399bcf28c331c69e2f9a80431da37b14c7e854232037284e91978ef928fe68021138649d3cbc669126910cd648e39cd91efae120eb275b114d33629bf451416ca9affe96d67ddbdfea590b7babfbb49a8e6fada738b0f2bb907e34a856a835e09a8c9076ee222bbffaa25a30aaa21309449c4cd0a7fcb6110a1c82fa8d4a737bab8d92e4bdde60827442e9f74d135f3834073da3867b5094f4653d88607e8551f0c2951595fde2880f0407b60146b5f83ce3e589ef16368b7e058db6b3e8b98d6d459428635f1fe23fbbae5e96d5afbbded8dc22010c58d11e84edaf7ffb8c6598d15e8d3800cdde92ba519f3773ae13219b7e2b967f360162431f50b0de5c634dce2a361760bf2c656e47f8d10336c0c8a0694c148d43dcadb3f84ba52a2f8a167732f106df835e50af089652c7c806b1f51ed4dcdec2cb5d97b5c06f6c64c2be83ec4c1b228fe5615b7531921a5ab4e2357deff9d75e04586f0d325e0bc6306cc22f59e26dec56a2b0ac627f95be580a8efc9d7c27104a852df113d443664a9fb27c0a7e9181372eab430394ef71bb5327e2ed828b60a7b93a42b054cace4b029a8f4fa8fdbabd0b728971ba99c641ce864b627f9fa17c33a6f50d3df9c97d066546a37ecc518b6eec761351240ed4ac606e498daffcc4cb2ccb061619377d33d791938a32cc3640f45549f625e8c2c284a7fea4fe1a864417183177f9c914348d7a693e2d53a95dff9fbe6b26604ae005bb1244176ddb2eefc07942edc0b0fd336f267006979bd82c4499460185d7ad41301fbf5b17e78491a02b8df328aa35eca2346c1f37ca775d11facf01e26d7473956f28551bae4afa6039faf145ade0da17470beb6857ff7435b7ecfcfe51417282095d7a83316d16bfd0a209bddb52461fbd14a74bfe06183c01c40cd6086c6594921073e6a49580aab6b28c71b960ad575471fc6276b4df624870ed01346e3a6252b8e9ad82b40cc88f5627ea5d8073efa300eec86ea921cde8cec9e172314081eee5f6cc665f2b0f6e5a0e56a9d55d8fd1079ce1b5ee10fd69b1a1e8fce047cf7264edb9c44e51443387f9d2fc54b3ef09055f819fbb065d6f0f09e53b3d5536f1c5a98c1778a5a45755894290e45d27f93fdd72e948fb5a1e4b2b97798eb030933180e8aa5bef5d89770c546320c9e2080eb7a1ee3c03a424891517c3281a0f2a7865a138e7cdb1b417809c3c3f62b12baf9b02f9156ab6c774c03d698a9b52380124d863008bf3875dcb7a8a80191c288fcd856e138783a0fb301e395ade94de2193b7f316c63fafeb388a52bb934409064aa9822f5582f632324e11b6e4bd668c0c3d57267d64311556bf855524191565c02da543f1cbacf62a1d5d9839990ce77590f138e7db0641e51ad911c3c116addea6fad97243e9ee4efa3619e8809d67e8907aa0d63f4d9ed863999212e5edfc8e7c761795792e7d9c1d05af67f10645f76ef119c6ce384e92f1f91003761c9203f2e2e6afb3ed4daa3c24d74b9cec3526159f7f88b6df5354db2e7eb0dc1240cddcdf076b8b8f4567eefb4b27e07aa3a6dd9e17695f58a647002283b2f853e9c5abf16b5c4c1f4cf6dc67e14e2ffac3ea0e98830d8613fa7a149109d054ad4858fca3ee6bcef6bed0ed48a877ee4d0c758cae7394d1fa4d65e6fead01c555ed81e9757641d48ddf8ca28e3a6448e67eb0daf3dfdcbe10a376db16063c1a3c48abf242a5ce4e65ab7d3e535339e5689017337b6051820045bee408764b4578c6d0d7e1e17b9bf537912925cad18cda39c8402e3897ed04ca387dad9cc68d049350c2b9d8440f4195144c5704251e5164cb969f08a4ab01d230dcff7c769a026ae57fdd36abf805d114716a8bae45c099994eef19abaf515a0963633763fd2c42f4fce201ec61da3b5dd9d2d89c62b9dc8dfe0ae91fd52b67822cddc9e4604da09865e3a5f9db7e19f1c13420b07afbd84725095ffaa7f3f301937842ea821ddba3e138a0e2ff251d03830a885b5efa7f38492e376f610d89af18c7878e0e179c587d33c2e17241a570496e9ff8e0e980d8d7eafdea8f6cdb92ce8479f21d0a45855a41f5f20103389d3edcae037113c6777bea02de2fe919c021476b8ba937d1272dbdf038cf74e5bc7c94f25e85a8314ab2c1ebcb0db37daea22c2411c77489425be5a37509fb21dd995badd07c3c0cb55400f3df5253d856068a0c643ab1599a30844664e0c1234663f447a1d6eed317b362ca8574e724c263c29221231e41f980c8a773736572f282b5818220e34ee47ea2266f9291cc5ed376aba26385a5252e44d05a49755b1f7b0856f855070ab9ecb1a9de29a5b3920b3ceda55c0aaaac031f935e563c50c840f9002b49dd06fec768a9a258eec5b6aebb997a9e2fade8a95fb824c9fe7332528e62b23d82f99cb9e13e9a339f1f086a7a60aace5f34d2502a715df1d1ad9ce421ed1802f6acfcc96836e481a9f3963b0f28f5ac8381f83a7447e2cfe35f3f95276d54a8143b458bd195cfd4a2b474923791e8edd3ce383e80c9a87a258734656d7e82cc26aa4f038bff3d13512ca976408466f32fe5202dfef7a8bb8aa0b24d798191d8086b5a3ba1742f2c105439c58ce3288d19aaa535818ebcabf73678f27856da1507aea1df0202b01965042602c582bc9a3642ce2b04d4b0bb4fdf3d82fd3c4f4c99ac960530b04bf5fc3b885b0a5fc6fea3103ec3649f40ee24da9d140ca64f28cf0fe98d57f72fdedd468b27601cb5e34d34beee6151ed6e3c452925fdf6b9601d69ae3c36e9fff6d6a1b6af87b9a09c3f65e121e21d6b5d02e068098dd1394894e472ded09f085396a4a71cac238a878c215e7a955cda7f3742fdd1e2dc4348f9abfc46df4650e82373f08e08dac0a59ca8ffd419ca2886c891e88e41ceb85e10c57a915f14c79f5820ed8dac9a6bde0ad419198efaa1ce3dd2f30bfc82fb37103e7091d75c23ccd5b7d7fdf1ea49aade37b3e7fdfd9892597be68b47c912470b518667c28e7c8ed0fe339114bdacfc4b61ad2268929c0e3d49e77ea2a3a4469b79977e928b4deef31617f8d97d879293318ceb5c16ed2df4f1c0a7259786270836ed39ab184a0390e0d0d084c5313f9cdcfab7490c0f8df7f9fb8d2ba658aaee470524d96d90fb51f509ca6db5b0193f817707b6afe3faf49779c95976d57eb710498d9e7d4e1dbc7026a19d079bd8175ce4f98d07462f1ed85fd34101b213cba0cd73eeaca9133dc380031f6ebdac8f05eb29a4f22ba34e1a6fc29e5aad9fed9a74ad8ebb6463858bd894e390499d715c5140b5cb342effdc7184c53c33624fed2f9aa05e085cb7d68e7e3d425e6a08f91dca36e18c8061453bd980f41d85df2924f3903b1ca62841d4545f8ad8a4949166990499814a3db50a62730c88ab592be1209aeb8d2d5bcb3597d5160ebcc24e8601900010fddaf5842745be0b72359e5b90e6c11bcf5cad521bb23fcf452dadc00d83a9cec6f24184e90a3e35eeb3ec473cb0a9ece0ddb5418734231a399728a09387d82acd1690a66acd28ccde630704ca4e7d232ca5d37eec3925a3874581d181b7391af5d0adaeea556515a2a8e3b164a7b85adbf667992b6bff10356b3c3e085fd3d676d90bcd741577f000000000000000000000000000000000000000000000000000000060c1113191c""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -f91692cbc904c6920af9eff6f57b6134b45bda6ebe9ae873a39c1e0f4330b9bf72955189bbc843cd72a944b95833371e4c06bf3eb2a665b4da4df5b987edcdbd5ab0e7c5823abf0bb6bff471837b8a002bd65bf7fcd76328e6fe6f15e57a8ec933a72cc3ed112ee597fdfac91601e2e58582dc4b609080ba634851b25358d0c9754350281637262521374777556415104864154860206041352465214453553137345236775358075282056885647303768587045030113278731814115881114551057578670817173873534401000711068401828428263081481017277750831465187625833523810016354580868548401441857264083372314878161522270727064333711682546124068264412643840758358838408447627025338300737308371266614001014336245214783358451307745761748303240644786363764736471825520567742255620673034736885603143848540366770518635837224344520418782013854701432613146461232406724061145508623762757104474481846413463435761547477850512744612861336161462154873852416844183351672874258434175215466573313077127617803725473868377265620842720484140613811225841166435350043412651265702675883751576272877822642382142060654556010885518346603814832385350857032673022330504364602345802637766037480027500017672070832862507221411804200675641531481158012220062173320173332478120312762320104164307572211150304777112577368026515022475227221526237672850742604350673830034371436706872072077285850737337730722006562010420468188176586122488432407536587767541380746858122020430172573028068160420648031447532653223555442726570477084433678280835588627680013544120740664444462067616224381176624820425675553845610766215101372521016340175780778380183351722838167847841251851220785205763271604276632836107100703635177680045501506353524230801541453041757868356061560200675564087263218478015205085086217587120816787626038643588882256045332002685650850864406716310262225785367023646170404536861170031214215780548215656682163386848637204727003614771133743560622307402732767066875005724512425272665757480306650470488674004187536675155577445440765742464370661551864815504156136385586564574816703676147564638005517426348048822375856871184345217602738766260417585746271507507570510040056317530803348186642144653053831678540337242413885416064200831201636480323423582817278526413532750432252553652348063287644833408001231444005103050185162038400434420347056323560663011208233834176232267471065573612368558534828568744114127618310560854752054526264330215157680613584083161688058026515337171512715422432583342201257422527403383585446750778640127544781836365130507331711865536268214184662407615508115011054020552746102778440301043766846753320370386223010231318077850584875767675687354456847801617844783652736474218216364370170532852111846533242685183301345366137533712315337353808163275816037073475315320481278357032512385723425657218052577281508084872030258232370206340126045035642787353202504281812581273174383414764882523037835526007680523372518155181435704877226072110817710451470716262037413701434382786533247683254721230801265816050461107728147240545711084436157023770440121161026812170048186872204082147300617864005286020058133765464066235461034572838713356310701101481833843686614643073413362213303431440568171734005681464884814c96a6419af7dd18e6a547708560dea1bb476c511c946ef5f593f69649f9ab3123a5ff302107bb4367f068e2f66ef0cc9a16a69a10c91e003811c76aec82791918fb00f736573bda22f517252c72da1f973386e41509e46131701e690a9717053661d4c1ce3dfac2d14427f63bf6f9c53cc3d946a83ca34e09242abe5fffb63781bd21ab2ce57dd687f3f77e1edfacab5014be6c6d742e7e91792b489e8cdd932ce6777cd412729be11248dbc8c31a6f13e430ad1faf5f0d99c19e5e5bd26827f2d4bbf4b7a5ca2fd4026507b81828d84a56ec69485d011bce465b461262ae6aada92a67745b696371145acb33cac858c4b48039d6fb1ced29e3bf963b4530737eadfc1e7d9ece7d24f442f6e0f2e47576def5008cd01e85128e211fc27aa80c558a0bddae7cdfa6f14a9de7c68ee5d611d9527ef9e3feafac55f11e748e125d2fbcad6373338a579ecb332b99095bbab9b2efb3b4da9fad20b48ddbcae17cc05e530c5f8910cca285a23eab49db9b9a052af08307a634b3b8e38144800b32260e0f33ab2fb0ace0f4325b9f091cf99c80de5cf88d62249b68596c5cee719e34cac3bcb25f3f1872d8c358c2f93639c5bbaab0d41f75ed11cf1b98d373c855cbd254c2b3487dd779ba6f28f8977fe1d470531d5efb392bf3ccaefb1c33f5ca462465d79b32aa2ffd9c98bb455b3b306ca41054435b727fda48fce34b31f81fcae6c07296ef8a4a5acf37ccc14384f0d31d21d31d7131827cd0a16e112c7572e291c67bf1900c647b3c1b5872110b9c411b15f7acea2a7aecb97a671e4308cb77227c92333d2d24a0db6945bbbd13c86cbedf46906cf41878f0c3d1e1b304aa9a3cb36549d6fb1c7559704d76bcab57b2b06d4a52e92e1c3cdfd200423d33722671279f9698f23dc56139258c02cf9f44d5c7d9ffa67b0060911084a464485280428481ce1ce470d96fb8d336b9a4d548140607c37f2d1bd3f4645a96519e50be01d3912471254034be81b9b627a3c8f60c70edd394776a7b9506f7886a1f76472674c5c93221babdb60100a379db220963338221c6f811e47229d1116c1ca211131500ba2dc0973c16153e28180f03721f46e2a58bcd521bff6967612bbd5b70f6039e5849534a3789fb5d80d498f91a7db68ceefb7ec802be752c3c4519968024eaea470e33723376dcd7d1cf0cdf67363b805c65f366d5b1d8e967f86347c16bc3fc70b7222de5b5593f65f9b99d8ad8ac8f5a25630d4202c59a8029f240747d2ab784d3a8d20182e0063b8b8ec64217a05abe4960b265c72a75052dbe5e4bf24dbb5db6e7a0ba448b3c8da5797f15fec696dd82f0a2a9eb867d1a65d95f3220a64226ab0148cd67fd6ffc95063cdf7207e015487dcce5dbbb841de6f2d3cbe3da332ad75d8a7b6982e5cfd28aa7cc64947050dc40ddcde3f77f304a7d5342cc332724e19ebf36d083da2289d4536b47bcdaa31dda127dbd90c41868cc81ac638f116f9cbf5fbfc787a1c1f7835d7efd5933ca85965f419c16f3f4d5a618c6af610055667224119f9f869aa618ab5e2fa10e92cacb53c9b4abdd62dc1bd82e8854fa7469b7f4621245ca3c7f97067d40ace3f7e48a3bd6f1006d89047f3e4ca07848b72ff50d3b1de761e8381274f25af3ac755c3d29c1bccdf810933ea9fac28c596928014f07d654c786e61bddeb97bd654a36cc757700f988d3a27b023c889489bbd1c70ad863aa7a8cdc7adf720940d57f24c52c6c83821bb84589a7fc30b52f954da9d69d9e41b046dd3e8b37b4b6e2376aa0e7f715212dad754bbeb64a0a2a0160584f18646ab4c2b19bf1d3c3c383d7b6efaca49e5101ccaa64667e1bc29af611fc94aff9da7334984431e0e4397a355d1c8f9fe76635492aa891b90531b7ee9f5ebf87cddcda8b060d09cf85eb4e7859b93c7c56af470b908a3b31462ca08bdf66ad9e28a7b3e438d967df3c7c844a6da2d57a61fe85adf971acef4bb824ac9a4a9bbb8206e5ead3d96f539325647114585aefe1752e405805b987650ef7fd2ec8aa0069f5dd64e9a3541d43dfe09c96a83bab1c9ca6799cd4789d082d620b4898212288a7a92792803d204c6b77042634f2daec62bfc7b282cfbc80494fa2bce24493f0795d0ca8bb21d79fd5d1e4a53fd695fb8def7786aab4d8a6e6b5a1c48ba6461134ce550f1ffb0e0fe236284789dd3c10e63a748b6b9966518f641c5ad3346c1a6be1437dd06232111fa2045ba2a7521c6662b9aed1397509e7dd10e3343d9d439843af2f40fd3a9b6ffc8dcbbe2f89e3e718e83043fe84e0847dd9276bb20800ac07a6a0ce94e9c2735cdaa5dfc5e626f25b902ade09a1bab18509d1b0e075286272fd99e469a525523f1ef103b71b9870380324c64f4ecd0e1b40f6c2142c49cac8629941cf68318440ccc15933954ce61e48006b9aaa466b3c69a8cfe8519a21aad7a9c04e6e3571878ac468b72f09ba30446d95cc7ada23d7413061224ce2ed10b9a626e3014710444e13101cb5b2eb3e208ca67a755b7f0bc166b53bfdb7b08476c42e8f8123d295cc07d5a7b74df3fcdc1447ec23a5f1d7ab98a965caa69e466e80826696c1f46e7be9cef62f7d82d448bc5a5fdc6f0b3e355db9230b17ef9950356af47ff1f24813f8fc9b667d375b7897d2a7dc0d84c6c7ebb82e3655f1e84ca5f5472d230ed0e2d1ba71bb99af8092fa7c6d4ea037913cc4b265d29bf9d2a2cf9593ebb6448f6c43501da30dcb7cde661a59c9e45bd694f30d3549814f52f3e01733102f48bbaf0f48a3684b37293126abba486d0dfdf8c075262bfa6d9f095dea8ee9328a5bdc0db76498d6ca91d6314f1e3c9ca11018c551785edd5d90bb6e9659f117f62854fc62a0c707c25a42f5be89aff9daa67f0fa026df50548e8c2086d919da914b21f1f907d146e72a286863cae693f1d2022344e67acd3d70357957dfb3e90af2f829427043b41a3b52b1fc34e0d80ce1a47dd5b12877326437f9628eb25386c51c59d0bde81862035b185dbaf7c574ad4abc0d50e86ec3e23c6f51f9c871f2f55db0c4a6fb9a0756b61f86bc3b2f0c9604bbe4a495abc83bb1a07ce7e9d9d60546b53523328104b66fab69db63cd6ef2f44e405276b45dec335e1762aca37f3e348a4c4a348442453cde7ef103bba64269e0152f6e292fc54bd7a84d015e809def97deefd6f24042d5be6bd1ef4b105abbf567ca98ebc8a2a93d0e1fdb5c1027f639fefdbb34a062d83f6b9155171f0ee7133782b6f742071cd2b727563b7d6114360f9c1d5f208b34ccea4a9b4762192010f698c2f160828ce9fff3aced38db4bb47985cdffd3f089128a789696386f07336728380133767e1955595375caefdb9d3c6f13d427f2a61b6a0ad529791f095f22c77c1937cee13b419ce545a82dd1d7f5a79370a2bff47ad9cf0b8da35586da8333ef7658ae73f284e147f78f98eb0f67fab6f588b446c43204edbb0d01344c50bd496c5223318c7dbad4e24ed7dc51e559488e8df5b071fec03b"""), - TestUtils.hexDecode(""" -DBB70175E063054DDA24BCFCAF671F820D674F1D09CA173D4A1440AAF50F1FC8FADC1810F390286AC101D60507DD285275C6F97C0D2B2CF3C7F50609CEC64EB029C3DAD8B9954807E35D4836BEDF32501D0E7143BF488CD5B4D1A53C980BC70A3794E4392E4560E609B9C49900E1C56D319E1495D085440DFD081D1A7C52C0A8F64917834C64EF32A441C9045689DDD2EC218F58B3BD534F18309E1D780528D3BD1B23DDB3B18FC1F7C85324D45C3E9B25961FA5257EC31927CA35DB25E6FAF7669D60952502680BC7B5D777D77B194D0CC40372FC8F711EB048E01BBD5676CE3F2A9FEEAA4B5F29081C34969C746208E6F2329CB53A22058C0AE0852B7127FC4C74EB3A8300403F60B8AD1F95FD2991CE0C8CE452C2432B6422EFEA8AC0E1B53BC994C606301473D7855EF86687287BF56B450D2762C5E03AF26A987317C4BFB013A6BD791EFD141AB34718A37D1DCFBB63014F7F92C9E2870DE503452E271E9D02768357E3DEF6BAC5A0F0444DEE1FF5AFC79B3562C12696FEA15815B7D9BAA38C66919D137F82FE36B140B960E02966FABA1EE9CBAA04941396D665DD2C6B0559502577541AB0CEB066E066553A2DD407354123DF14F4B1DDE6B8C34E3264161796F48DB5319B3CDDFDFDBF5CE17BCB5924984143839B4EDDDAA8F0568ECCAD253C48D00687F9A07785A67B62D28B86D70E511AE08A525F66FB15AFD112C184785F91E76852DAAA3E78CB96E20249F38979031712440DB723B022E1323818431B897DACC51400DB25635EEE41761089DC47E8EA56DD0DF60B56FC682D000E9D660D0CF38C263B716359F41F3B190D201950E140D67F50287C09D2008664341A829A074F9629DABD88BE69A6058900DE5782CC621A91376E5CA31C66E3C430CD00FAA83BF765A2E6B2FCD20EEEACCB996FB5C4B63235142BD5FFB4390F8CB95BCD5853D0226F931C38FE972FBD0D6E10DC2CF29D1FFD2653CACBAB8B81DBE44A2B8F1C5DBDA7C56252E4B35888DFF7808B3514F4D7E5EAE9B51078E8D2E600EC57200FB48EF946F021CA8209E7DC6443B37D7281C73C6A3B43AA570398E62CD5ED9A34ED23AAFEFDB7DB3141202D940C1411CEFFBCED878C0D325E8CF7FDCC520CA3377BE97855827D2E6F4EC8786EA1374E006539387924161D65782C7B2C262AF9BA8FCFCB5B1477083836129DA973AB8B082324F74BC6320646448DCC8AB56582EC72EB192D3F72255D85FFAC2B5C62F245B73191A9176BA5A9FC0ACD3AD48D37E23EFA0C65F0423AB5CD0EB76BDC035112C7A118ED47C0E67E510A6F7A28F26C3D6A882EAE74BAE6CF1FD969FEEAF6B36C85F62D40CAA26B6CA98120D612598F360CA2628F6FD608F4E1E290B32C90FF71E181D4B72978DFCD189D857DAFC7B2AF8C958EEA6894ED59AD56B9AA6F83092EFECF9EC4091BCC9B8CCA245C30B54B9B8DFF3636BEFD417F46DDD2F6136B983CFAB532FB623FAFC3CC4CE8A91434377F4DCD1607BF04E431"""), - TestUtils.hexDecode(""" -5c796ec117395c38a9d7fa1a02d81e3b51522aebf68f3fff55cbf7d584ec75e547d413562c4c87f28f57433cdbe7c96644619b9f03d119c7f87f0a970a46075cb8c29c506f67007470bb4843af6d3dd1c91bb3c2c62443eb18a69e675e3711a08dabee5cc1a03d35a1399755566dd2f07084a9039c7710ab57b380712b39cd6f3cd2098225785665bbb94f3761d5a8d431cebcb533cbee5afeba6cc877fbb168009b3f05f9829606055e71638b50f4c6a41b0b226134391ae0efae4cb1d2e31c782b55035cd9e2d0bb53fd72749de022537ad8f8ec49a297f9bc81d1ee0f5e6b96470d30d6b78f48266eea5d3d4805028f90abbe90232fea807b50323e722a42fb455f02cd2c6f5d932b9bc606f9509fe2b1c133eb12de12db0206d78b49154c34adfe204fbf5469a0a50301be999015c5798c567729b60b2690ed93db0eac4021d38665a3a7db7b5ad55d94b8cdc9171a00ffa3ddbea750e83e495f7db132fc253c82b6b901bcd00fe68f0277988a1b0b2cd1d051d10ee189cf971f79ab6d1bb641b1f3b160b4a4d095144d1f9ce0dbadbdf6955622a8b300c69ae67dec7f1b777f0266e71413d57b454cea0dcd8cf3c32b9bbccc36e1eaeb17c87734afde3feec5432a18ab9a7c6a1fb30e2e84af2c367b4f47529bf4e0782a26d41520df8ac3cad44d4e792af7f427c75221e4a5230e282bf938a6072574e23f4cd35aa49758829d521360db34cadf94f9ba90d5139179f877723150d4d6f53a5300ea3e26392399adb258bc8075cd19517cb70ed48ba9c61e5e5f3d245d45f44f5e6e033334dee3a95bff8dbad0a1f8ecedb431cd52530d7c2d06ebc8f1b80e5e30e746f9b3b3fc192e359119170e2216081dd908d0a5b03670cef41420585653521ffbdfa58957d06d7a0ed23088a5835690df344473f44b6213fa10832539197afbb410556b8046e06d814c2702ce1c50fd5677de3015575e42b78aea720270aa303e3a6539bf343c52ff933aa238770e7fda2d0d0702c1c7a829e798b0677c1044a7e4af1df817c4167909c158074a9933f364a1800e76234751e7463c78255c3d5189c2a3cce7c2e55dc55fe97131cd4255d92b3f9f5c888029d4b92ff3a544e25b80ac12e73c9a65fcf0b755ffd0a497c6113897ee8bfcff0dc8c9bd583af6fdb71523be596bf0753b25b47766d5be895dcfb63d7c7d9f6143efc509629d310dfff428a1d5328b5307edb41822695f56a09ff2202567ae1b80318f827e0bc29c5df5e4cb075f1d7c1cf2df62dc258544e3dea90239a1d997e52e568632e259def0bcdcfc6f9306c76558dbb30a880d41fcb4f99988e6a9186296e7a5a31c7b910fb2624a0400bbdc6fe0657865a6537131f0b0dd2f56e2d6e2201a843bef51916226577e6bb0e891247f93b5bc36c49fb37e458d363762c12b4b95ba75ac1b38f177fca6515c240c40007eeecea8dbef687a77d3c09f9b5bc5450231ee83294e5a8d0fa79430fc2e701ab39d3bd891e73a695ac6559d8a8b4dc4a6ceb7472ad032036e4aeaff3154099a6f2e8297c6e4bf121631b545b472ab316aa0a3e1192874793597e0fa0cf173a78507ea55b2ed0c13fb045a96acd9d9bf8cd5197f968efdd359bc4449458ac42e2efa187190790de076f56445f92a79be0469efa11c98992ec82e3a2ca311d76e282e91665f5659be663a33139e80952b444914fab59910ac08daacb6cfcda1dc75c00077391e2b38ca54c1e056968c4c41fe7201a3c637b37f48be5672828d5f20c06bbc818332f48e0a4c0cda579d4c114d0446896b60392bfb66ec8e4eb5c3e8932259c423025da0611e06b34209f35413be186d98f8494d18eb0b2d56aa47c6d72c5b57e2f68da8ec1039dc565dcd5c5937ce1d358d6c83ded381060647ddb52badec80e92a98dcd4be27a5990c85192e2989dc2553e3606f6e6ef8353202671a1f2dab2d3130946254a686121a26a29ac8553ef5a58d31f9607bf3912fd4340562ff48b38a12b7f4d8ef2e058c9c721467e0787aa0eb2ff53ffab5c2b3c40f52524d8ff1cd0df1edba1dcafcf983a9e8e9840ef269f9648d3ed8e7778e086bcb887c54e49c8848d21002ed58f163a6888b171a945a9269f410b3d541b07f7c83c0e6b80dde9bff6c3f6da1f780f52ce0da11c196c0493b6765bf01aaff22e44f2b538672b4db58a616e2d2a36b1a20a618acb6e7523546e61c8ec4b593407d0ccaa0ca85d2db46a6cf188939ed9583f591499fa436443287fda7e49602dd8677f171b487e4fd6229de805f4693fbc8f27b52f283fb0384a2994755c5a6c0ea99a8be6f6f743d05b75405f9e70d68d4904b258d0f5f3ad0b23d62767d54ec493f15bda17b34c31eb50210788d38ccd4490e0b65ed46e50875da092c35b0100aae8bc387ad595be005bb52ad0f3281ac662305e0a62ec6254c4e091b1fb0552398b9cdcf2c12069b90b6ca5d67ebeb22b6aba91a7ddd85ba31addb18ea61d98429e633e5296eda442264dfd6bafdd3f26c9d6cfa7d8c89f273c4058c7b88ddcf79d7cf5c8bedc4ccd69c4b545a0069906c12c0b5dd5514cc1d45a50173c4f51e0cb89e2e56025539394be823889e0b7cd3b2563f756bb6d95336a22a1f84215915507708fa18e425a6de61a7ac74689bd85bef8aee1a48226a96ac318bb3d8fe95be46eebfda3662e04741f93995e5c30b1b3864feae3b476f341c473d449f3d675c3335617a201e992e9e96d35640d0152587c7edf50ee5542164e12d268c0bdd808ebe067e4891172a4d765650decb3e9baedae4c39834b5b6df1c8252a9b588c30b25167c543f389f4d4db14fd1319161453311572c85bdb5fba5886325b5118b6bdf774c76fce3de923761e22054867a19a06e2f84463a737ee6b4f42cf97e062db911ef8dd2a6cfa15a4698ab96c9e70c7823956665386aab0ae235b485391542ff57967b67274a4a308818ffad47b82051e674ae13ff73a111c5da089500f14c7d05af77d777c612628b157f3a921bf8b0cac0fb426866833ee35a2176653dace88dbd03cbad446bece7c6177373db768d561aba1d86ef2a5680f5d71e2c4e35832e8ca69de760893f3e6dca2e9b39dfbfa2bd4e1f3c2f5ac06e7b07c9c3c85de16244a273385f9014263614cecc9ba3bc1679d8b2721211b7fe7fc96612abc39312d8d05dd530e9e6f00977bdb27b0632eff254f54213213f608177334ef02f79cbcd5062c9b50f9c3ab14a8fb019d0c2b11ed1a5f93d769d3fa14eb3a7e2a96c738d1a3d62dd49a5dcb34ddf6944c066ed1d4c662752fbc961eedf9606c40922c43c543f6c79cc4e91432d652c6ee492679f84ddf1e1e6fb885af725a63168a6c6eac8cb180fc2b71f8d83112b81b168e96e42d3f069b69995c351c6b2bf1344f98c5fdb2f3fc503dd6ccf5cbc9a1bbe111ba2380bcc2392cd3726bba4afe7dc66a103a2defa50516d7d0d5bd058c7361bc6a81379a6c48fe76e81cccab97af3cc2a96d4abd8d5399c8ebbec651320d66019aeee16dd9e126a4f6b16ddea40a36f2ddc9e5d91bf8d5a39cf7069ee917c23770c18c54a5d2ca8f23ca2c9d21f9003b7381c077b7607dd3e3b0c34cb12c77ef08547501085370c6225e45c40069c87161bfb45498397c5d714c86442cb1489accfb34531a14199cf29e0e611f4047f22d40db532956a20c8f5561d9c6120a80507c525dd8584d60f41e999686096454475a2c92bef5880e554a09cda2238323fad2827d9ba6cac319b01d2f89d708a593d660f9c19499328167c5843ff20a17bf0ba26c8418fef3ad764a865f471099708048a624c39bc7ac317badb19226d8c0943e0fb8aeee9789c0ab6e43f932621e89c424da8a6eda10b936218264161433976904836c0c913b5a0f2fcd701ae18ff8309f583f75946a02b930c897aa85ccd239ce2edfc7dac8689b8e678b620cc853e5dc57fea9221f3c5ece3a1484022934d9457b6d3a34b801baf8afa4adf307a8c7b6092168dc5fc35393f772b576345b2f6e1fdd9ccf27452174b8ef6bde9cfb37dfedc43755be905373f54e13a1a40c3757a15bc36aa21657ae4a64a16bbd4463fbaaf69cf4778306876b62abd4305d753da808f0728c3f51f838b640be0c093b732595b153e2615da3c0d5ce5801322689ce85f91767bcaeb81cabc3baeb76deb7154b79528766282bbea6d026687d2f823fc25b97ae523e1eecdcbebf460b447b1a2e677c0215fbae2da1dcd182bcfdc912b94c732b793588ffb0d1e118d02b093a3cffa510d159ccc74ceea63ed881ca79957dda6db1329c22c10a082baf48fd6a2b635b3f1b896e77087734528d0943da51d31b1619e549ee1366e9df05d0a356aae84cf8f3d0c8fd5ab534a3524be784eb0208501f17e3b8f70a52de886bc691db2bcdeb63f7bd739fa3dca52e4d44a7b6b57564f17076104da5169b46d47bfd01d2610a9fe55129e6249956233a911eef491d9c5877e55585f62f1d17a84bebd25738d11d830c2bbc5b55d7fc60894f4db0bfcc6639277d290ebffd8a02e4d0593f65223168240e528822a90d4fa94febfd55e5562fec1f279af1bf7333d5b8b8eabaec3ea262a40586d8ea1e12b3b417789ed00010f333a787d86ced10a233e7385c3d4de1c3450557ea5000000000000000009111721292f""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -775194fa9e30c689e7302d8c2fc00a7f00841fcdae64e399a53e0be6954663065429981a74f61454a21dc8dcdddf4c4066ddce8e5468b7bd5b26dbd4283fa7a877923797381790c1713da02709968ff0832d6c4d89d20eb3145a7c15ac09eacb033a7da76730e09b3d046aa5af01efe52e3a0f027fba5011fa546fb5fc0cfab8123354588821124761125462867143201068176532572015662021787412776133663461662516613127305076874123764663443174716886480125868463106558201008703176818888335470841078863525124780848221402401271324205864713506180015021080561066460302752630337573872578318172800670886377121683873150166316433017633687422041072550783123188513067875320218141887780241707861057474220312532464675542836737678404710137071730427208884644822180077044878772244308013004077287021731285122144771457608441245004186732638806268712328246273182373310817212362101711217128744356367251232358767873630286444004265228015852545234702853700543220230385386347720606804853040270356121170354546661117884006288624425424261076447101017261433632246067153565133005185584112568087530887400354165514575612710107518105111212880423160320776164322663187851666826475266514506542017236133470881016371558026467184825281620822370012506573522580870410800578835360423727437546187382604545324437380583851840368564484147868560247314316431274136074313628586112642714347270355050863242834182541260623061362670072443286601140011122260170704886474038621622106223074831064667433402301675534076201486620401610182475848155741838435013666012256742055143062248642370042501004404201220472422713362532468454186164808851065576017668724284048886510873771246805247433731476322167183106422148886801663744886227641807258575643350158780032653053403277082020512364842215836461740846432310100831764051262516215812253404208551486515827351162618003733466066543352780177355410552035840806874540435161826802664586320781278338035028133718746822122511552230063508641532268816678453680866581380828033615673280874678758324088400275448388454607317108875831531354227470725076141144534686412537824563825722877183411550677700373524533067445807141178142157871184851387873106405258723664717374150224651476366210256351366353505453335354526742522767451684323424516401350610873104848665032166533585003470786668323686852545850637165171575158723631707561800080148548322850210080726687771640233236848368300075578486270244466218706477857038331816632104585010604237368056736578088326582476813804678062134825523128202303334241720070686472747774265138046574103501028660081182563722570666424860667805087485053108754536312327142124803354804743005550286355268320427431215730548114172563283722026208424375640424116413408624467633266482015723581236203131518862113064822005608608433723653237120352587004423311474456472088471536172214481065711267885838858351122324414845814341224441731416501101677844383118405826224634471523326237030353065105122703137580526125512333342624572870570653773585614446713440410767104157105715385272211378045570506026334811377158286601313708787117102676024340056353641642212118688236601230400305723181867775275010672436885537146518804123060448460341683143361006382558285618843318316025426272581550022725e3ab52ad317a7288f7ef740ffd3fbe62f1a96ddcb6d8bd300d46f4f2cc1cad162d5f0bc4a1c0d46f8c0f567ff3a962f5037da119a596bebad2129918de11be09cffa73a7026b1c4a94ab98184f7f6b214e37b06843bc197f6e54084cd03f427691ebba03207bfc412133b8f73dfee78df80421a3c30b30962b6d06cf8e41520e8c9a7975a48e45b9d6371e3029f63b7972072cf5c30ecaadb3d763f2acbce180c172836e2f866a894cfb2193268616d8bc36157f48d7846b317c6adffad1f4197d5151b1f60f65762de9ab5244a5a7ad8d6feb6cfde27e5adc7e48bbf7f37e7db6d8b42324c070be778426a242e805dc353b88916bf2c32158512be8d0a62215a4e9ee2535a1a123661cba33ad1fe6f8e61c62b34dfc7edb12e9aaadc76d6633315fe128cd6df60830057d5769008029be02154b385bf1daa32633a8b73d39549f2ef157b00cc8e347257c9c409113dcb0008d0d9f9a68ba9c0e2cdb1c5585c76498365e81717906f6e2e6fe9153813500d447c101ad6ba8c0ce13803396cb44e6ee31cad12e9e934b101b9c4a4e18f9a795e270ed2305552e43c74c6f9673cc78e8d88eb2f30674367415944ec31fc5976a09fa62750125d609f5af9f06e4480922100d8031aba6ef774bcba84a1b3b1805787efe2af85a7e592eedc320bab69cf52a9467b45d9132e45e54db62c53154fe963293c252b4e4e29e832016414f4dae7f2e9d0f87d050abd1a72ca7348bd4ef25f9efeb7b4f25795f8f15ffb8b5947f7f99eedbe22f238cebd8d747f50547ec451854a363c726796c9adffee62ddf079b8b39d4d2b9c77ce9a629c1fade8f4a9940aade74d3f6194f72c3af20deb8c5e4588cbd9db261704df134b3b147b526a50dac889551c7c866147e1cef784eaa27f940327f713e4f0e1c2f77a09160ca8cb6acca67778c6f9f5cf50723ad9edd8ee2eb93bf784a4e6ba07c2bfbc581bb80cc4525594e98baacda06999dbfbb49609481c9eeb1082a7f05cfdc95a43a0d309e6d3315ea1a98e658f394f239162c8b417635c5a100687984a3a458e276f6cf964a87c72c275e35771ccfd9293a13aed45526352421447064ad00a5457f04ce2066c92cbc2c287056036cd8726fcfc5e9dfbeedf73493c95be8f260db775d5d733577893d871a0281cba27f93fba8e5520361c5e9108299666179e3f40313e0c6ce6012abe07f2dfe2171f4da5358733188bba4b1059e516b0a2a00493e9e7386b9f00bc402f6986775bd2f1d5ab7455aa574a0576117dbed54e8bd7173a9afe2b5428f1576ba498bfbecb42e6f86164dd5d69b744dfdef0ecdae1ce1c9a03da3e02d707f405ce5cebf694671b41f034bb8757ff3f403d4153573fe46cdf0a91b5e0f34676f1ccdd8b37e12a737e0735cafeb5ba7a086639a7298712e67c56c71c3c81fcf2667187b7c5487a0fd292e1a836dd576d177e01a24949ca3c7251e9c522782dda331ab2008a77c55616cbb163233a45b7ff45af92434c00a590aeb1f4df607077dd9e8e1eeec4efa64fc1b51c15759ac1c3e7c6389614e657d314066ba3d84a5020ab46006424914177b19dbf6ee27a3ecacab4e2779ce9be2651dd4128f1a3c5acd58c3106695eb403d5fc7a8dfdf625b4929dd6903c7f4a27436d3ab1ef51f74845a7ab5498a9e5b10e57714864383bbe2d6584e7da26ea0ca3059ac96fd8020fe4d67d8442d91f3fdfc26cdcc9ef55877a460944251115db42e7470f80784aa8b7e4fd21642d9d91282e52221d6fcd04a9b7acdd23f124149e6823c250281eb1b0ebc31bfa8ba142ae0bfdf6097b14408a9e61b9c2b0f0e10efd2cf3cc1079119e7c23948941de9f927ac5b2d718c19ae41c14802f0675f3b75f084f622daea75d65b05c0e17098b402f05923b9011cc96e86a103fbad491faa1b8be68f8f5738b199e14086da38ce13196e3b2f4b9c038b93bbde1fcc3f277be2d37b4bba08fa8e8504760f63cb954e511b89d8dfef063682502417759885b1a48d93100d6eabf14cbeeecf2ce6c17903ce588036e4e499c22cff789f0d311fee8e4127819679730893009d46abbf837881e26e490c437489437408b64d12114b7201abd6b4591afc083402e959bc9c510930abac67563759b95415251db053b68a5278adfcf26cdcd18463226338b46b07900ae532488a1a4fd172163e36e3f7c219b86292c92d68d6d0123314ca3a75487e920f2b1b12c0d605f153f65eedf3d98a587bf6eff36dd53ef6686a88a3f0265248c5ff91a4a1b755aa1597d1c2cf37174dcf082c3f89148ed8d4852ab2120a53697e9538d4cf661968d6d8d71861b32efbabd9778bfb75607432c765dd3aa2f026f38a477e65958b9e3c2d1d8eb0533b1f9f939279d687e4398d2ba454c29c420be58c3054b3cc2054a4c064f3702a409bc47abbcb70c59a1d6af84719e067805599502608645563c4bae11644415f1b82542feef87605e389d8c9afcc191472fba3987e4a0135f78f97b34cb10889e11bb9ef1149b57735ad77f841650448775dbac5d82ab0294b35dab15eccb5cf979021f59e0cf02bdac2b3533d2cb56543d9b1896ce9e774dac74f647674dfbb9ebf78b9aa02eb756182977a8e5eee876d2fcd9a943fb38850c1de8e8a831249d2c3ab9e3ee4a25c4e37bec0d71bc2a5a06b04706ff801b5f0d0ae9220f667f18480db1df8fbf38be4c3d5bddb133e102c4ce030713609819632c472e85a01262c1e2286897208c3f9871f8640a171bd4e41db5852525ce5a8da599e845169cf140f33f105219e7d03cf4a1aeb90341902a2010a172955983a252c32f0a5e120b099541145b8cf23a3f5a3839d5fa649eedd624a19a2530f570c7ca1941b112749ffdf96717c73506639eb3a96677fb97c66a613aa21bd77a5302be163d726ee5741c15bfb187bec0c0c1052a1715a2cb4573d4c3f9c3618d2c433f38145ff88c8b0287650f6a50d2ee661e699ca59b6385f10e250dc70dad3a5e12c5e002cecaaec22ac8b57f5ac5ebed502a8e1e6f2ff2936d8eb7294aa89778361cf9b325ec79197ca4e67b5836d3d025e5cda054186c214f9b920bf2132d403cd8dbb24573055b775aeb18151b1bfe53cf1b71f58a9a33a62d5431e3e0513cb0b0790f7d4b167b91ddf78e00f988ae84cb81b724f1981cca7f78e5553fdcd93059664fc84ead17b59f5832f67966d93e3dee2e57c25174d217f4c054206e53bbeb341ed71f6fdca79c55bbe8ab26ee08007ceaccb99884400e1a4cefbac6858012419903397f64bcc9949fe070f02f227e62c563887b68c0b1b3c2c2854c4d4e828736faf01c5354fdb9c8a7806ce33047d591d80d3af33cb455818b228627f57b1973fc396f3c3711603b286c4379830044e3982c93ea0e8a9cb1b8a16595f442bcb11b9a51fcab5b37047bc114daddc06d03ff76af94ced219201585039f0ba8a95bfd17e5a8d24cd7c34a99284db28bc54bd2d5c4540451e1858805f188dd41a70be6cfde8ba28d4ee999d3fdf8"""), - TestUtils.hexDecode(""" -5F8F32FE68B556ED1D2EB8D2BC20AA36DEC7900F8E5D4BD3715419B28771E5B0A080DEB2F3EA6CF415D40EDA46FCF8A439954471B7308D3E4226E9D5A96BC22B08FECEB4C5E3CC2239473F1C9B8DFA5A29C31D499CEEAF6E34A396BF0DA53B54F1AA674056216756DFE15F669FC2E1D8E6F67BE5BFB3D5703F25D62D3AAB0398AEDEDF7C65E051A4A8DDFC725EEE940BD0D06B103EEA32D027CC20A8C61034DC54BD5533CDB1A85107B9CFF283FC3C5FCD9C3D6F8857560311AC2E0E31585E77D0806F9A4E61A70D3FF36895ED447C55DB52002488045CC358A39475BFE8456F4FBC36005218B2CEC1C573E41BAFA7A622EDF776C8AD340680C1B3002F69D3B3D8844494EA9F42D2C9C9D2BC0BDD850BA3C4DE929C1DF49351219F95EA7B9794827FC1A1BB4A6A00809393BC41852820569D7BC6FD55339925FFDF55A0C2655C85144234FDDCA91E8BDCE8CFB7199330763F5750D71CA8C4B3BF7E6469F5DD68624BD6D5B69E5FAEEE53E3A61AE659A364484B7D2BC8A85BE9F8D35C8B97716E8202B610BDF878C1BD83187F7892BD861C09FCDA64606A185B93CD2F601C3107D35B38D76D75AD6023AFDD95E103EEB7283379BD9E44CABAD923856A599B719A18FA836749E5BA95C79B1F2F1B443CE1FD26CBD2B74A0156C381BC270B74FC42DFF8D91DE4ECDDF3053007A09B8E3C964B90DE55DE5193F218685327D8C0C6CE3BBABD57DA8772DB7CA9234A3D19BE16A895E7D14337FD9D50B4A556C75A9D287B44BA5AA4E52C3262218DDCEEE3A7BDBE1B8175E84113F515623C07BAD4FC0985112DE4D77D31290BD013562D12FF8CBC5F2BC463223AA82991D7D60E38037578BBEEED70631CEADFE49823EA3D87EC384B3FBD4974C474FF9D47F467110EA4F3FD94B5FF38D8FC1C75392896394671853FE71DDCF7730C70ED26485F395F180D2F5C31AE0C2C20691CB4BC81356225E6A72DC72A1CD3502E42C22B594118D131BA5EF95F2C18B3061139B047A24E32197F89780B91D36B28BB5EC6C03232A3CDFC5ECF687BA5701F3958FD87FC0C8D09825E8BE4E5CE9089C674049C38EC5E0FC1AD542F57B4770B6E5DDA215D319DBFFBFEAD9141647A508E271CF3B0DE7C137A5AB999CC88082FF0CD495F1F1FB1E367B57BB400D8697B4620B75FE467D9B8BDF9400E14047576B3AD6AABE0C0714686015B8A963A0DBB68CE9E41FFBBDD5A792920916538E4C33F12EF0E93D249E562B71BC1C252E1DD8AA646F8C7B489A2BCFE7D29A6D3FDA2C21DDD78179861AFC766F6885E9959F753C66462DAA6E01C8B06A6F581104B583F7A5B1B4935A4EF08219FA8D114A963F3FF3AF22C3D1C1E3927AEBC886AD0670FC89C08FD4DF68EB990A0F7C51A4439C32F5F51785B20DC82586940C35D80A91865C3154D6C925250B24D4C1A9E76A267711A0813E8CCD2DDE9748FA0464006DDBA963BBDABAADD377239442DFEC6F7E8098604645D63AEA080C1F749CAC589F77B4AE0955FABED757E6576966D539FE1BE5965D03882279B2C9B6899205C9DE8D0B1819DA8B5426E573CE785FEDA3BE95A18A667AD5AA8FCE7894BA11A44B266EB7571A93CF9FA64C1132AE07F0F24773C83DED2C2885D415ABD96A21A0381811D66952252786C39EB68EF0B9B03BA7E2B66A49BC6CFCD8097C321A932E5CDB11EC6E43A8E50DDE01EA5A28F08F5047C67C988E8B4A04701A0237330598ADE8EF8F801A07F2148B44E593B0ED16DA30BF37A341073C6A92066645BD7042C3A59B374FDAC00F7F69BDAFCAE5EC0AE65FCFB785C93E49102F5A5029876BC23B0FDB7FBBC376A9E834F0D19A276BC4E22FEDA18FAB529F15570AB674B844703B47D726AADE3AD4015F52D86843A01AD5DF086E07A71A0236765DE6A777F94B1D69253A424193FA9DF54899AD9915634DA23E6DF351E9608219684EC8C8C949E900718DB6FDCD144D0BBFE1079C1BAEC516BF60C1E24B8EE6DC380F55E0F65DD64025C937EA89FD12F0404ED0C03CBA18CE2FCF169F9A1EC9B96830FAD0149D4A90B13446347CE4E5C6005BF115385F1D22EF6A7E40EE87847BFDA4CF7FC3135C4164091F49DD08389E1005271E9AC76E27B0CDF360EEBEA9C08E233CA58305CB276A8BEC9686CDE0E2DB5CFF9858029F3A5A42759E4AC6DD40AF9617CDEB03FB1F9D7F112A01B87A265C4E27BBFF596695F127A97E1558A68BB5EE4EF0F44D20F318FEE1CE988051F3C09AF6E142932EFE970C1B0C07040E7F3DB9BA53BC4AB1433F7A4F1E480D920C23A07223D7E43570320B3BA590507D580D29CC3A8C85A442BECED5880350F9D2B1AB5C746C1B9909E446D9508D701204F2427F41E043A78024EE3F60EE19B71B5BC925A2557FAA8C7BAC7E3405C920FE3FB3A1BA7C559BD75DB1E4169804B6627AEF19AE6E41B8A40CFB977C1AF53208F4D775A48C220A756783F41E13B7780328992947D215C5B5682DEC76CB035B41C007CE1017EEFBA426EBC423F710C1E962528F7636F200C2E79D8377D621513BA7EB3EE5A0DA55B81F6039D2E8BD42EBA5B2A82C3F033CFEED6EFA7D970B1460CEACD13A0C67AC0A7EBE7963F0FE21D20B2A82EA922FD889253B5D4CE4D47698D43AC11A8F4E1638AD3A4C179C522A3ABBDF420DA3E89B9FB7608822904944CAD615C62B28EDB15D3826D33DCF9FF9BD5DFD8639AF4CAEAA55F9F8409B4E5F70681BB7861F88283218E15A4282E199BFA12360FFB9BCD68D9BE5A3411FCA4E8279562F595FAAE0CEED4FE675DA4A8FF94B180AE9D0C8C687650730F05715820F67248D02EAD4C7BC0D41C880444B94CCD60A66A1C9B5B6F6690A2E1766EE10B5D03AC16F175603A1B9D49F97CF3F91932E97DE67CB523A38839468EE7681909CE997BFE5EEB364B472220403EE4A9AC1F8A4A8F78AFA4D9010A0127C0A75D3CDD87DD269F19A47C78F696218F25AE8A61073644A4F791ABBF1B180267AE41DD44AF65EC6E0AB356CFEE86095B64F4190D69D60284A1EB42744C31536F736AFFFFF186833EBBF43709BBE6903A06F7F06E8776D2AE41CFCA33A3A86342BD11B67EC10F525563A1843C8443546C1EE61DAF7310802AE9C00F44DBE7E04030BC4D0F53AE2023A7647F08A0BC6F5013A61A84E994FE0A20092DE133FABAE3AA24F8F3946812396B0643721AA13417A2423F96CA8A6529B0E17766E88B2AEBD79AA9D4D31193533CE50E4EBDAEEC976F156D5DE5917D54F9CC0527BB4F1F795401210739A42D10A0242748DE5FF6B50932B507057EECF8A1E37800223378642DEDADB464F5CA251D73DCD28A1E3772CC285A33B34C6701B585FC03C94A847CF7B16616D1C3DD646669546D80A27E9DE6424AA7AF6F1694037E774259308E71E15D7408BC1EB517CF0AA2C9E16B802CC8553458BB66D96CBA233487DAAD6E093235D901CF46F31B9A060D88DBD0B7380652EFC73AC1A6BB5E434EB0394F1EDC937E9A99A3867EB71D6E19622137B009D36ED7F9890187CCCE7D884DFE118AB3682EC08CDA8BA6DD4B79C9C18E7438E6914DC1C403870A540B74244964CA31E730A7D7591E42569532DA8094559241F2C7EC182FF8BB5A3F88DFCE3020D8B8CC0D1F54CF67FFD3A97CBA7F5EC79333D9A545221C963E0685763E59F1EBD34FB2394727896CE638E909AE6DFF41D17EE1D0BA036F8AF11335A8C1B5A0E9DC58EAB9C12F46740493A8B5AD0EAA73AF462BDF43CE44BD0973688D9C8DFF8FED961758E1AF88FD5D249FFEC179FE5AA1D135C0448D80F4B0CB68492CA399A3916A2EAB684B44E407706CC3C2F48972BC9531353091F91B427FA32693906DCAE862F34AEBBAEFD30666523EA9C27354F2FCD99A6E810685B51965571E4B4B5AAE158636497B6F952FA0B73617AE35A8D7C272DFEA1CE06E983CC65A501F73BE9D69EDDE6A4A1764DCC4B74EF09EC27C74B677920AE8C49CF4F18160E04B5AE7EFA8D5D92BAA5E4E547CC8AFB9D55F1A9DA7A6AA06626673431889C9996BE0A473702450B960231A617DF4705B07B47DBA1BCCC0EFCD5713F88F394EC4BFCC49EC24B76D531A356A6796785D755F027C664D8966B5CDC82ADE776BEECA8AB0D9DB6ACF5E841BCB4381828DB8F7358A637D04D97598A8B3BC823B891F5EB6ECF54E6F9200C380813FC3210E68894A656796C9A5B780FF486E6A93DE055B8F658FEA17035D9C212D23BB5974E1161E4F6041E5AEC446D70D52CD2F21F1A33C9938032487D9ABA74C448EEB8F8D51169E8B848242F5C769B471F0AF04E965BB0F4AE7C6F7B4AAD4E283DA762DFA49FD01D21887ADB28781FEFBD931AD8E2A26BBBBE5D88B52E8B7133134CA76C6648EA39E3D2F102177F4237219E06CBD05174D503C9288EC9C3E0128A824A7ABF418DC45EEB3A67777F74D6EC52891EAE0BB56DC756ADF40D39151E3A68719C563E99BABCA4C785BF4C2BB1BD25C7EEE22A8B0C1E90B948FC3A691670E9A3A331320CA4416B492907C3FE70AF9A2E765F9607EE1BB2CE52D2DB15F5DDCF59BDCCCB5BEBAC2784FA0896BEECF38C24022046E5DAA7607E8D2DB8CBC65541CFC6A0F20CC3AC5EBD4560BF5E9A3FFC0BAE917B479D960ABFC99EF84A696CE5A95720FED90F3AC58D77D48BD5573A0D85681238AC0EA8F0B58A01378929C691C146068897C5642DE74D79E08E5B94B101182200FB3E2BBFEFC8B44D2D1203075862D77A184B25A7790D76D7CE88C979D73E599C212F04A8B01EC3CD6CED3B5E25487957C56BEF6AB4433FFFE6DBDEA396212A6870284FD1BAACD5F7A5D9FAB90D5DA39D3C5F9AF196D9C46100BF45861679A7679638BBC8E5B5A7606D863478B430BF2C61F52D3D88B0913BF12597620D337DEA52BEE9CC8A1592698D23B23815C596981152C99453FA16800545EE781F24841FBE5A3E5AD8D08F2B898127AF40A681DF9DB68681533C349109C29D19311BEAB4C2F2DE97A5345EA7E41CC0988B2042925F1F9409D947128CE1D38F278863385A19B2CF8338D0FF31B06FD865B9167488EA157C7965F4679286077894660F17BC7289BEFFA93CB7DB990A0E40D998945A77E536902FBAD3C8A278CFE0AC883BBEA0B20E5D70EC6E10B59C2449CD1A0B55F8252C91CDC87E70E72FEC175D6D67BD43CB5AE4EE9C7F9476F4589E2BBAF89E801D5E14458F8A0B96ECF9F080E5150E2A5004C5A89B735639621157C4056DD1106CFC727B921D5890F37051E2B906885C1CA3999C18FB8C9FC9B652D82AFF074EECA9976D612ADDE990DEA418031FEFC4E972B31CBCBDCA0469E3966FF6F97F9788650298DB71CEDFC04659D30FE673602659C19A869FB3EF4262EF3FFA9E3FFAB1A3FE7670061EBB0D49BC60AD0C774913910E26E4213B76DB72AEFA3CCC197CB6F6DF773F86F12480B5BBC2068F61E16D1C0C141AE6F1811B2E0D713AAF60B90BB2F00EEDD4651FB5191DE5A246A4D8F3E9999D85253FA705CD4B94A6A64D9E9B6E18BB6855CAF6B991494A8DF75E56C2A427883E0C27246E5854B8DB2EB0FE639BDD00AD678D1B61D799AC59ADFF6A8616B357A4B12A786EB612E5613CDE533D92E87D51D47D860BCC39687485EA814DC5F5A971EE915C193ED52AED98D7AB301E32342F3D207BC03546460D33B733E1008E48D80E716FD717BA82403DBB520246AC3BC9CB91CC0ECDB7E35E6863C3C11558A8EAE9E1DC49FBFFC0F92F397828A4AE7107785939B96932B9EACB6BC6D8B3A189B5D3F6B0C7A3A413054B25318792AEBA3F4C77629F1E8CE1AAA98FFE1EF50C2E60C11AD76EDDCD8EEAF858364ADD637AB97ACBE4D2124AC0AB559E85229F1B5D81701EEB1D6834FB215984E9DF3847392EB29D2A428DAE7FAC283F93C8FED86FD2377E8216922D46A51E628091F6F8EAF967740B0EFD84F002358D3ABEDA0993DA16D0D8233090A2CD9C27D78DA0A53962FE7DD282B276A30F91C2B734EAD2CCE5E03137205BD97739F6CD75A08491D4ECB22591A6FF840B5DF123FCA7DAA98B11C85C1F8591EB988024C206CDC4A4239E7A91DE75F49541FFB6D91BE4699C0C0D8B4A44A8204F7E90AB863C3183C2270D185643D6A7165C1D043FC5108C340650F38A8FFBB13BE4BE68858C50A2463F7BE998286FFD0F981B45F5E414FDE71637D6EE77B33E10A530C630D63F21A212E844C2F7A26BED4F7B4DCE0C566CBAEF4EB4BDF2B53E743EE13A845D3C7AD5E9525C50CFED35DAF5D993B6377CF1DFC5236D51151B046F4904A02D7D51B6E331754B0E3621DE4CAFC9D8F7247788DF0EA7E6141FAC4B24608282AE29D594CEC0C82DB05C0087AB377D0D504F64F1CBB2D9F3121087AB6F35A70ECDDD15C9AD2A185C16333BB901CA069BBB0B80CB6F505FB3F382CED72CDE60FC050241B1D32818D11AC4421B66CD85D0F7B479C021AC111F8EE8F1C60B2320585EA276879AFE4034DBA277806FEEACE548CA0A5D36CFAE7B99ECB0236CF4838254A20A13A2DEAAF201B09FD027BAFC3F0C5ECA9EB5850A58C6196645F051E57B82AF4B6C2DA9441358BFD2412864950022A07542601631A00E27BCE6E203B1D3F1B844CCBB2EEF71A12AA4E725188073004849A225D733C77C068B0D2AE53E0DA6F759A8E7A5486C529B29A3EDADA69924E7DC200158DB4B612C62039B321CDACE8294DBB1A56ADC685B0B0122A4F3DE0A264F47B00C903BD30B5E4281B0C75DAC5C48E18BB0BF642F8C2CA194AE56CF7EF3B4529FB9271774108C61198A6894FC9FAF896472D1CE78DF00E714045C5F7C77DCEA45B3ED5BE5AD545D8F3833206340A5E10DD3375BDE0A068D050CB4C87E0BA95CBACBE59280BD5CABCEAFC88F5C05E3D8DCDA6B15C487B62B467E093259230D47B79F36572972BB78F90BD384255CFB1E4F1DFB7B5360EBE1230F154C3645A7A233FDDC472432F6C845CE86B078D93A5BBA3F8800C5313593D66A8A103B01377FBC5C6D5FB8A55DC71EB0BC9904B24BAD2F505D6DB5640E914D84FC71FA058902578B72C47659AC07AD4D64C3D28328D2DC8425C4039EFB2F20E3B954BD0B0483848F2C2D9528214514510CB0932F7506E9B98D0E891D8183A907FCA7AEC068B9FDF7F3479A128C6982BED19512A4271D8B682525B5028B77D6B6301181B403E5F62F64BA3CF06F0EDF321114855839E9198E5BA2A65ED952B2204809215B9BA3C366FD5C9D409BD71ACB748E653DA82EBF617D2D57C74CE37BF20AD8D789DA53C086423D86F94A96ABA379F3425554BCF92F82FBBF5C2A15947455D7D7478A84BEC6E3B9FAA14E425D2C8971DCD157C1D9E210620E891AA4304CDEC54BA7B3352556C49A172EAF19919184CA005A526349918F9A7CBFEB83510AD899BAEFD3D1F689DC3F449153597C8D21FA1C7BAF18E689B51F89B9BEF196193B7A781B96B38B9145AF7338FCFEA109542BB1719C9C8540B551A35F733C394F7831900452C0B8D36BB90824699BDB587EFCF5E8410E4ACB8ECAEC5F96E74A5DD3DCD4C85720064A14028FE768041BA1A13A46CD8A0D2C4D09E724591ADCD5EB907038853D8C92C5BA7FF57D5B54B2B324073C7CD2EACE0C521254E9E5C0CA197FDB3C1AC73FA8EDA729A858098E6F5EC11A19D4F655C6DC9AFFC4E67A49EF62D80EFBCAA383DD3DDC22C2A9B7590C16F8CF23D52392186B95EF9E947D851079C35FA11595682DF4EF4D770EB16CBC3994326B8AB3B2C279149122D178BC7B53318406738290596449D797F61B3D0CC8B11750F8D841FDD9D333A5FECC67CC7733824BBE257D40E53B43CCA19C95ACCA8FFF393533AED57D423BE0C38584A81689248BC7F78CB7FA4C94A7BDBF3015B4072B83748E55ABBF4A334AED679D89E2F18BE1B249B3F61363C79AEF6E1FB09D1948610F77A9927AD6D57BEDA02BB1E77415DD7FDD3EFC683AFB1E20C08284B620EB091974FDF8CEFBCEE1461C210E81E86B61F2D5D1882261D60D60689E39C81B981EAEBD9A42E608A34155516E4E385B86BF0A4AA05E3F99B6B3B7E401724D1442A45A696A189765BCA3240111E9259DE161DADB4E0ACFF27818C631A8A2ABD752773A83DC29CD619A58556040A7B27CF56086BD499F8B8D283683377A21BE120374B8D4561AFE781F246AD987E828FB40306366B4BF4C0B4B909ECA91DC85F521ED5869A2F2AD58C74B6C959AC71DB6F11503F026DFFF6BDE6BD70363B5B38BCA0590A5AF2A1054209A36B41B2A671293F2805568400AB282F783C356DDE30E0F87C001D9B1B9716A7C4021928253622F2DD156B3C3038A077A5768AB8AC070BBD9467E9C9630754934186BDA122CEA503F5E274EAED746065CA81A2702B582E82A33CF6CB3917D451FF59B0909E6BF847E6B610DA89AFF98B3323E1385954EDF1175C0C1B158CB905BCFD9AE7FF9389ABB9FBC5194A45DEB0570C58F31D914F9941B0242717B243ABCF5A20676051978C16FFCAA8ED2EA23B8323CD58388860DD64FA39971F9FAB83A4B248EC8161D32565917B7E6EB4937B4743C6C236E75E1747A1C83377FD1D927D385D81A9EA7F4AE5034097A0A77E2D2EB1943D3128BC0134F2D600ABB929A5281C26EDE1C12CDC80F8EAF2E893091EA274EDA1A246AEA3263E43D6C60043CFF6282AAAC620A21B523783E0CBE33F78C89D00EF8920CD53C6EC0E83DD7E1303D9B6D5280BD2BBA26376C17099758F34C22054DA031C86CC50367C81C3059114A71C565B1702981D77040B0FEC1E89436ED1896E93BA202F11ED2BA4EF33A76F86AE8E23B8FD064C8FE894244C97BA7BDA6BB56B7517C236400F591E4F28050C2958A7A79964AF233CFF8655F1603F6A0C7ACCF440D0C82D5528876721434C163D86858B02C6F6A660F53B3E45185FC7777A629C3E4392AEE4A96D900B0F19783DCB6E5028B6E56E160A37D37FACD7C3B992773ABC8AE1ACD6AD41E7340CB198C9BBEA1CDC185AEEB51E2620F0695C2691A29CBCA8E23328E84B6882A59A8C3C2A273CDBD26965564F1F1DF0B2CAF83F30E782C049DBC00596BD85426EA90ED30ED8EAE8A88C0D1363E69868E8CAE56E8DD62CB36D9A15150FE567DF7DC93CE78706BA983885155C9AF05B5FF1D0EBFD9D020BAA9196D9C871236DBEE8A703BE458938D3C882719881BD49476386387DA3508780878271C0DA821BAA1E9719E437BEE6294D8E4E2483932D0257B44B8CCD8C55028B3B7D2BB3866216A7F52CAEBFA0FBAE120609F95213BC05AE24473C98C29F4A46D985336DF8305787A0374098DB279EF0E34E6DD79BDB106EEA24E4DEEAB6DF35C58AE73FEC926174E0942D242AF0D30825274FA1D510D1C0C41FFF59A4381CCE5C6B89AF30C41733EF42E76C9CD58DEA7E881706843BA04E3A170304C551B6C801CAF9B8DA52913D2DD4DC755E0BD7C723C4AA5B001D9855236401C1014507CCB84577749DB1AF29E318241D91C4B23BD80549CD1D6E0D793E966A8A7B755552F16D3A1146B0CC6D92C8C90E97D7EC8EEE7C365697F93AF257BE24691E41F2AD26BCF47D52A1B80F5BE1C658616537630088CB6E227B0EE6EB8DB2FEC0284E58202A73CF3AEC16BAEB59D2A6E0257F0ABDE5926D9A13D89A8B2F69695BA3682E87A77DE06FF54892F56581FB16991654F60EA22856D6FF9E0BE2C4837F0C1F6C54E840F67A75185F0DE9439AB1E37D4FB3E9757B0FBD17C89DF8568755567C390032DE93E9C93E6C89B2E66E9E9D96616919D9FB461F9F33"""), - TestUtils.hexDecode(""" -02dede66fc74f94ce000d6c4898fcf4464b834b848d2bb2d98d3a5862ec632dc9636201321c793ab26e4a42ae4f13debf105d087b112849946c76b54b801382b9727d65bc732a5620e8f4f158f0c1737b0e4ab8e7404383f76c848b36f58f5f9d70ba14a8ebf622bc848a9bc3e116fd7b2627c41ccaea47d493ebc6d3dd167f79fc6ededc36c809ac87e77ee1b006e96ccccafb88d965bc1cc15388e6410c68a74d72b6632487c284fbfc10135da29f29264cbb9ef620c2668066a2fa80fcf2132e93a29383e56c8bd89b3aaf8a905d4e60c6f8002132d38abc3d3c3b6fdc6cf508c8f6a7cfe9f78be8445f00a13414e41c27ba31efc46d0e028b778ca57b2326d624e3af6be0d4cb2a80e44b3f1b83bf572e8b7516b8e4715376e5da06bdb7d487d6a2d268afdf5654023ef4a13aaee221fdf7b9a668b2f4e1858da3c1ae3a7a7279163ca9c1407e8c0fb69f0ddf75cca64f4b0f277acf9c469dcce264b8f37f9918626dcb4252391526ccb4f068879809a2b115ca1d75d7a1ddbe5c8261531a98494ff634dff81515fe3ea4e289d75631ded8b8ada415f6438ada0738bdf9f89e986dee9c80d82ec13aabf10849dad939e81441fb063aa627c4e316461fff15e61c85821bdd55b2cd1545f810c1f280e7852604be73963b75e33eda2e2300196590b9b77cac44d059016c0b08a2f18f18ededd8dcb1474b3e088a6e84c12eb0470cef4b409214eb47de0e277de2665c661ae7766de5d05bc357a2db50ce51d9087a66b1d3715f5be97a9ac56ef866fc3bd3025738d4310e4761b57b3f901c5165df95385cf70f064a760b37341fe2c8466aca8258fe821308d8be08f4d569e27365dc4be8a2ee4e5e13f9d467d8b6ea272e407386e9f448c1758858d038c18f49dd7f60874cd4059b5950b8e969df6a2400a628759d6d7839488674bc128e947594521a998a7e9aac9d61ced0aa7629035bdcdde11a82ebdee6145af1f9c31ab104219beeb4f222e0f0e155e6b67160f09f6ab6943a589bc4ea4a1eb3231bea73f16da8998af58b8f71d3aab3e2fa736f3307180e6d777bc5ad02be4d7c718855177d7c1826bdf9f3848c1b9b65c6a25a93af48c728b6485ab765d36ebe3fc82104d043238867683169cf120dcdd016156283a7e6171167ed19996ac57e4691ca3f49b43b03aeba25fcb3d5d89cfde475eac580b58291084d8f7d554b463b3620a63bad5c1fdbbf98a5d8200f0e0ff1aefab7754e70e4d666e0b31ba193fbc70d4dfc601464a7642c56385abe64df8f377e2e7b7c451e903a13df6020d3cc7bd73fac7f95dccc9be71af4facc9edd60e9e5cc5c99bdee1339fdde03b3342a4c0635c71106dbcc4ca3ccaa8ae7e0b9ce740fd9a6fce8cd805937b3daf103c246d3bf61a10eea6af21bc42867e471991459ea895bd74d6899da56c22ba33294cce17b88b39691c493d7ca312776dffb953720f02fd814e6b9c96e4e4a9aa6e2d255735ada1d02ebdefdfcb74573c77b4b19f751f55e20a5229a22e326ac75858d7eb4c7fe9a4ed48dd49be353269223d3021365569da4c2cbc3dc6ac620056c5aa7382a363f93b894c0a4fb1af983d90d8127115837531e9ec7ade4a419051d503c1501afdab4d9b9b9a741810693e256e3f03415901ca0eb9eb74083d88d7a1db546c4436e3b19f3be3da87a6e4a7033d0cde55ebc2f7123b750475886244bb6444ea293fe498fb1e98d9ef7b31a86cf05cc660841f0b21a3ced89cffba8cc08112fb9c20a8abaf1e9eeb7fc7c678377ff2edd2e4c4d3140bfa4106f46a8b137c4d68985dbe4b8d67342f409f75a3027dc6a71acfdec2b723a4e1b96a12e42e49eeef5ca77a8961c77c39d5542d5be19511d6bd5364ae79cb254da944281ded04e1e06b7d4de33e40b1086de49543e56e5d7d4ad2e224f31337351707819f96d36db4d3a29018403556995a098cde94138f71cefad7d8dace8a6e08008b22aa5d257508cc4f6a9811f036e7715c67ac369b6d80c425c79a8ee97c094c93dc18771394a56dd527a676d660472b9fcac4fe783500676a9aa6b0322752a73ab982fb28e5eb4ae639033340b9ccc8ba036ef1164d293627c41e094bba0bd851480d2f91ed8ec8a1d4a229f4d08dc25b5b7dadbcdf22b2269cea9c7c6b886ba74bc156590e440a9a0e128a35ec8aec4eac360fd9bb61e9804dedfdbed1e17454394ddaf851c73327022da9456ba7c4edbfe7a0031458088f026830c3695c5d89a60810c2cb6543880b892d8d5c93214ef78d8e7538028419592df1f630144856ea1ef215ef6658c350a50e018cf0dba35fda2694e1efa93cca66931d9560d90bb434501f5f420b8bfa02a566126dc2bbc9f4e0fb929e2c42637de5e2e77e07659ee590fd3b8facbe7847b9400df4bcd858925c15cbf1a385fd395d50b9590c154928cd95798b735faa3acdb4a8874672041d585e45318ee942b3e36711dcc706bda76966cc0100f14014f9ea47ed9c924035e2138107f52dd26bc5d0312879505d7ddb3b468765086169e24a6e1919de2eb169acb18267fd0ab0c468da0ac6436acd2c4e08fb85f134e648a992a69cb871173675e87906f30e7cedca148c00ddae418e07e1aabb8f82f53127635e09cd898b348d4bc5c575cb6656d4bf33af7414bd26a84b5184b9be5e15c384902b1c66a6bf08b16172ed8084de06331119df75913d29ddf181de3bfb9de1242183ee797309ca14ebfd5f8ac368aa72ed7403fbddcac4077d669930d742240dbffc1a2b4a83b043d904285ebc0937c087c9025c0472a2b6e546b6629cddad4b9e60d64c01e0ed4d4bf8e580013e2b215d24893b3dd7629e71cd6c9f906205ac2a1572fece8a7d95adf21ae18f530a6bc18291f22e1b05349abf287d50f1f6724f01d0cb3fb7e0a576997c3cd9c013ddcae7071a7edf496605715568407f86ea78b20e66404676f2b34618060e180e4f9dbfd9a70a1f96acad53deca1db22d87342ad2eead7289c7e481d2068a74e62f9c9b90eb02aed47b57352b23009adc93787eaa74c7b8981525eb077fd502e6c476f6fade93b53c29cea27cb4a7594b55e4ca11b66f94ecd43187fc23d27bc72d0f48a23987fe95b06940a360e9026a022d2ee3a11eb72c8573eea76accc0fc2acfc61fd9e1655c77bd652a5dc40de7dd0182ff371d5a8d3047bd82a69a4b75452dd2f4409c5176b02488b9ce6e8b5c0173d96e1a83e5889ae16b4a07b09afd8f11b9b80f812c9ce794da70ce46cc3e31e24325f5358cc0c64deb9305941c0511ebbdc302c2e362123dc4bb4c9579c6ae2f692949e92a76f9aad182ab69549702421d94c5625904af24a42620f331b8ca6f8d6ce59306517ad93fd6d1fffbfbdd16f4f120540753a630c0f56b178b1672504d1cc0a20bef9d93c8777c036d881a42a72dfaeb14a1a0b60990a8c27f978c95ce44edd72e677d3be62dbd26b3c9bb1ccf1128f79aeb2a41f6ba6d021300f0ccc1ad36169bf63e36b6da9b3a9a6e54815d3445125a2d5078ec0eebd58df4487919fadd4977129aa61ac337f347b3adda82072d758925f4ce6a5125b9e4f87dfdc5cc4b3af5f9589a9cc4969afe7c6b99edd05462d1da3c40d785b8067c4c866a8579fbe4d94786e0fb0b717c6fb96e2e3ebd72b6901acf96c0fb174c272f3559898019a3d87ebd6d9ece260ec913300392b541a1efc0811c10af0671206345b46a588abc932f58be6149ae6591250a8740dde925cb9fa12150c9f8d191163ecb613418058769c54f883e9c0b533f6d8f568c6a907c227d16054af09c6c73676f5b9859beeb5a762ea323eb76853f4a3ecb113ebc42f9c99d89e5869777448a26c40407362a45730621c700e3710a65ef8a49d9c19a2692bbb37c1fb4573498126522468f738da44bbd4a719383582244a284645b318bf7de280d1b9b9829af334d24c49c50fad08a3c1c630a8e682ed700682998fe7b121bce47bbde010fbc9ab70494d5d0b300b846e8987efee9ce09cc1bfcd828f18ea2bc4f40440f89ed48cfb103a80e77e26967b7ec56740d18ee40bfc9fbc6ae8a0d7f46f3bc09b7dfcc590b55e3d8fec26e7f4dbd7806f550519ba3ad64c15b657fc726001b0644054aa24f9b1dad492dadbea8082b176c5fd819a8e73665751578e74ef32779127616a28ebca4be7270c195ac077fd71627faf95fd02f3b6dc45a9f47d3f666c318d752ae08c17d2385e810408d90fe0aaffea328466c5fa82958e840ea6b7ec4f2bc6980db0f3a86461f51cb55dc262ebad5f326533b6bbe0d9c4b283f564949f9cb05291ddd5371af7713a088fb9033bce4436d93190fa742dda242d725bb1fc261925efed8df4b6e3040b7e4989384a464752833f83a087ab09eb0d2be8320ffe552741a5a6b90ac91150fe3df65323ddbfee23f6237c623eb57a44f7dd67be498c97bce8a03dc2f695d0a41e270663a06c67819f4ba401a45886d78853efce02a00335cffa3b47c29b5341f43756fc5c180edb367aa43f104be106d233224623da7738147527e42a904f5a1fcf1d35261139752f9bc38dc992095ac84d03f889024bc8dc211a1b41979ddfe455f696b8199a2e5ecf61625293a6e8f9e36718e9097badaf37098ace700000000000000000000000000000000000000030711182024""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -02b250a84d15d015d65daf64921d441de7eaced5dae8d5ed5aaae0780710cc6f297bde76b46a47751c9af90b775ee5fb60558c3223e3eb5732b02721aaf4b2c571e7ef940126874e4da1e3caf1cc2ad7e27ce78891f1291341fdee7cb3956ab7ea4619840bd86c7f9dfea16dfe4183317150514ae0802275ffa49f6024b73fe8647141425335708465313201426464485346242381251600248884382713606716557375714102105768868264738542155467388816816356812542627664178831841037254605688411724580237205731280866143526825234680318656422704153533366183723757466871843688178028881525836875501828568435457286665223064636185645230082113325530524164585450807060828648444577380467366336754361347002616478552715650545343028378024652505823347436461673212376362234025530852856734378445453462845284101853812575565581884827462217026026422104812154576826272426053254068887115864026255272878171100133062131322881708327412284661110206142314411622224337587412032420350668587700242526761482182726675778500830622782044207773116013105023034233776328272350126302720568518583358656451354230083043841277280712565820402201860064335052181175517311735442231750885473485037215718385878270138340154607044703158207867761262843151363863357713438131822607823220673301000044571035402768713538116316681661333581683446254512203172240767614876605304851065554516305534873744587532285306102132174272346747240832551816548184855245064521871825764413883184880638014732810482403611487478652300457226475201288323730148184350722032842227130834781121602654604023710282810767482168615127440306717714253337676650252810422380412017358174362723207845211345873075406185684783381847626578275162801521336142056152170155712241310876237617136086741136380504866038451845470225151278835071185512660605346805647733377213630110431352442082411744260720818165866163256467725736467210364865838535371781843306701265611455343258201250377030186530054148020488730682653287712420076332033632152360007738566311722306842342001442552108785228736068105822832556448320553027240817753888583045860088518418735447717834455361718663826710688326265670546627753121815634362520041561353322020182806804003170603630646666735317632666212644884747232226042203107541782711326203571075272838712027837538612884105214213440255641088764071225378263327161071701133325304617456360706381304876424815454081020463654588185224521206112700043112564040383368163743670720762520847703261453336085324624132272682450408103756773710773186063277457057200638057521356383470147541687564530335405582586576663835354166674556028404827843742364212470042005558685247530877324355223572703600740553684760470530433178478246407657755282728728664872333848341350211277700011176401760584128238436637505138325505065217756818608062404186640767275603751648614303125612236426720624257485313257806504351724443061164254862845182170346255843504017541208163705313707842235716441111165511437066602366003214233060621717318057200645070765311025637234215854421157547802133221647713605385536202724237457842541827665838172167350548151224528361420224511555686218886503218704567755513515188462180482327014724401365004608425761256824684371031461705077834160654441852347634061406138085734353c75788bc566b064f5526de67e27b5f64a800d39cb62e3aff6ffe4617aaf109673efda26bbf69d235d5ce4a5b9d07c36b392cb04a53fa09456c88242b54e4e96f3b72447d6216178506c1f380b2dc277ff6d09613d7ee8aba57fd05a35a69b850ee29a90c857e06b63e904e73bcdf2908c8940598f4bd78b1b642879c8f635c908f7653df743c94d8482f2f727f9fe18bc78a590bd0985fdd040f7b879e2fe8858bfb442890e584c3fd5234529e2852ef752edd0e24dccffd1ecd9f78e3fe754339e1fea97d49652dceb41d3b7209558c860d82f25df260d8a482b3061dc1161ac6b181a4c2bc1a5b54616d0b65744966636ae1ec8bd61c7d7432cf5c41ddefa21b2d84b3b65208d13095cda462cbb08a9d4cf071fee7b6dffde22532405dad2e96e6b5066af20abb7a6a58c5d656774354dd504cc795552f8c2677730e31ee16f39f9a19351be7fb01716b121298da000653be35f50ddb3e7babee81b455eb30e7cbdd4319ea1af95c5ca3980dad25fa11fd69561ac94729e63d2878209ec3fad599a52f742b1ad9fd58dda60ea1ad7b4df59629a6559cf2999b7138510e14a55ac0bd242e92d12f989254d5135736653be42f86c004ad17025a0a234ba21c0e9d9721b46396d5e9a9b95d3007e59a5673d28d3935bad4d58fed72920f160af1853c624181ae74349a914cbfdc01a50e6ec008263f70fbefe9a939e1ac02f370545237a31abf3edfcd0bf395066a1349a99ea2c1cee48d46ede993a300253634820e60cb6340aa1da98a83178696d21c1e701f92133ea8c1ecbd7dd199cdd7e6809197978f40da4c8d22d1f459a8fd7baa08ccc7c5e16951bd523c84181e3d7fee55c8b1544068af3d3cfa6bf545cff8b7207bc288fc6ce3e6db3404a2e5c85005a515881f4103084128e29858c3fe94fa2f01cceff445d7b57f0d8cd12a983ebfa0b5c857c9fc1e37220f82a2df00043867c6fcaf3cd16cb549f4239fc42da69fc35ff58affeb5d4013ef14531e7a6fa437b910989e7f5a75009023702c1380467854974acf722090a7a8b7721941501a34365fb1baeb02ebf3b9c27c04615c2cbe5ac506c69d0c581681d2bd3f8b8f8af00e34ab4e64f21b75bb443c41edb3909c0f5b899df77ea4d4e0d9f3bf12cdc91c010e94d74e1636b0e90c47f1adb2e6f31dbaea300bc9e3604e81044dc4c00a0ed3883682415099f8297a0499fae7d26a0c7017e3abbb8211b5b5dfb24bebb37b1e1dfb9c3de36eb45bf2e0e9fc6faba5db70adceb53ed5ddac5e5f097e6b97a8a1f328e08e0f242316053b163bc950a065b2ea29996e1978dafe0d35263ed72d3d2748f0e289c41d0245a92acc3f06fe4704fd5df117d02350f01cebf300fd19be1c710b85b956c75707840c24183e28a4b455a3bc804b1cf4e71209086efd7f4ee877f341df27ea2842be106bdc8c57b86e127a359b3a26fc148f754e8ca99823d9055b45572f51417b0e89ef34c1e36d4c6d9fd2fdbda0c2d084760583b8afd08e5f25944fd3133fe0fc6a446b2bcf51e7d3473f498ddd4d50c4929c164ada3149236e0d9ad31bd14bc0ffea2ca972c3e7cd2339eb727fdd73b00a958729b9ee58da1a0057483268d5c0992bd0c49a5272695fbdabea68860b4ee535ba1c94fcaae8d74df85fff8e8e5f8146147fb7d0cf1c267981019661db028779578d772c5d2bde7574db97569b9cadcf0eeff8d4226f687f5d1e65b209e5a9ac2941ce6c26c2c0dde60a8dd76dcf124fe32f7665af15d86ce0db8aa4e0e662c6d1f6d319869f1dc7e51a4cca6f3af028e11a837fc4aea7b00f2cfc52e71cb126944f1a7599f3945348a828c6106fffb5d88ce5a234cb6e83f0a2bd3b63a7680f69ab58970a32275a2aff8dcfc9ecb1e1dae60c3d57dab0f9d5ce5420d5af282e025ce51e7130b86a88a209ceaf9a351ec039c9f1948521450ade546aa06a2a7f77c59dabd381b688980731d4fc7754bb9ef99ab175674ac3de181d5c5b21a22a1d2a54ef81566f2c2d157e68b0cd76a1c67896a12a933c0839c7b1ab3dfbc042e426be112b988752cee46cb78c746f0f2f7c5b77a229441b9f338fd34c7e882eccf38c9b0107b9409bce97194ac94c5e26f5c3b09a9ebd0d6ba206ba8a06291b4e4dffc1511c7a8b8e15afaeb5f3c96c0473d23d693b07435d6d2668d67ac57957def609df4ec6e40edc6fdf2251af26a0b023e7236e4c9b1b5b8340c19d791301dc06611c988e8f1d30dc62232c7ffade76b31efd49c978c2ec271f1a2500e5d48b056c3dcf367fb3ef7d4574154c9e51001fc0428ebe89180a68885e0e3ffc47e273bd802874d876c9b8bb1da540e3779b1a1069880fc2b5db177cac551d70a780c4c24fe90b9f252734d0df53559ea363f88101d584dab86977bd9e643dec35a6b98127aabddbfb60f42dbd5fc83e0ea6fe8dd3974f140fd5aebe7f96afaab7f16c49518aed0711e8dbe67b222029c3ba237a9058d09cd740c91e11ae8fb0a343b85d3330ad680080e52f9c7a67cb27c3d6f9f2a8b69c0a65b27870d23987414c968652475896d420f13ce0f511d394774b92a09dab3c89770d0e30fd56055dcc88b6b25b6f42a30f72e37fe2990c4b2faea18bd9f77d0bb712ccd2635ad98d5051ee593f82b2942c520b64997c2271621c335df8a36b4564ca3f80b02b3b6aa0f5317f7d4062b8c890ffe003be32db5607333fef37fd415a37fc7e987ffbb305d96a6bd856d09eaf7978b9f8343c340c477927d82727e91110efdf462132ae09b40101a3c26e9657b777e74ecec165986fd1f392e5c5ef1500d5e98cbb3440075734d0fd38d05ced139589b1a42a1d32de2014cfcfe5b32ac85473d7a877978edf5535c93a2e447f76972ca0d9fa1011d6eb55953ad22e67623cf59ddb2e1acee6c0cd762b565d03e547fe26eef6eba891de2599c1b0825fe70f2b0806959947ee2e956537b7840d982492aa295cfbcd3668203a3d02de4ef54f44e82baadfc4efc50ef42dc005b3dd186851ff44003b74bc48ae4b8c8a431d03af1cd23198e4a8e2da45d0b134133dbd124dccd3a269d64439e79753c4b1074b27a6b99b0339f5630158641c07001493864268ab8409ca6a986f8e7353f0e1cab155ffc60f6f8a70db47ab74d16e271c0e669c2c8c4630470d1397aa40c3040f93fad09033413d96ccc2b1f8b933c7c4d215000e5c4e7c6dcfcb4519e59122a80506b96a4a00dbfc7c02fc29a3360feb00e1f5cbb999f773c1de0f6da976c62b5ef787a3c08f07db51ffceac046ea9dd8f5cdd22eaf7c2ca3be7d410dd87a477df1a8838eab8ef72ea38e5d99c594b57c2f79a831db704c393c29c9659db0dd1082c8df0130b8b0760aee0685a289d8dcdf526f3bac8509cacdb96625af6339664dde755e74fc8acba8b6dcb57d79beba260446e6cc33ab2c27263232db07ead25fae4b2548f652cc193f8a0e93ef835e15aeb18e401e3875ba4b82fac32cab00b3b4abe14a8bdd235971fcfaa8b5852152f0b"""), - TestUtils.hexDecode(""" -320D1B2976A4A4673900C7B75B23EDBC25B9AE867FBB79B55B29B3780EAE8C159A3AFAA47CF1D9E452CAA8EDDA3304BBAC47EFDCF96CE92DB1981A5088F731E1EDA1EA5FDE9A031595A8F268E92B4D75793C6F408F79B78599D93E80066F8C4432911828A87EF71C877F55B1F18207F01820C0153B647205CA93DDD6B78B94EB59E3EAF01B66953951ABA4027F811877B0F60C9A5AE6281D82348E3EB749C82C81D53309F9B7E624BB1BFC6382F43A58D1951F7FB716C08DEDE4A8028B50544D0F26F7B9DAEA0CD075C3B11B7315022A37198F0C96D752798E0EF406875CE86C367079841F717261A2B6570A8F4F9BE1EA305E73BC8BBD88AB162B4D4BAE86CCCD406A0FF6ED5A968D4C985460FD8FBA5B3FB40E29B6ACA07F70717A0700AD3A0BB7081E09F7219F3F8829692C3DF91C90334DF9E89284D65F7406188C9A1EB7B5C491591A20EDA9399DA1AE8C0C158588FE1426B763FE9D11223FF7A05A3DE036B67541C2811AA459045CE73096F89E6BA672CA7A546D2B0554DB35C547AD9585D14485AA812BFBC88F7B248E03F2EC57043F4DEFC2B27A3B20C2EE7CE334D428EAEB228350A3ABF4628C2DCFA84BC7435818F91CD67F70F3C7D54E2C205E55BC4ACCDACB354470FD5C246F32A542106EEE0EDB38F01FF5C4B657C7C1A00718D2BFD311B8BAB6523351E93CCB44274B8F96EE343830148F5C8594818777C1E798EFB45AF1D2A75D22470B4D7F7C7A5938DF3F8288A0088719C4E36018D9993F9E69B8469E5F2ACF1977D441B82E5340E5AD5B21B66051513553BA1BA1C1D5F788C47CD3BC60079300F6E3D9F13EDAD4DF8521EDD022031A3D74A6A5F32AC6FC51C67F920233C5079A2B44BA7B8EC6DCF9AD4667BD26BD07567E078267A1BF44B15E68B71AD38226EDDF138D2A599944F70D47B26F775BB97D9966845AB3E6AEB96E1414D3BDE94160B6DF19E03BA1BD0361354E5078B3C5733B740314E2DCCCF8F4C9CB179DA62D5C982B223CCEF5F29D7B673680DFA2823A2BB279EA45D98CD91BE7D52E3E386B98B62DF3FAEDF025B55F49EE6FB5E8DFC9F70A4F093EE3898B25102CF3AA52E669D6EC69BF6C79457BBBB7CECF65B1E948DA808025A242841FEC6073326BE16C2D1953209F31BA4A772FF24BC30376EB994398D4177FFFBCF78C9A79B7F1746D077AD146514A2DE0AF9800255F3A11BA661765A7D8E8E7FE5FA46BCD1269E278555186D4BDDD03FEEB70BDFF7E5F616259ACE39969CABE8D4F8F23544918516C977F84C09D6A6749B1CE719676378E82F9B4E563D67AF7D911233F2527B5CC5D0733360CE15A173F10B91360A3CFB08EB44A09157559A0CE8B661AB4A97803C52F156627C642CD02CA5BBC7648833F2CD7E99D2A7AFB736E5AFC4FAE5DE19ACD2F5CE3E3FC887852758411E8C7FBCADB1578964445332113F963AF3E944286DC448471125E55A46D2DE35E9C0F6DD10A3BE4F1E4BDDE51A16F4239A1F6A535D3202055990606C0065C542297D490553204A6E3CA16A7FC9A1D77191E5C01C1507A332C659FD6B11FAE088BBA796F18886195A2B8F5B0064D85F56FB7256F0FE70E9C06ED18B7C8A75ED97A1DF482908D2E3E8D6BE8D0EC8020451C687D10F829257F3D09FC47C7EF008B89E2312792A25EEDC71E9835674CA50235E0A6C832E7BBAB458725EE7BF65D26A0501C91835625C330B0F8B4D46A0762F7773D2415A0DCA573B47EB8658F9EBFD26D9F6EAE9D7A7304BC690F8D2F60C33F8A7D19B52F9340BFCB2FFDC92A7F9ABF85E3352E46ED7591F354A9E19B70A3B247E3E4295E45B6A2CEB59B120B6758654BAAFED2120B226FA778FAE5350E756741093083E4E56A84B64739695C1C09EE39DEEF11D7E5BB7866C90FC9C96CEA071FF82F145592443BBCD6B7CE848839B641C4522016945F711E86152820275A6E16BDF296D34AB38CFF06A63756DAFF7BF230F024DA00C4128F025F091F4341620E0EA883042BE731E82D21DBA6EE737D90346B6189697CBF41F7C2BA7C9CBA20E14D26CA578FB05E92798D57C0060951BDDCA5D96322AF35D80013B48A79AB7684E1E1B040315A350DCF84389E54C054AC4C3428123E01C2FD66FBB2C5BE2D16B22BAB805AB59DF205B71764E4AC9BD4B2D872B8905DA230623C65DD235FEC253468E53928722D1F04C486B46E63FE63441F11B1E3617E9765D4F388D4A2B68B6C86C8E20FE0F3C48A561A0FF5070455C43A7FDAEB58ACFD4BF51A1C37B7751ED37BBC73B9C29DC4FAFD0A8F5FC98C7FF02B404AC08A0728FA82A5ADA4EDC195E679D88187F58004844065F281A67FF0A2BE0AF94D5C97ACFD43683AC721045FEF8C36DEBA2E3EFA248DA65837046B62BD6CCEA84CB1211C5893B0C5F0A5922A989CF7ED093D5D706657AA6E79EF3FAD0959DF594B9CFBE779"""), - TestUtils.hexDecode(""" -c344d3409be7db98ef0a349092d4bfa68e022cdf72abd10851fb824519086e7cb35ae13a93132867d90ce67d9c99315a3c548f7bed393d9eb71231bd9cfd951c53cf8a7555c2e8899d7914549a5565d8531685c7a02b82f3b95f38fcfe9c24118358f4dc4b0bad89c5e169e8f71e97e5f874bc8dea40c70e9fb2322131eced692b164c011d04844f0cf95a663a90e0409f2b36d8d936613343f6078751a082056d1c077fff3c3e0bbf5a9edac10d8ee0be319df29a998e5a52f06dfd12c47eaf72a457b18c73bce7931b74f28e2b3ca2037f0711b8a4755a860fd79bff06218b965a1e1368128e3db4401bf37185421d4b080e20a017f9695feb484b7a4ec6623cf5f82d99d1e0a3873d380cc5ba715021cc8b24f0839d10eb2b1679098330d772a081bcb20ba8613bad19841b411cb84e4f9bce9449b5d1b79922733e0acaaaf3c518d316c63a51ec49f4a5f30671df7b36e3996201fc625c91ec7cb621b54f98bce47381bc062be82eebbbd2196fc8fb1f26405a80a1cba591820c6b90f9374406c97020e0d8bbc4cf71d5379d54e3412f69d19b59237669e1751355c1721d097f07a218214428348ccbc0c954ea7029dc6aeb605ed6fa8334206e230c39ed5a836664a6c0b848de5c6a219a63ff24264ee44ee5d9f068a41cfe62cfbf885a2bb4c71f17863f5172b9b4203e9e9f21e0e744807277cabd3094d2727d78f930ba8779af85026e45b809b8b3ff259dd8511981e7955924bc29d448a5175c7742b7a1bd7db170c55a9831631267789adf7952fcba1391fc4eaacb7c3429f43a2b634553d8fe47ad9f39f81e54b0461061f6f67ab6b72a25e99801616737e8687c738b45a8ff6f05f6b5a30c8d87f6bb4e2d4aa82ecf9f7ff4d1a6d6b5ba61661e8a75d4dec3daa6ac96c0abf7ac09da08efe3eb73ec0de8ff231078bac1cf98ee9ac6aff210ce15f8cdabb143ec77860bb090463c0e6b63c0b12249633510404cbedad4eb85641630cd131a7897b46443008e79edbcfe471d37159a27a9622bdd6e34c1943e0b5ccf35d8885a9d584f6a54cfe7b1b45162360b573fc19055f6ac05df20662026072faa0f0fbdcf4f9b7d89d77fa0a3ca7ea0d857d0d9b94e95a406bc039799ed56e076114dd9f7c8c028c97e2bb813d8862da972b069d7c1e251487472c291baa0c0a9c9f349f29091d8a4332a56084e11296d1c72b7014045ee584056e9822b113136ca9fc27b1487f64e4fae57b31df3e6e2728fdeddb4437a8257af982cd08fff4c4e6e9aa82067182290da938b3b969e5ef0d15717f0c34130cc2d9bd29d9a4ea6707c9a45830c66a2598d8678581d9a389bfad0e34c3cf45c3596aa986380458c5cffc1dc06c5e143952a211288ef0d67c7375f0d9f59ef10a55623af7b6d2faae4802882d09cafc9da95e7e0254b147fdadd9b8b28498d625e9b0603c9e7e0a710d34134e6b4d2e31003ba30acb30df03a913851d5191adde83fb0278aec64262de99b7ccb1c6ad5358651f336083f59089beb924db5af90be237520b5354ba63393c2514f2f5c815b694258cbd56cb7caa5de34986f214c566305163782b9a67db2f1e51c0172f757e3c8d9804cefb63df98d4297555aa95781e8c1114d5c53b06491b2c4463790030d2d28d159c071c081286071d95cf5fc624b69eda6b2cee5d84ba30ee0b4357eaf5429c26fbcc455357de8730f0b50aca059334ac5af33c7169208be3b060abad80a41d5a720e262075442b1f514958120dfd51927363fb0b43767f3bf4ba7bd2669f79d9ae38c8b244c9a1334f802e7295c1a5b2d236edb5ef8eab028dd2bd8fec9f0ded1dced5a352f55f4b502f5aa12a3131bccbc88a2dfe990cf2cef02ae787db30e8bfe26079bed383e363576ee704e2b2b3b6dc0254ed4039bd0155fafa471919703f632bd8623350cefdcdad074337d5ea637a95f995141b21fef74b93be8fa18ada82dca3bb6ebbca0544d790ca07c42086bc4908a4dfded5d0c09e8c8d4382dd30fd6c586d5c379fdfb11f69faef1dbf46b0b03432c0b9967e6c7417b2488aa22682c5ee0fe6a08e90d6740af02f131c5acb53fed64329f8f108f53d762736519923ab734654f968783dfe8d13d715e9db219ab7441fcb739fc75913b20334155dafe6b85f28512d71a02e463e8f58162a2075d301d4215c61164b5143f096decc998b006051752431e1d1d7d109f92c986c40d2a8f17ce6fe1c32c33631974e47c73b5512697f5e3fcafcab2a4f8b462685fcd5c19decaea96d45a7c3d35eb6b81d52d3d300f4f94f2f831e3412b12429b71b46253c83d849250072c035003b8f4c0c7376e502183848ab14ed9f8b6ed1c87d554223fba1bc99d1d065cbb945de8968fe41c161c301b3cfb9c181ef3bbc120cbef645da02c295d6ed66925802868bc8ac6b437550637e5a16d429dfa4b124c1f1045174507f706d3c01f9343ec58bf79e5611109530e2543ddfaa2fc0641c69ec8f3947b4350bef318a55998fbc25686a5e115c35db12a12e77c8dd43863c2c024745410a0fcf1560f1a902bacc961d931f793238684944140150a99f2894748d03a83e030ca52fd83fe43bb9b7fe43a9451f3850f92df5e242a1e75c3a101efa727667ac45164c35fe7143b4ca2119d76980506e8981c4990c8f391a0c9416647554db2c46256f3e56963bd4f7ef309914dedbd893fc6855caccaee377d70cdd54c64ccc3e3d1c0e197684fc692e9d64be1b07af246bf6d2e4f38d2e8844e01efdac0b24dfbaf32f08492a99b38486a8db4661dac565fd847d83993cefa810c42cabd357b3b1d5669afb73274be28d637d8c2de41305c33ea3569f865834effe4ba3cced51fa00ea3dd7f442894bb2ef9a92378ea447fa6af9ab8b3fc01ac45c7221981471aa121d59e77a1d472906c437004ebbb168cca7f518145494516b1d3a1aaec164e5f73a96c244afe367943eca32c4e61bb5766122f1f19e9768c4eec5d76f3b10376191c5d42005a99eef0fe332cf5cfd4ba59f725bd50916348b5704943cd5d14bfa826630a9529744148d9ebac15a84cbf6490be826ea51fd42e505fe9e74a13ec9a1ad546c8c22e8d498ee7a0dd75387240c3d166fcce4d957fdaa53d0573ed995a229e2744bd8493d44d774910625310b4edb8e46ae665c40599c7b48058f104199ea6ce1070a37fcb383ce4e2af436185c4a3f20e186a25b8dbf4dfbad8304125e186eb76b6f6ceb7fdc51ed324272945e44b0bf11ce27b5b6b683fb4efb7e168ff13e46f1f0f4a136827d8d56cc6fed0a9fc8a2abc8f5c06d1dc0de33042c5b840c6d66a8f27331645a87fa6710f9f057685fe00247cb7f12b229a43f539f9c4a6727a8897c69d8ade9c2af6538c594699a9f428a998bc1e8d11adacba134649315ad51f73c1bdc11d8e5eaca86a138ad934b30b376d754bafb3fca13963eb800818592eca6807867d9bd23ec931a343776da195c8d43830028cf4328701faf124a19beaa44293e797c2bb89b2c9db45c7d3785a0cf5c9fc783d727da3a3f20f5366d9f39bf49bd1ef9811dcd74804716f82c0afe9a73c88138bb23babcf5b7acc87f5dbdc0ce1e39540a5e5979ced0aacc221362e2a18a4af86f34f9b2c03a21dd21f70ffd443be4bab058acac295aebc452b4fd32ea5750f4a2fe6260c30eea5bff0fa17f25c3dabe3b58fa72f75cbfc18a84e2ea3d568cf6e66e401ec82753652f44e9410bbc435721a10da1eec613e71f04023f3121df6b45316795f110c81ec9124b9a5568c08041eef364ee59b4eed261f3edd834741845ece57fc5ad1f50d183d03c0aadd61eddb2f13c46093082182b21d4bc5832081fee8c81c1d9a77f132e8e5e9f5a94650222dbe47f5d7f846b1e91d52f62609cf0420446b55ae4a96c2bafdab6a8793beedf7a7ee9f678a099996b6d6f8221427fc86e1a260d7426ebbfd7b9f3e0b9029907b00cf77409b24f73b7f21fd2030cdd4e36fc09322ff6176f49b6f3492076eb9de2d79f41316a202994871bf7ff96ab0cf94ea11ab959ebb4fbdef3813698b1c78e13f2422efa15198dba6af17ca9b2ad199f133076f9ffbe8496fd28e003575579d6f62c69a237c588ea8bbac99b32c43393b20112779db5f9989c04e9530af29a7cd959fa4eb1276c69d46a67ebe363d635aebe19452416e01db478ab32a32c6e95d43ed4693d51f4ded754c62f53524d4179dd05a102acb6e7057c63aba9c8664d9140f866a359f755ca2bb4b0e66b3794206bfb311535810a24a6256a8c0c79c4a87a8fd40bcb9bc23321fed6cef599deffa6994cad1bdb655eaf85d082cc1c626727918e63eb27521b6de4ef5857a2ea372f64409d4c6885d7eedc15c95aea623bf081991890b8d5673cc9ca26483d6b7bb88fa61b31a13f114923e7332eb2a52b9c42b7b341ac6495d1c4fe01f627350089daa8de8cb8b4c660ec9bb065ce689d965e14488e67976502337f1de27d825cb3e6f563312f1a3467e1d2b2628b5a3ebe401b6533f549263babe79b0ec66132bbde277a1b4b8d913b1c378e864d3c56820b6de08e3462882e72573e8ae08c64861669ab8e92b575c6e7fd5db3a698895d8dfef064b5fbfdef1f411373a788082a2bd0000000000000000000000000000000000000000060d141b1d23""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -2bd5cb469bc4c91a3b3064b58eac4e6e03a617650702c0d2d7a74874743bd42ccadfd0a0426a18eb3bd2cfd8725609ec1dd664876ea3166bdfa5661bf98aa6bd4dc43c4310e2e2aba9342cc140161769ae9a63b145fb51948db18bdb445b795e36e0b1dafbcea3f1511748327d816eaac6223285317767e6662cfdbe74165a1f837627263848874756877165276577221012676651444137680132351130784766788147465478471367074350475415218011258206321522104032260216358087115052487816640447746366553266721274514170003637258758343506047250725516568524230380681128162115337361701040586852051744264103454573305535062334537784484077656163074677272568625252463165155875317358360146115625063886554172373584244342527435771442357733353661235042676104117250321606683502032000304787780284453048403518686437812433703270542350835714767753404446076203235271085334487676035830264555553820638166783022256245427730457125514514141754877787346727386770507351017331511724787024054365575235864224380446106330453668340626638555373327516062516306886475621371718244701207532814635187371248030251086845214367337305121680057762817347221343477236268755411121538120032625527387087820444367451140486361827338170805820871463737404481676878720218775500220783387826711830344223526751174102542172057377317130427127801480471835257171264437133768081188782016312740871764452200326044135076454347426856278612352770234227783765776357757573058200813686182602844752021610350156033010746466432146177667445420481264340135175072877232526365606487634201345884304360040750110731501650471000248242232213628325476255740664880703348565832321588525453628717041246764467867301880535846172546126865811071742130263724618348008631416206332005206121853267247108855712233132683424345244848303807538204405258230042874387023163681814017812032137307221648277008410212678058052583746378836842645158534814724670837823578171856506780408155350888617676567180531567033882322162555145138678874828584823364454732222602030751015404558527231541350450340703321417116030531380476526278516178561184083623485516537445054173805185443648434260361525335872750562508727141471515701062834537455105224861345443200067381243725158316423820424705434846600327113226176138138454231433663300613423772776824764225234116254171433001668148037672821722303011538105181471258064724308067107564661085382384052651662161671371345002406584155285674885115884255623875833515644444012106045031335230435125421350485781633764533072382585016230120814462005013470878246287428846070527816201075813467457643587442707224786278733035472163083440581148234114732088143538867042226061853513505227741830721305557406052855436154702188382365521173365277022316072781138710386701325360744315647482770676701727178207307406733252332236826413631243466755010000556060201513176671172088364088733451430652141371747471387788002657666744184645502366471414202007085075162567246527800734147856021313101363062687280452240370150345431545834251037064708377637257784423423561853746000277450201775363821445037005416848448528210732571687768775128345304188263680432021232840435830262414877006657477861158627541208278123144738555315743158402874328317821771457820661201658137582861032041e31fdc3c1b5655d9e975489b7d89e8323046b49a6cf03abfbe1536a5ded60ff7c2f6a4623e6d40fcc62dd75bcc3ff33da3dbf4f21aa7cf1fb38ed42e330891963d504b03020f68a30bba4e6bc2a91d0be9a1a48553ba44d362ddc405f46c426c7342dd4f72694f49bf36fb98eea3ba0cfd5429733aed165610815437adab5aea371c1c82e9231023d2770da62d93941374d5e130e5cf7f57df615313fbd2fd93399b62f09d97e9b055b8cd8c179836416d27e6425c888b64d5d4343c6a5837740cab52c9271c928c3647af1a120e567f3b1c312eeba09002f3ae4e90e96f1fe80c005113d9bc1a1b7e755936a9fc22e670bd36a9077b263a7e286e8b0c57ef594927ab23d88441ce3b2a62ba3e95ca800bd30ea65d0c8a443bd060be70b49d2a1596f29ba16df338701ab6da24c06da858d8be565606e6b579ec8c1ff30a4819b04c83ce8b84018b26695e3e5715f11f9fe2427d0974ceb701b9695fad3cde0aed6d68c8649387cb9eb6ed4b7814e4ac262e44dbae89845e28b58c2b6372f74e8dedb43c4e68717a3d3007fe0e678e1627b3e3ff2a5e1cd2a1f6dfe2a43c736effb67060c08b2b000dc995cff9d47a8463861d088cfe609d21baf712adabce3a30c5c4eda380e61eff53a5341aef7fb5be2fef6c9ff5a03bbfd314eb43df88f20d40c8bf8ec86f4d268846e34585c2c7e7983d28a6136d1ef222ec3754a1ef0d2a155463275ab103bdb2d1a1087646ac0437b15b838c883f2b870fb1e324d20bcade9a80c08f306c2e7fda542f34a3fb242649203df14083cc9cd801e4a9576c60df4e601a477dbf9c1417deef0d0e8564980ccea153af41baf6c68ebb772a8377b222851a015351a748f5ad260fcec7bd9e3bd4651d08ab9475173c98f5846702bb68514d4a5e486e65b09f163b11d29b2293b127fad2703bc3e95925186b6c439c35e979a0163608900df4dc83f28d15582f20a7dd8b4a9c3fdf6cda6cc3c6b98b9c09b9823fe9be87ecff183701781933fcb4e1b877d2e722a2647b8e55e6adf0a498ccc382a27b0fbddb6bce5242ce1f1b0e47ae3f0a1c2a4c49898c56a3e9c49f4d53d3825e0948369f36b4c6b81be9b1c5bede763653f7a3967c9466a9b4dd0cc826d1ff276181bb770b9ce59871e906b5e3102ca3f6e567c6c275958442d66407b5f3a899814d07a0356d168596824db9c84850291cfc7cf119424949a778275deab8a5cba7926d07b82b6c6b296cb433bba7fb45b679c15a6f177562158f8c1a9e54df79cafcaa7bb6e002952250fe2d533bc27a9479bc03db36919d90ae4f074bf88da84e651cfeec8715c918ff605bd60c4bf3843816c7b30e11bab3537f14253f100646c7d0072998761d1122485f80b28bbd24fa0d53aff658202c42efe00385c778c611351d152b353e3265baf90808737271337310c0e8893fa16e9725386737b64ef5e41fb080b65102ec6197910700d309ca7f7643885163be8d9bde7580e591480f0de498c00b22b810f76e11b4b656df3611183c36d17c204e34c18f1d2e2946816506b68647b5cb4222b27499c4a66d3fbab7700a7e1f1419921a19f39a24dd5a905921e7d895f1289a0f07338cc2a72a50c95b2f8bdb3912929354d4945d4c327e6ce0779dd8b126ec891170f073fcfa03daef28f0e3a214224e683141199b25c31b0f47ad1c58e1b47994f2801829842b84dc5d583efecbc528181a39857dd19be0d3cfa07f3e63b358eac6c2786a1aea7ff5ead542985f42149a98a1ddb89ced1279dfbe56363946e27e8ce0046ac2244658c4ed3b97a18bea6c4e1caf48eaa7536c65b936af37fb3ae8f78adadd1588cfb42cbf14b9e30e0a9761fd8701953b3842da1d567b249a1eef29fd29f2d73e15b34eb4d1f11e0db7286303ae426ac2f84dbedf6ce07c1919f0205ff59f369132e27875a2657e6d560e74f8c8f3e5af044585f0272c1eaec7972aac43baaf68e884dd3f88d4ab66a471e4fccfdda4658068611e5f5c33756ddd38ee0023ad2faff603cb0f86659560d10e7845d5175a88c1eed5fc9f7beb33315d2eaf0273829b26ff6f3b99e31adc4752dc5cb651e8de0974ae5d07e38f08d7dea694b56a83c47731b0e14269b4f68cdfb66a5cd33b53fa01bb3f15660b7f21ac6bf82b69d8eefb52b75242e7a2879802bdbcfc3ef969ea12ea287a7a3cc17149b2271012b58d760e00e7b36269560a29cec00cef0d979366fac58fe69bd30e80c051d65268c7e8e50caf51edc9ba36825d7b3f9edaa2b2314bb62d0c244d78a52c4d5e2f3114fd1291bb25355a8cbc250931aacfc716617c884f74c2360fb383a04d5172ac24c7bb01ffe26801c7e20e4c35711dc0d4e9a22de14e047a45aee60d5cb4589aa53979b51a73f720966dd1c1d714af9e5179cae4e760b7a4598d8d46988777dbcc759effacda8075393de7403ef5c1d405572f8b49641799b26db4efd1f2c821b453c0704134a1215cffc835b5a63104cd0110d455902361ba484127cc84ea642405e73904b857e4c94467fe322108f5159eae46449c125ab62bf864c0daca0cb5ff09067b520c69c81ca2fcf59d2bb924ebb443296126198a0615867ceab2636b98f87495cb6f732868d29f27b6e1f4859aba4a83f172ce5e73385f075ff3c37c166cb360ea16dcfdb53c8d29159a65bbad099394bd63a5d3ebb2c46f003424eb81889090876b6ff0a69a18a438ce6989c465d5e32ee545558b75a28f51622831cafef18822100f2bc5b8e45e495b13ec7ee150c02112b70cbf245310344a6341072e48784f01cdae1cb885b1853de04c43121910ccf30c9c24f491e56db7538e99ac00bf0224eaee2e50fa9cdbd0679a500ca1d835ec1a129b42e88c11dd90f84e413d0db6a22a21d7c090d641c34807145bb0ee35fdd8348b75e045fd7e2136ae8bad14feeb2581e862d9ef964280f9ffdd2ac55ce4935f88858da06e683520c9be9aa447691e3bf37c0652b944f1b1bc458b6e67e3b760086e274089ca9177970a5906d45cb50862e5c30620be6943cd075c7babb86a2aa0bbd9fa06d5388239c2606edd34e729fd78a76b597af751cec41ca553300d0db0ee933239487493f606f6b8b5e2f49d87e061d56104444e23659da7a65e6bcfb2b767643183efe835889452e94149017dd16271f78d50cc74ca7e259e128f02f6beb925a9cd8fea3d11b105c11620c10954a744c65df3ed7ca978994b85d6ae53a89c675d58e805ecab90e575a9b553e3b85507a190a62b3e59389892ff078b0d5196469a2c4ef1edbfbf64ec4a917fff3f7361cdb7a31b360cd44a129db7fa091c3b87c89028e49d62dba7db65326ff9358dac88745b1be5975a6d519be7c9caf432cf876bf1463632bf4a9bdb67b1d6a16a7c89e2845af39e1a92c73aaaa39a917bcaeb3cd7b7804829a65eca1a885c08d381e4bbdc6b8792404e8bd273b2940c60613467e6e2756d4035681de14cd875ab004b4df747c4f6e0ae913717ec7054c37b253320e8991bb9a"""), - TestUtils.hexDecode(""" -C9ED9B897C34D7119115A0758332FE70D4A9E11FFB2D6A800AAE33F85FAC59E715AAD93BD79DC8D958079F3B5C2422F8FD1A1AF9406E8DA3297226440E30183051FC9AA52AFB8BEEA2228E88D193F231F2422977DDABE4AF4F0437628C6AFBE68F70CF4F56153A2691F7A4241EDCA760D4B3AE0A17A8A0214BF1BA65221DE64647AC6578F4C7E4A14C401F7DCC30A10A695A7F72B04393F4E9C4163AB68667B1757154BFE711BB54255F4DAA9D8AE6622C71EC8ACE5BB79C6B4C8AAF1B0A0099EBBD07B292CD7B55E44ECD68DFFF4173743145B71F536E7D23E78C63679FA2F3C72CAADEFD5A9471280CDD3DD8DB83F8AFF14FBEFDC8C5969B050D263EA462C28CA64362F7F165C3EF427FE5E90A83310DCB07C9612E9A0B8EA1D0631D84B4A7F1C7485B0C91C3B7BBB0EC98D353376B692BAAF24C5389D50250F3BBA82173DCDB52382176EC5CB8BD531DEA049C5B815D788491608FFA2AE8BF486849810AD89BF0352ED595E4EDBC0B81467D72944AB83C3CB2F90FCD10810EB65BDA18C43F9A9A5D98E714BE992B7DA02E9F7C389F1A22810DC0A473F8891C43932E0F6B5D3A21C3B611AF6C394AFC576C07572DC4A1E56B4576FE615E516F48544D099683EAA886CD41DA848567F70C2103C467D271919CC5935605C0EF05909635D431571E5A316E299E553EAAFE9C7CBF5063E2057D297F60B5DE1C17AF6B97192E840474CB7266A76D509A10FC7A71721D705A9DAAC5BAD8A52290C1D8DC7938663B24700F992FAB008CCB3801258245A0F5F329A4FE5553F4130DFB1D673338889B357FBF11681099FE9BFF18AEEBB31DAD290C1401D49CBBE38277AAC8A99C8BE4E6EDD8A0F3C901082A789A1037768AB7C3C704BF1C6E890D20B3DB6918C477350F4F25756BE1742DCB31705EA9DC975DE0C38C21D29B340C63438268F6CC399BD644EDCED36A7B50E8D65A507BEC51A31BD136525F4E7AFC1EF9E0E6325D032682EB4AFB7FB22F1716EC6F4C9852054429B5C5FAF3BC86213F6D800281913D5722F3A380307B59E1CC290EE66FB9699FFC627770B52619256C7B76D993FB4024D2DF0602F102A6A1257A200DE1F39DB54614FEC2B60F3728F59482D71C7E5BEC36F0D90D6FB0B4FA252E7FEC4F0FB9EF539257EFE87715ABEC75B2A5FCCBCFA5666F1C9BE2F0489E04E63ACBBB239EA8397FA2EC24C25C538BBBFEB74EB8E15FF93B0FEDB7F36FF67F7CB244CAA067EB2C005EDD2AC9E0765DD38E51E7C71AB72B056B230ECAA8985DCDB50439BA261A0DE57E68700C64655E1EB8608BCCC33480ECFFF1BB75D0AB69CEEA8F2E3E9515331A1EAAFB9BA32AF62798DF761267475DE343CFCF5A352C907A0314365B8CF6FD2E72F2142018C4BBCE4CF0A160266DE320EBBA359344A60D32CB135F5FF943173A3F9C7F4A68489E78621401425E5B8E6273309FA3313DCBF13D7C69B63C1EE34D3200BBB4CF57518A5E66D010984AAF34CA9B7DDC914A3AFB514FA1B9D3FCDF3324998D0D9058FEF10C30ED6B381C41DE363CB31C5107E7C00D4C0CCE485DBB4CD2092CD929E5717DB8CEE4790A48475E1DE9178E49B13C5173B6F301D5B7BFF1A9F8B3807A5FC84DCAFCCD8D585B77014EE285074E64448589A738F1323C7A865C3DD482499640A3F166F38E37C6F9ABA8263E4F3D1C2E7D7AFD16BB02B9B4BE8A055452071F278C32C3247DE2BF83A0633BABE7FA048BB18FDBA27022736615"""), - TestUtils.hexDecode(""" -6d9ffac759de540cb67a1d3ed0e50afaee62c1bdeae34e94e8c88d8fa0a86e22b911655d83e0197987aa1151adbb629f7d130a143a3c0f34ea817898a86d76f54ec5fbcf4d0ddc93ce671516be812b1eaa2fe2da29d0381d9d5cb8e702c038b8b8e51d3ae18d0837fe459be7cf6e4967233344749fea70a74f143fde0a0a9582366710648c4f1b26152ca0b56bb6bbb6011264960f9639ed7239881337eaaefd07908359dbbea6dca1834f03a753dc02ebf67371af2ae1a82183f654fe20ce6212eea1aa256b8c1366b4d13ed800e116365e8f3277eb522f2793812329e730f56f6af17cfde3273045aae0ec8188cb956a0058dce1c4d481ffb1e114405fab0a5e9a70af8d438a2a266d9a93332e621231c4ca1d2aa02e417a327a6feda50ac402263e797fea04579ff60b9f026bf7a97fc3378790e3dbc9e7b6cc12d1c01813367647bdd5f8b867c9e1b2d05c870b5935e5f19772fcde0d8116a9ca9d84cd340ed26adc1033a8615ddcd29f86659f3e742e7c08cbf197e4c2f680547099b364fc67b8140a22eff4119906322ea1badd4af4bd008bc46d335569052cf26520938e417c8a8a12c72cf0a451ae2f209532e214bfaffe20414b4243d9351093215ec3ea78a5689e4f89397c7d309abc54d55d3dbee907ebcc6a8ef921ad61c67c2094081d901ba8631745ca131a302fa813c7137c1f3fd66207ae753d0eafb1211ca4e0d247182b3155e12a42e1cce1c415f74677928f7db645889ea70928679c7fdc7e36e43231ec831a6a6b6241bf54466bf530553c268cf5d63b22d755fe9d341b0ac7ab830a303d3f74acbba37de4c109a63a6457e9f79955232e368e9b4aaf27c6c5d3984e7acbb9d19d4cce1b8d53a04d7e137811f10ce33ea05a0b25f0f5ad1499e39542a264ea0830cc2b20646c170495e71a428d35ce3b726ccbfa1499ea716df3a01186e776586d431b90978be9536e5587555aba18ac6f7aa3bd44867d85b6fe9727496d6e0c8e8e776cfe346c5546bd262d30492cb480040c42aaed646969120db4dcf7c3adc8a4e469680e1d5d1092594436655355631bf037a3cd4b9dada49c259e0c6998d466d6f3df582bf86cecb7f4c874f392806cb1dd3b08d3759792875a08d589cd8f8dd8bcb533accfe23001773d6b9ac4dd6686b4ec3ef8cf4335f70d86bd155e5e473666c3ab5b27f069616c6d87f3969a55a80e59825840feb3c82816ca0e7c544eae787ced30e7e5d0b911273909ac11c5f0407848a96fe139887569491fc82b02e70134a1325956e65f02cd97254d4f469455f5ddadb32d99b851020ffdebfec3c83fe99ac4143bc4de6e2341948494dbff83f13603bac25fc5801cd694eefa4439afc61ed048a811b355b75ca4f7f7cbe88debd671657bde2840e95032129f2f40fcdfd160a13c7c123fbc811a7759e86f914288b417a6051393fb564a8a2473c3cd5216b31848cae14dd935b79647aeb287a262a59d37da18b085a86745b2090a83b6796203baded78332e5a76ae6d8920473d268230c00a442af276d11c5179e0b776719f02f4d380861ef73ef946dd03cedc6b7e19c812cf6367d6fb847f0f00b0ae2d5296122bf26553bff501afe0d217628dd44a8a39b509fd5a50c2b991d70eaed000d85343135c8e1f9a4bc703559e08da575ce134e07a33e3f3214d75f959c85e28329aa2242d8dc69b12ea2c95be537b8d1de119a7ce7d7a672c7172bb7f9a5df91ed8e10adb5ca072a493f4199f1135ac519484678681bbc88135a766490f99c2b3d4c6951d3e5da5e169b908a60ea803227fb870510c1963196712d0283102d6883b9164d9c30f9853a799696d488ad8834b6903602d14565faf6be82e911ea41d2cdefafa2506b28f1ee5a77eaa115b91e1ab44b7123ec70114d0c4a13846bb046bfcbfea6097220fa91d1e0605017f3849f9e2be6507fa4b7bd4239ed56961e70bef8daec13fb486d458c7186b99adcc45ddddb818e4947c0e6c5eeada18f564bc664f51efac7a8f12a259956ffb2165f450d728ed5a3c9b4cd6dfeb2f90a7711620374a66510fb3c2b3fc316e15e52a5f91d3e38b3313b7f9b5a80b6b181e4c4fc036ea2574d219f179bc1afa98fc918e33a52cfbc95e20c09b4140367c978532e6be246c8cd1d2c5508721eb298db406a92e77d833bfa7c5865c997b402cd8c09df2c5668cb38b03eb0e86da9707853b20f1ab23e11b6d38421ec2d6882a9121b847f55923601914a11650f02f99895f9920e1df904c6f45715a4c0d7218933149297191f72eab16eafb816d5dc1f59c30a249b8545e6947ad81d5b8f562f42c016ad46f19f5ba10fbfd2a1c22974669c376f496519525bc7ffdd937da7845efd848aa2431344c7314d6eeaed5610ed1ff144794091ffdae46c31fa9e7116aed7dc93c4765b9b72e021b825107e248b988d11aad8a9d466b4b109ffb874f26d6d7f1a12dfcaba5093d60179d1cfd2b435cdac23f6b64cfddd536c55354aaf6a76d738bfc12ccb003a14d19b54e6ddba35dedfd5e4f7f8a18dbdb4d7a8b34acfa4ec462b9a9ac8fa962ae9bfe353ba9ee19d576a320e0f9e22347a84fcf58c0ad61429f9a5f22809b72e91574052534e96832a99db4fe9e22e20dc2ea8f5cc4cb70c844ca9a0334f92ee2703b58b2b09e77c71e27851824c78bf3f4d177237b212f73d6681c6bcc29f12116bae1a25666035313ea2af3e4e98af8f6cac0236c392c39516b610234304b4e4d1d02d8d8e349dd00db7b8acbcaa4c79aa99f711ba693c7e93c9a71342453add96a124e3d06e46c503425a311bc5249034ce01fcda3c5809de83a87d4eeca01b26f92d9ea61616fb5383918e87522bb636110aec1d2b43afdb4258a51f06ce0af14a8687276d67033d922026dd190346844df0974280d56c22fc76fca0132615d1d61bed3facb80f8ccf45ab82121ac3cdd34c425f0efc86e1546f35cf470bacc1976e8c8561b086c52dc71d9fca01223707341c9af7ea6791bb08c2d46a578ba479fd36a2ce79558387afe1375090a53aeb2183294e747043eff104374f6f247591860028a49ee51c5327007d08bda15dfe2de5109683f0c10b620e455d265411a460c3474c3c2c9de9e72356bdbd7309b6e6dd2fd9260131b595630932f46c372a3da2563f31fe5dbe9faac52abd5c842eb8eaade71500f235fe806fd906ae53a2b65a906dda24b3839a0492b206687931dedcf96c57f05c28bd3e1e97731523ee0bfb74cd9367676f142f73d861b070843e772fa18a80dd641f430236a96b294c68ec871f957e4f04546a0610b727b4bc9d46433434e43e9d6c0421997701c5464fd62d7f73768f92645b251151bbc11a9a968b863a2a25de9b1bf547cc6857bb65c3fdc38268b9a89d8a4e49f1c62190812148e2c2617a92ee7003a3de676129e1f6b92b81081f1be2d9715bb83c31fd3136c80a0b23b902a9a3e5f9383b1206d2d8638fb0a5e5c0e2df646235b6a40b5f4f2bc4a13041f44850bb8cb1ef1d525f2ced545246b830547136c8fcfe69c86d4846391d1b8d78a63f50a09ca62ba8c1578eb7ba182ed67975889ad92458caeddd358dbeedaa34e160051b2346ba269003fccc4c3f58d511bc74949b152ae37ef64d0ab0560b8c474d3a1f78b04de729c9f0c4ad7ad2812f037195c85f3d3130559a336610541de8dbce1c91ff95b4d73ca6e4f4023378a5e4e49c8a907cf89b3b71ebc5729b783764a8b9f998e5a299c877cad7bcfd34252ca87de197343c01249c205ec4057912afd681c5062897c79b272c9977af12ae543570f2d8c4977684a2689c627ea4f97a8dd9600a17b6bc10a71a9cae8b18737e3d4e070402d8925d8c81d49854806528d5b03fb90a4a01c03cde8213522cc3372e49fb12adede707ac55eeef0c72a1ce7793925ea6416728a2afd328d2241091049beea09b93158c0835f9e28d0fe34ad0e6cc4cd82651b3c9524e50b6e6e509fba04dcd311b679dc7c82d96490b2f3f7c48604860afd25d38786d7adee7dda54acdef35bf58c2fa5bb0c226b535a9f6230c9428175ddc939fbe2f2191adf27a496644d1004c05c06e4a2e8b82a1910665062c10e6fbcb6d4e49df3e6d17b02cb891f89070288c94ce4faff7709cf88994af70a256059e6bc4df8e2769f9d2871aaecd023d11b44c7ccb0b0f40f4bca202dfb1db1890c89c4121c3a221ca70592742c1c624f9c54ffa3ddcfdd40864836184cfb075417f28a6d5dd5ba9eb4fa2a5fed82c86900dc96aca2342d29dd7208270bd4d6ebeba516fa6d8809eef26e6e929853df5b7b22a66628d9a728170da4a4eda26af530fa05778698e85f02d979a76706b2daa3d154db0872ea5c8b06ca7235305b1d5c1021b0334dc8df6b267760e652a0e1a1fcbd0039d6f585879c7b53a2dd3f664e36fca174322e93989f78ec66ecb613b0a694f13fe2715a930b2ac5cc4ee65a120c3c309b97b8e1ff856857cd88c0ba77aa5557f4184002fb96b35f367bb62502fd6fedea2df3ddb6f4015b018fc00ee6a79ab78c25aacfef26b1d5b1fbcd372b296f320c3cbd02128827678f54ff94c2c5a677193999eb2c1d7f7080b1d4667828e292f373b47696f7b91aaccd4e9ebfb020a58acf20a39586173da2d737583d10000000000000b1221262c31""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -c80f02072f243218956d3770dfa0eee288f8b5372ccff67c93318ebecefcfbdf18881d022533b778eb8b65b8881dc3c5a2fef36a869bd5cf304c457305af5cdda268b9cec761d38a2314eb1b8317184e325be289861c3518cea2a10dbb70a66f2c5f67c71d0ae6320e319afab670774d6f34ff4ac770a48ccfda9b1d8dfeddb5057025530050677416582278274505667301351576466870331032351083264716862836432486031506605800101361627684822632826581466212345526573758007433333477862751355246324087300847423142180181328073136142622170774306280323704618416477570515142514130455832022610134088876138124058114320611080670118018464085050380678730326046531300536216285206033762276762775135456675305781306813144351058438878403307687115162445758762435444306181475864556088114581615805216153138726620282135405184773253214002763042432742285182025418687637550727618630446721381621561150288271788350383608014736387120213568217622652045405551120320576502871101420474433680435304327652662515883127565314215370838830033816150283507766554275413064230572085558518426058845885530120407528323186266567602237370105201014564604774882172584373620026546053363771278173628600720520652860065382001123825403357873050136310704810102517285164840568604863133864655787425780060514544323632362181675425103051333048832104182222534843223257707062722432431888444556263685673774854726073818648517112141628084551561504640265646442511001786808432003757262538078314515135755137018852833864121201105007256358100857612560813851383702108482160852481266481713382031618845286043105732050857858607353564132122344423377458771167748115086680288573474886275656287884524782738240452330508132453212563243264052512022138236723506415274361568172077584546563246848741847227366113853277677187003120672803312751338731535378660130452317062527513307208683812056457672618347100420828582478354158351014326870707345131061078405044837370213315684511333215646478872283027464677328772837066376715434438300243146756128411654274728230883102040147160236612421547335046566446706883215132525265735424774111734410163874662657464330762111581252861488544800081145110813466088381404533445272646402333765551273564033557176722630105714613135526825771388525741752552048313468426860581660618780270076873311738236518776476873827573031770438878487513011411361583071301445561663156520265240035804757477167382832424463451480481240152163665000582805647367208703027114876055755766242113201847066246108435208437356368155043852753534553884800410550611352563613328277231178785005471510106804217363330510438775850050201541533244435247577721612262085330353712227748025886768140455853781817167865520612743051656428875760637056123627868651516386807077756848254735200340838355075611101746703364144574811707376411548585113884075077423148765742857850822700384480233506021262883121710116835788133723704346757345521270442111754166000801666758036038382282534825367627860280876821686044258467073362032026126470206571804580600827540023301101145187820771648116401787587233440067756345560263886241380357614771073381647234280567584172010660461051813086315325671588023055102007554535774637007241602270404175218044451787766283416771207805266403201725203a5a72c38850214325e10e875c90dee2ae6991fc05b67acf1130453620aa0f16b3eb56700a11ae3340ebb059808062a52757126da288c4d6b913956f99c53715f2b7520caa18f15695ef52294bdfd7ebfe3d668ee773d7b49e7fae905b8e16aec6e314362245f4978fa92e5fa66906f875b74ed5705e4374e90ef2d4dafc3348d49c17027403ff6e18d4576e61b21b540f9b89f5604db87721ffc19a6e58e4582cfe90fdc3c8f1a06467125fc6b133619c19a299c2208ac729a2471152f58ab9221fb1f8b8ee99bc5562295e136c1d7491fe4a3272012e7cf23db42474500a6c3fac8f9fc80f5464feb32a81bad914c1034fb278bc6223e09a3b3a5d891540ae563116f2ab2719368627d70100c7156e1131f8778d605ee6da8b78a7681f79e681081c94c2032655ecbc5c54d813d1d3e4c3875b90a5bf28424d0f3aa44ea16709455e9d8b024f5cd288507cc5c4207a85b1780a40421c996c1e385c96b8a168c27fb7dd18b80ddd5cb27e815cc3456cfd285e3a451483ba46f8031e66bb2f26e3b34dca9229fc737f60e3bec555f749be2ce66967f842f519df636727ae2b0ad8fd7054ab44b3e676bbdc087c5e744ed20ee4d70451a3f991a2e11df9309307848714f5c5173234481528041f5c4cc401a59812652e7536f944a124359e24fe0e915a605f8f8cb656e6e29a2c62a58df629548cc7429fc016953c5c6cdfff738359f156f504d514c501cfbcd63c012e6e4a98a96abd0265a8cae4c287e8d44e9198d53c16fcc50237e227787adaac3e53097aae470812d7885e8a9fdec4c683178fa31699e09b66765e643eb3aefb034c471cf83fa6f6b900d8e9b76a25941356886d8bef84444a788103478bb73ec2e0772698f8d05c859dd7e37eb065e3bd9bf54bf30a37bc784adb358dabb075060e9777c74898d576ffb8b352a576252d203a0fd11b24bd73919ce83271e5ca576cb1237f2df574c65cce4051f89ba91e22e9c1e1e3d981e45597488fb23548a0c6f555a148a6f5b520293a2dc1655b62719d4defb596b613be1a131b08e29d3cac60bbbed0fb11a6bbefb006e6aa7fddd6667323a09ecd9d6b39073092c1162682ab5ed6fe878007609d361abc09f61d156eaeb34c4c01d660458c0e31af7f43e6ee71ca77564bca40f39e2949008afd9028e6bad1cd2fe320971e2cadc9d79a2c860a41c658ea8aa2f8842938bcdf8887cca5df17750722c135f92da46d749c43eda79f966449948fb955a39d90a725298566d8d010c4706ba4137aee184bbfb74650ba401a7d08410d8d8634765868805032b2605714f866c169ee247efc2991c6dc62e5978b787352011e006bbabda578ea283f510906b6c641e999c263f53fac8c00213338f021bd1c07ffc4184050a3c07e926d99e10f53b6017d297c29bc5762ff0eb64fe011a2296810a52c3dc0e0d5a44a0f576bedcada7defbd51595cc7e9d223acef03ce265ebc8e47f326a672daef305df9d8137c93786f791452842837ff9db6c480770edd3c1aab4577527d669d3a656b742f89d153036de73628f6d27c7816b105646cc9ed77d602e5fe2cf1d203aaa9cf8585d576f4a73ebcc5185f541b8dd3c0a42c34899d2350132680f1e95a5caa76cb97ca22ac2d149294eb0cc8a53d597fa77a686cf5699620c393073fcb41636d52861920ab80b8fc5eb1716389991a6517481c107055ea08c341c9da52ec48d44e80900038d0fd105bdf79be232a2c2b3c7d66adb018977cbd762c0f2feffa3aeab21b2ed461326b22ff1dfab712903ffd798c819b493ee7651e179873bf28167d8afee704450e826d7cba86a119e044e52a80b0ce31f1fa95e67c7dcba3e78d0569073e38508e3c2327a429030ea59a4384c8c29561d410dc24630a80673a7068aa518b8274c68cf4355db661804b5b44abaa70390dabce2f16b51537956b7356f46194b5056feb47445756d32ea2b853a3879652dd5a77c4c93cdbf5dfb3c94254071e0e054b49e85149b12b8d0edacceab8f4d8d8351d2c2929d3930c1d684ebd797e9a2528b01b249daced8dd27669bfb184de5e3d007a194a310314dd50489ac49bcd5e0648311a9489ea505a3eb26fe6eefdb5859e479c8ff00b719e0ceefacd729dcb9b00be0c1a5688b192594f5b9da5cda8745b925a6d768ad753c3006e644a1b790ea8906f791f879e1b9c90a124ae504f80f0c17ad9d823a794bf0db57a8240e982d9f99cfd9195305729a279f39dd2b1821fe09d757e875d6e9f162612fe0dfa08be5ce075bbf6845623ed468792a8a15e72deb7f3b7f2b44b903b5170e98f3691f32faad1b65213cb4198dde740b87ce9ee43da004160d773747d7e2506d7c41f0b6ac80b1f0a3c9666d864db66c42b8b4c839a2f19b85e3978807a2b0d8522ed3c6d1afababddfc0a06c6d5897daf6a72f62a49243012daf2e6f08e4077312fee54b5ac8f7bb9932c06b8dca2ec95ad741861bd12cbb87f0ad8e2383b2c1aadf8f9786585ec65d61db5f66d5caa23d86778d5d186537b6e65667212709e7dce06b86d88ab40ce21ec3c75320b08c9f92e216d2e3480e7cc9442e73eb1664e081ca56080c3c4570eb5cd51b0a0d7872c95798ab6f027c2c32044d937d05dd72a0ee4ef973dcdc2623cbfaf0925f375cd22878b2f28ab048cbca8777a6eb52def28d90c5327b21924492ab7d1e24fe6a24b37404e8de633fe6185aeb2cdf1093420b847530601330d914990d764b33bcfb7d3fa90ee25197fa585992c9d0726e3ddb72bb6b03f7ba66a888fb522e33a6a8132a6d39b7b83e255e84be3c6bd55714d0d0146647d7484d5737ff6dcd5e9f128434919e0259f8766d814d69811a25a6d36ded06f7a6ae919401383a87fd451fe1d59ac85205efa636ceedb523d39c048f45c36aa6ba72eaf527bfdfcc4d8e99264455274335ebe5141ea71803e7e2fc66d041848847717d37a4f7656ce2de0c4a23acb5214b78009259eac4ef77980e80ad76442c6df57e7507008d51dcd2b49c28df2bbd66f8a6a9d99c946ed37561384f1b981eff93a64d8282c71fe39cacd5cd8b087ffa3e52eea33d88c06944a025edfce077795525d33c75656fd4f314a0f6089375d96ad2bd29a62df58a45af0a03c7b9d917ec56f3b3083da68aeb20e034e113ef67b07b58bd7e49705fa600fb36be0f345390deb3d82286d4d04329fa60ff76958214775764c7874cff5287e435442aefb809fccdfdb56adcf00c5f420e70ffaa04c0f768750424f16a7b25533ce438ca89e33ca9afaddb2136e6b1c68468aa9e7434adf614d0e9d07a729c2aadeee1cc07db336d3bc2083d0d87f0e6b13659184da03434e93028c93123aa1be5f0ea0d41a1fbc6ac2b7987a66693c46b9d4539b3020d5422897d4f2b5c33e802df1de3e65fe7840b793bf0ae4aee817152b00a9f3ebf6a2d7ce5df3e4ffd5d0e35e958f59fe742d052f8119b4cca8f0f7605b2f7f9fe15f95cca1f59b443005bc97824c3f64d835b6326669ef53c12"""), - TestUtils.hexDecode(""" -258FBC2A94EE48B415DDADDF470F14FF8DFC069CD949BB88812CD27B2BC3D9522E00F302C0B72533C9A612A251BCD292A291F3652695D318927CE1B922125B287FFF9B1AA2B79180622C32AC624E0463E5F48E86EB5952CA1A95BA51388760FC5374F0561FB8873018DEBF785FEDAE4CCD1A41820EAE9D7056BBD329E7A95F21A4919A109BD27D26779C3588C9A886EDBEA1FB97A8048DED858B299DDFFECD4D678820E5DB6CEEC8B1EA879C9C22FB7F59B227B4F7C6AAC577767D899B2F11FE39D1ABC527DFA0E656F25E53CA05630215C5CCF0FC071F124E48C57C5344BB103D51A1FF24114426A324BB16D8F80D3CF2D0CE573F4E50DBD1CFD66C05430A1109374CD84156D2E31C0C3F4DE2F1E225B5CAC05D56C4478929E356F7F46032E2719E07BB1EC207B32D241C87D87ABF28C7CBCD38267CB011F26A9B49090008389417C7A219A9F18203E6D907D63AF4C42C60F7FD99C7F9394021640F450A9A072BF2C1CC3EEC88BEC866FF1FB5F032567AE053A408342A56E3068EA168B9E902068EF808916EA58004FF31C31DDC3FCFC2CCC92E0DA09623FB523AE46C8CBEF92A1CFCF4C0F523430E60449E5825A81DEAFB2E26B3131F0383B8FEB4B1B4E1499E89E9C5FA2ACAF1F37C422CA41ADBF907EB984DD65D8314E2F71E8AE616C0518DE9B8331FB00983490483362802FBA242E4CB71056E3256BD097504AD13F577B36A2F9FBC1EDDD25D9DBC09B3401D58FBCC9DDC8E74BBBC897552FC826620060D3777455BF76EDFC059E5C02BBCCC0F05F86ACE1903AF2BB08A962BFE9E2C435EE8C580502351669AB7DF3D9F6B4720A0509BAEA97FEED3B8C769AC5D0997A097852C72DD6D5FA0A7144E08D667F21936F434953EC3C88B5BA2EDAFC4F87BE8BFB5A592847D15D5E5D972710A4A75A5772DA4D9F156563C17B1F0F242457A198658524B0D6A46DBCD26EB9400DF3C4C942FF53E1102411101B2FCCB58E3FBD16E725147960AD56C6CB6DB336857EF137C49D53D16E98CD7A0E856E2D6B391A95954ECEFF3B9956A6D0C279DD9E1FA5895D37EEA8C54255A6244002C7542789453B41463B084E7FB3361923C43EE1BA115CB254F47E55E6EB79C74DAB4C9CCFF486B8CF5830F23BA23C5CFEAC2DDF7D71EB5F54141C100E0AA9873D43F0AC1034C54193BC63A560A0C661047C508062A70B3E575CC185462A75230D91A3021330D95F3C807688B032AC15A9623A833DB718D04603ECE983F1D21A4513E80CC67FD34EFF8E377B775142344645872844BA46F5AE6971E68FD8ED640BFDE9F276E26B208A8F3D74ACB739C7EA6CB26165EE182F165EFF21905DCE3D02E432B1193CA108B6ED066CE95D549D9B12445E05E0583EBEF32F17EB121D80EC26C1F154C4DA2ECAC841BE1CC7224576EA43ADEEBA53C4D58785F36B6BC0F8AB23340B92CB87DEB0230869A52DC634F68A83BC1AB8A4102264CCDCA39A51C331F6DBE30C18C00A966E5692CA86399264399DBD3F02FF8706302462D62E4D16B5C2FFEEB02A7E8447C2CF1A3FBA5046C792FAE0B1079621D59C1D7AAD17CD6578964D1ADCF1256F2A4EB4D534C51313BAC17A9383B5BD02EDCCDFE59998D2FCA7F3EF52CE0B1842368EA66E0A83FEB581A7137004655957E91B25F5435BEDC0ACCF69238AA4CACE418F08ED0D961E13B2234187597FCC012769F798D969C13F6BB4042897B0D8C32E6CFFC06680B1E0A40F5F149B5974B0E7F0D45367E93B415F7F6DCF86C2131137DCD0DE30A3F1FBCD5F8214AB20BEC9738AEAAAC200900F4B2074688C8F3026140A354A22F83BC2ABA66407F87671C3E7EA4EC6F8272B6D16F3C66C76ADA231677A9B1CF496B3C241D2D1ED7DB703119CEB162EB097A0AF2729D0D6CA8DA57D83E1BEFB880EBEFE090F6E98D64296F7CA90EA1C2B26131676232BB394BCD1A06BA83004BEDDA287073154D3BE16C242DD65839C2E1125B3E66DC93A95C62F5DD31CAF9895646D5E2D183D40EA09843F5DB189B41AA4CD1B40C5792C2BCF9F44823EDD4246100457299E30EB2C66896F89F4FA250AB19CA06EF5B899CB96FC5E0369B773691E3447E68475A7552C10F96F44B3282D92AE49A246508A67EAEB9F4586074D6FE8A44D2D27C7B8FB4EF6BF701084B73641E41AA7275C1D6B517FBE3D60F64BEB9119F3FBE96A11AD45610E63CBDBD79929003BD1F2DE89DCA036973974FE5C5D5A8B5BF82DE0368DC60D75A138CD91E8A9233BBD439666ED1211EC2FE7D7BABB1247315DC480CC64CD8F7859BB9BFE8C668F112FA96EA48BD91088EA44F40D3E57314D3759F867BA52E52BE822400D9B0C2123F50601EC5F8E8B562C4B1F49F9779A99C926FABD8A74173195CE23173F4CC4098EED74C8E0FA74320772EBD1847AFA1B397F5A6F05A00179DEF2E6C3B092D9182CA3C4E382C4092396005D8BEDF6248C81D3AA0854F0AD43C1079CFA1E0A42650EC9D7B9077BEED377BF5FB2F3D2717BED04CDF2F7E7D1F45CCC6F71A780D2E5C3516E5F6211815FD691E036E4FA002079448AF0E005B67D2939CA88CBC57567F634BD0402EAB06805ADF8BE550B3E27452B372CF8C92A7055714A228986FDCF4045421321555BA06173CA0A761BEE635C541FC984C5BD3857DE696E9B21EBCFB87ECA437E9A7B54F4CBE2A601824EBEDFD5446556B64E1A88B0BD9CBA507C5419CB8CC4CACE48A0C9668FD2D045E9057B13BF0785F59B35338501B73B44CB749EC2EBEA97C9D29EECCA6AE1FB719F9A67E8E175D50B2705B6149E9D5D257B34487B547FD050FE5C998412AD0B4159C2225EECB67903FFE332CC3B86266C22FF7776334543C1E954AF5A89C4FE59C1F1AAB5097024E2AA7BC09831C9A5ADB713591106CD3304873BCF11A9138FB08B7485E123DD8F7C107E336659DAFDB866487E197589DE47D2DE8298EC3560EDE21A633F820BE6352CDE9AD51515D309C4BB4709F171CAFEB407ED1A02BC4AAB53588C2CD4C273BD527F8B4078925FCFF8954536E0B4366E474801F5B938A4B81F037764D5CBAF19F237CE37D00246C60DA652B76469BECABD51F873DC75E520A75B52BF585D664B4CB9A09F8EF3C03FCBDE6B9E595C1371C2CFC24C16EBC392C75D2BA04212947944BC0377DB718A7FAE0F6F9008AC7DD30B94C1FCC6BAF750217C0119736E4F3B7E744AD72F1F0694BC88F71E4BE51ED8669F0E814E12FD9F833286E2064708951DAB852774D4620A26100FB44A8A92B86E17507C036CE6F3ABCFAB91193CA4BC4D4198DEAD7CEFB71B01FE2506995F2ED3A02EBB0355E6B67A2294648B8D1C1445164D99B966588CC253D1EA1361163024372E2550E9D29AEB4234F5F9B20AECEC01862CC98365F1C57FA4D5E0C1F8BF189E169669F825DB43172D1F682DFC7729B2AC0C103ECE4ACD982D86C515A208519D23F62934AF981DA66B97DE2389F2F669EB92CA4A5C4C844FCB19903371AEAEFB32E210F2D1155576566C7B529A98A1CDBA36B450F3948F34F90A49F50E7412E6EA68BC3BB0B0A0AFE3BDDEDB718D5A150EAEA784859953FF1DD1B371C539243547FCDFF4ADB06C61CB49EA5783AD06BC8C1F3E32A95AD3CA6D69EC1D226BF9DE0562888839E6243CD150EF6953C158F9FEE5EDBF173997D08509EAD1ED4DC2AAA33E18DCA6F59269CE457C412B58C4483BC96AF5069D1C2E3F2F8DCC5FE2825DA21AB2280984C359DAE44C2367D6F002D64AB47F9B64B5656622517A5F7D5E1A78D4182B6BAA82E0490659CBF2724080A9ED39BDFCFB21BA362DC29C750C5034A04EA5A85799E01FF8B16ACD2EFB8328BEC686AFA20E591E7C7FC55BCA8BA1A3C388B785AB0F57208CEBBC5619AE3A0B799D1816B013BD67D440A7AECA7D0BA517846B68F70CB5D6ED46C36F663D6F242E8FD8C620C9383EE1BE9250D63467504B229378D2589B525348DFF852AF1676A18DE321DD46D7AAFD3DB1825F192FBD3F160E8CA400B201B1A61D0864257CA340F179F5F1967659AF4789846A4D086041441DCF4267681B83D4C8539086E276C21BDF677961015CE550E41C2C45D67A09AD8F56AC3ECF1058F366F2E35BAA9353A5CA40C7021DD09AC9FE0187C10EFAC7BBBF3B1A462C9C6C96699741AC16D3526BED3B30AE25B8E8A9ACD8CB2BB6C28AB89F0A3F0D0F40D10AFEFCCB067A37A2C93D3E8399A366B5FE4829870DA75B93249DBBE3C9AC9FAA70C4E414EBA720C323E6627759E7287472C3DB9CA9B1A5FF03E872374D6B893BA4887AB227E989D9D4D348B3965F7B96C5094F42D84432EB771BFE757105966C9A08D6C58DED7DC216B3D0ECAD2D0B025DF33CD3D813348B5E08AF95BBA08DB5BFE5D0A151C98A01ED27661CCF80F416A1AA260EBB56526AAA289F17FF5AE97CD0907D9143BCAC73F1F83A2A8DEEB3ED209EF0952D5E463D87145E0E4D8BFA1741E3FB737E14B5924F436D0183D98EF836DCA3F9623B50CC13EBB5F94EFBB76EF9BDF40CE6EAC9C49852D08E2A5A193D1DACFA04EAF3C545E0E25E37E94DF51FC1976BAD069CA530E19EED277141BE62239F47441B88F6555B0A998C1BAB53758A41CFD8CC4CDC54E1158DE15910408A6E79D33CC37F61917027E9D2F186466F704647B1CC1CEC06DC1AC37D1A668D44DD8B12621AC3CBD2039BF5A843A86FA492A847D6552E1570DBFE008F51652D65D03D8B613AD917B81CACDFD19DB7F4DC9A14E237CC6D7268FC5D3B228BD88ED36D8360488509C974E01433D78701CE07108C67D0489AE94076106B045DF7CC508466D35BCF156901E53AD2B5ADF8795751891A5839033A40EF3F5DFE0BBEBFB2C9D1C000691F902AE490D382EBC87FD40E76B30DAA963254674C7B6F304DA2C8BDBE8E1DCC87DE0486B4FE6B57A18D5A9E9E4BAE776D6147FF9C98372426EFD30C3B2479231E624A253A7B0BEE31E0FF739F862010AF03E227A12C3ED1F33EF1C0DC9D48A100FA24CE5C5D8B5F88F92BDB6A3A5328B0AFA983D57A1D3320A682B5CA94E75DCC69BDF2AED0C05887B791CE6F6F8885E4CC55C3FB050ABEFCD3AF2CA603172AC78B3AF2B047E506639498D0391A06DFD328B8E1BFAED8F76C6E4A93E733ED1097DAD8663F5BAEADBE1562D40C772D376786509323BF059FF17A5E6EF5A31BD668954766417E6633BBEC90B53ECA61BADD4037030A55A5EF4129D4958F6A8A5ECAA1AE7E220A87AE996AE8D9AE46B9C60FEDD98FF1E67807037970C92CFF9EA4B64F0BF8907198A6C038F9826CB968B1F301952E1F409DD6AA4EFFCAB157E792ED45830708ACD7A50BE8C08FCD12560344221104827BFA495604A57826A49F90B8B694B2BCACE4040627AA0989E3DB4FB7167F50E8A04982084FB3ECB0DDCCA5F24A7398620D19B37309A4DC0DF28909E16645F35A81EB3C5EF6BFD650571DAB03A7FC02FDCCA5FD09C9D2D3DCA888B8261433DE88D05DEE5D6165080A237D55ED718486AAAF1E2534CEC3A87048ADB40EB9F9DDACFB2C883EA6B20BE1EACBDD72432C7A6C97721FE1E0D9A5589C951F7D46F2C5F0FFA909FBE12E1CCF00161E741C4505681B0B018FFACD460528795CC3810BF7F94FF9B75884956798F21ABF36DEDDC1F95890894EFC15EAA6F19E9148C71EE9BF4CFD41EE3E5DF8A449FD95E5744793B9C223D26ACB44E691D7E5B68D49A19687F0237E7287841D3B0B4483E2A7C29CA81BDAFA5D96D9D2CB6FD9724B9903E8CDD03DA810EFBF94BC7179349E10566B5A314F81327F76C5A8346E222C408EA43FE29439132CDDE79D0D69C45C7217399205C2DA4D33DB521940C4EED74CA22645D5B6A549E8712D0B8CC50DC180067D13457ECE66D489F687DE218449D974620B3B5462FF3A7F00C439AEC73A53303AC51EB84BBEBD51AA48A5DFB8F93556BA540F5101CADB8BDB912D7BC87EC2AC67971AB99093C8616C4D1F3E7B06003E4FF22D99E6CAD7558EAF5C1410199EC97720E5C9278548E7EDE62BE9105A2B27A54D95673849CD5D60424ED97BB64798263F98A63DB58BD55965D3A4283797CD88C7CA67B1C4F90FC7237EA35AA24DB18A4420B827B3FF7FA5472C31499480EEF5A97BB967D1EC46E7B05A3D25212C75972D48A9269D67048132399E1BE0C02150A3D48717E4DEC2ED47458EB870A1EEE5381209B5D182DA2093AE46A4D99E3D4F12ADD71001BDB936FE8AA96797982F88EE67AA2E0F340E7AF498D5AE05C177F0BD2650A02ACD4CE23018F9E00DCEB9794C5C76418EFA65634E01ED5E9FF94FF86AA73641117BD554A9391874A75C7CD1E7759755B9D2A7F367621C0011F61B588D913C7AA0A0EEE3A2201426EDDCD56A020F54AB41CD899721D6E1F05F8774CD5FF6417CB68EE14C20D9234369C9CA59627B8796C37B4ECF1DE2F981ED0FBCD5737DF0B82637D599A61826909C978A2B68CEF01C5CF84B50BE77B49C1887544779BFEAE3F533286287E48F0ECC0D36C27F1209314726855E61E5EB5E9A5D7E3516E29DD369F94D72004742E246AD4699C64EE996BC7B2A079344ED32A528A9CAD6D5AC02970D0168A8B5BC713E28934F2880774418550AC2F534D06B61E627BCB8711AD9FC6F2A4D9301EBB74E1F3C73B05F28DCE5623BE1BFA871C14A947A947CFA806AAC43AE515D6CA65436BA6B66F62B0FDC8AA4A748DBB72D9AB087AA39561271A986229EC02BA3719CBB1798DD333248E4DDD0B6EEA4169D3B03C9F4DEF9616BDF97AE993F0FEDAD31834B6F78E23164B556A39AC1F209581F61AEADD8E504E81A808B1E97F79F987892A8F7FC35FED9B1A2E9D3E17BFC5AA64680DE98664FEA7B479567CBE307AF2A8516BE4CBF9EA030471428CF802FAFF85701AF96CA1D8F50F5A79AD63F20C5CBB954011BE4B1A7F627A8B5F5A0D022D27BA6FCB8D3587E8632A2FE5794C7E8FD09C9AFA3021B9F43BA82EF48A3B1F3E40F2FAE182DDF9558F7033773F5627906E159B794C4220219BF1A9878B175996A16F3CA1DDEDA56B16E63C504354E5E42FB90CE4D2C1AE7C93D8CE27480F3BCCC076CC253B574A7BFA6D3BFABEB3FA6A19F196C7E31A0D6E9477F828689FD951E0FB033DBEFED6C680F0FEDF2F43F48C0136C722601CC7C4B48B24121ECB6BF84D6B3DB240FBA1E014F7E3ABDFC1F9B98A16F4D39826BC1EAE44385FDFEBBD649BDDA129FC7EA3F50A5F481D3B7508EDEB04FDDB3006D6EE943930E3F0AB405D151F21E8AEE5BD87F225DA6E155158DE27290B2048D384BCC54F0EB905961AE4CE5E6E93543016F62445AFB5C39C3EA2F3367A0B8F0FBB83B37518C5DBE1CCA1DA9D0B54F34B15A1349A2F03563732DE14EA9BD238F481D9B262DF69D24A91534805ECF57A538D8F08B2FF11E96EE692DFEB106D3515A7C69386A781DB1D5434AC18713CCA12C92557D1E7DFBB15605AE3BA86267F3E6CBA42B6084478E460F092BA2649C8C94D66128FABA2D0EA7D9BCB20663B0DE6EED2623A061778DCB40373B8CA38B02B7A49F6940D6D11CEF549CE80212CE8D3A85CF2D774431343FA1FFDBC71C5334B1CEC4D4E0EB643E1AAD67D1A5B73FBB1BFE47EFD83CD17C798044A504FBBA5726429F41DDEA7B7265A76A48B0BAB4845704C771638977511092BF6C6DC9D574E6288C6A3B96BFD37FAB695F8DE20F28ECB27EDA70A07FB2ACDAD88DBDFB2DDF06E83ACFD3A136C5DF4811D34C242BF9206D579BA8DC6D20E8600B726C9F1B918EA573B9DB2F96444E17B6EDC15822B85D452CD99CBC847AA205EF79E574ED9625E33B6EDC793E5"""), - TestUtils.hexDecode(""" -d645f682a1b7aa2650f431a828463cdb131c1c317bc2d9a92477f9ce4a7190d287bd352213726174bb967d2538e6f796698924d4808a15377e3d05877a560d2cfbc13150acab39cc6ec464ae5fe51ef788aad862bdce80a3c3669186598ea3f01dfdf9479caf10033fa89d5bf164b454b1c909edc6a85793b2f3662ca4dabc42bf621b2c5f55b357d2b7c97b21a1748d6e6d0cb3c2e1d891b057f0c3bf482f04add99ecb92d32a099443987c25b1a5e26930082e9719fe2ca845343c3c0208d35cada03bf51f8952ef49c18c916c03417e217342ebf7234cf9270522b3f6bf7dbf5f7aff8b245f1833b8cb314f86b1e407f4e0b49f2f2917bde67c9ddb7fe39a64ad96811980b530df51645a89c365602dc6a6b53b67e56c74951d72e0cc2a7ca5ca0c1b32c3c9700fff54c317b3bd1474cb3cb402a85ba80def7b994f84018b9241ca20cc5ebe6cb24b26b4ee21904b658954fd9716004a009b762c5eb5afccfa8f6153d1cba1358653a88c0b87dc6478578929baee5bf33065aea3dc0bf333453ed0fda613d9a35e00eaef91ea96d87b676b66963d2affec30cbd7dbeed1f36dc93527db0a082d494afded3ac6df843e385a53d8a7a0dddc2a38cab1a92a649072768608fead5c538d8767a75f46bb73f7971a41401b8fd50312aadc6fc5f2096007d6002013ef9fd66be15822ca3b001540652636a8dbe65b2b6324885504ce3233f6fab6bdb5d05a10d85ca8b9934a5fe39d7c3a095530554d058f2f99f9c2775a0822ceccea548a35fcae73ee931ca01ccaadb226f91f0104743c423b220b9c76654c9baa1a1e60310673fe86e8c71eba544763f94b80dd075b3fcfd82956da9ffd4d4a0364e26cf4c4d7f0d2ba435a4e7b51b01e9cf55251a5f8fb4e32ed1fdfb6dffac187bfeab67b7bc06fbd1d623c68823d45d708ab29117ec17fb2df9ff17378ca7a021b504e678e4b7371f2aa05588d710f292e547f719f7d2e66ba39d382807ccd3cfa8ef2d33516053e6ebdb2a8584982efb880180c45480939af7b3d72e71d046fc78088c16aada249506b079daeb16056bcf49d495e5f5bc9b64125f66c809e02282e26a8b8c9656d19b75eddb4310daef82ff90bb199142ce3ea68dd6ef33cf4d0f2e7981f2d6d78beb9aa10ff7421804231b02b39b3e9c4be9363c49fce0b5a460f49094389ef2c28bfc45c805a563dc2202bd9da12485eff443013dc8090be20ba1430eb71516fb36926db06d59f5313d43294d09a5c242edc04ca7f1f69b3f87861fdd572385ad400f66ff9bf127e866957b5b7ef7e16f0cf93cd10d77b87894fd8c0f184f0a359cadbfb5fe6d91a06bdb000720f202f077cd4bf5c8b149565c43b4a07cdc5a3dae7599d26f3931d101d086b9546be593ea0bb85a1807eebaaa798e57d88d4b042aa3e3f621206e22f66335792b606f419d1dc63367d73dc462ebb177d3d9d4532ab6c39341b447af8a982d24300226fb367987aa37ed10223083e4db66a5a344628310d46174e0c8b466fbc0809905d416e1b742f3749ffe7ea56ec6c28b085d71d4e315b4e49d6ec945d23ecf5dcf503c59b839446abaa0ee57179a6567ab4d02fd1025b671aa5a464e1892e9e2b96248107fbe5fc4b792d1b6f62ecc6195be7acd19d76eabee8e8deea2ca2661a382f06e4ef90179a4fbe255f4a617bf6c1c3c564e05d1eac7cf110759364e7d3045b2330a52bdbc8ab2307e876df8b0011bd2361471c6cfd7fec98dd4161bd7f7517fa6bdd2d678dd4dedf71dfef7eef7d28d03131aa2db37f163d16818aac1e4daa94c6fc8ac8d76f03f981d98166431fb42081dc565049be93013f71832aea1c20dba0112222bd1acbd7e7c112ebfaa6e264655950a6fd78da09d55838d2f79a87a311eee67f023af189511c7e215cf8bf5b8f47ec397ff8ed22f5825814c86712c289977998dc8c7ac8eb60cce95ba56efe213043e7065d8c6e6c1c6b7c4b87f807e6375fd93e8133b9ca61735d2399bc2f0cd4e6d28c21c4172f26808a70ec7d5502449e335abfd7ec5e45fd298cdfc8699b2607745c30c89803cc741b1c74fc6698fa95c1397b59ce6a08a19d3572fa395af1f913af021cce85d40f53d511b2d6ca6860ffac07dae4de99cec54b0608ccefa3395e327d67aac3f8940c03c737f0066da5435ff060320aa68868b2fe309669a014e0ce7eebcb3e9f3d27684c0d14be48ef4d8de1f0f541c2dc22160aa238f736de0f31996fd1e554ddfd33892e998180e4a47fbe34f6e9f2004d009e83fc55e7c921a73390f6fd44a7f32122968e174fed54ad1117344325897482707ce6cb45121266c870f3f560c4315f046e3798073ee0ca7ef718176458c761825f7288b6663bf48b6efcc50e35a5ad124772fb64967056ab6a39658973471ecadd3d666e6f0377fad3b7390dc9ea67545fa030d1085244082ac60d0ba4d6f0ab44167571324e40ad664fc95c25dec94bfd59b32332ca5efda8288965284c7f88fb8045af9169eb63e98405e2aa3e949d4ebe07f3450ce6caa14e2b399e26a347d88b2fa8a301032c39bbbd945ef5d213cd4b3418c25cdd175a3ab8ffa41679cf6359ea3c28905309af59f0f92cb1db581e21da648f096171953fbf62d53da61da8eee1d24053270ef6911539a7ee93c6ff45a0b465ca879498e131d37d1a05be88fad8cc28a3026c7853b9a48bb8f1680889ebb3978b738ac7c3c54a0bbf1ddd79819a70e9d083775095e1daff66f72df70cf17e746c70f3d291a343d4530b6c9dbdc861816ad799b1a63f807fcf791fb1ca2e3160543abbd10e4fab61c18c3c4f150519d9690f7d22c10bcfed5c211a6af6f438737402b425c5ae274ca98716bf64b127ec0c7a6cf3598e9bac44149b93310ef5de9fd8381a961d5b9c166b7a687072a1aa27a8ecb2d9a023d353bdd29870650e0626931654ad80a995d6c5ce63ed42ec35444ee57444ef7edf45afe7255739b7ea731dd4c48a1497b5e6c135f4ddf4cae02577920f795809c1d00a391f15e7e376271c0cc0a09ef69efd28f6a44b6d2a9577ab7fd2198f81b92cf4094c7186e72fc3a379ec9e31b7bc12873a0008f40c14a81180f4caa16aee8ed827341c08fa4c98d3be393d524abfdf5546999acc4bb74e6d72b7db9c443bf8bc300fbb0d19ab0a716001cc87dd27bf2605930cfa437c08b0392e8526a26dac97e1e692baefc515eba1b82fec70c5eb4fc950386be3a5eb3379537100649cd192d611dc90e5787dccc69a364afa632abb31de145279e9d736ac1f6185f332b75875006f01eab3a48ad573d4e9b6849cba181d1aaeea5120fac5da72d81e7a36fd0847fdfc5f7f8f589b98511bc086a107d1ccc4797308be5b590ccfdab138078ca19679a5bde6962909491e1df2b048924a235819a7a28e3e3e97105a1a400c0997376ed9ff34b48d6076fc8d9668e6498171b82d7dab2418146610d80c2c7be50f614c6d5adf8511ce282d2175ca5101bb18dac9207813b9be0510a2195cc2c746d2bb99d3049f29374664d74497e0372994583c788765f3ac918db9a4d4d1f2c2482f50d013e7e93e0a5228cc03f4db0cfd14aacd90ed05b7ff5cca2b00f577e0ba47e7a0eda068f1aebbe688f167e3af3bcde28b3bcf0e89c63389564fd60be1c8919ac245db3cab86fef9d0bd4e365c1edb0472f4ba23b22c1918a399e3e08933031b2d0ada07b4c89abeff516f06b67e2b5c6bfe4fb6671ea4a45c375b9310f07278f0594e4943f4e45098e3c68c2c7f8b4eaec3b3d49a21c077469c84407b2ecf958c7aa3ccba4833a0b8c6f6cd8475c4d239608b9d25bcd9324326b4251b89579f2e902724f26943ae92b95487b215d719236f69eafc46070695e8d4a93053e275b93cf87723bdd589c15f722c093ca50c1d54121bcbcdff8c4e306cd4f11fcc681d6af09cc0de076a252bc8583b5afba1405798756432a729b177906ace7f3b8340f3526e7688fd49206e6853b4c72979469a30c584786f2b8c75cadea9eed04cfe68dfefbdd2ed5e1e2b3397ffab7c5d84e645a4049e50bdb9cb2453092354e0112cf00fd214e22681e4111a7d4563b84828d6bf6450facbdeca5137699c551f2b0c7a0bd5ce147dc71dc2bca5b0abbeeb109e6e951115c9c8448d455bf723b8e18e31b480e5b17c8de45d3f73ed313b9bd6a8f5156cabf25eea4737d4dfc8ffe042c6cf665bb346d89477d1faf60ace914eff5db92d82ab2da4e08de466f532d1f7c639d71e6c3dca9bff0c5a4948540cbecf4aa65c4dcd7caae9cc3ac56c04511518c1ebdd02aa8285b05393ce9fc2d2a3d8fcfcf79d4f1811d9073346d67f4f9af28d15706d577f8592c653c315a396e03f3dbe81c339c220aabd4f654239b14dae453dbd213da8819df690f38ab52a1f67319dce8ba5cd33e9bd8f5e61c0e0107e97b7bdc384269d410cbb77e19f2d89e38305c6e7dffb952e331bccdf884956c9c67ddf2d56c048b31ecaadea55e8efbbc94ee0a19980cd30edfc85d6b3ebfbeaa51ab1bb01008554717bbc6b17ce9b8b255707f95b7302d63b0189aa4e9eaa966429c1c1b9d2aaee73460a2335455f8e9df22a2c3861cd354f5163b1f1fc212f709c040516172a63acc5e6ee051f5a8a9195a3c0e3000000000000000000000000080d1418222b""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -8ee898ba956b2d9173be3179771f705dfaea460258d89ebb97518aee95f7560af3a7aed5924ba5d41fc95d1e38a50f933d02fdd280aa39c5afe63c3d9d1794d60cd72286b030b4148763878971ed0b5148ed040f91506cc5443983ff03d71e76f9f9c56b1aa8cef53b23b78dfadf10a4c5a1644dd5b2a2e33818effc45eddc2e4335271321448822403470047324138804438087588843706214268172475025276564145746423461361702544370526584123688122766438025344681178752630841205185142880034051070654535540731775307511227772152582388516212136381805636674882762427882403274050386855208724802323635371166346386078303506483716037112661182682653125854143637634378471542132612773664523401452863833035254314658307485600331255344301038588760626073667657566824783054365633462288132682748533875185444862162254814415860001373078718255261684106327781124677850673185831163442273852312501053226141146222163634824506148584236864562146634065825411836882440250464233048824316504534284448710354356011222712187424043071220737224254741123321834651238540136100320462350627487576313802878824634827083482111278134020462438040464126408725167702172738314238282431041864706527654420367467388153108253278207884852246535046221737521426013710361237422631134378231064331038366647860156765065640638568152013685218854640261823187005008782410321125585430133008257133230477257543211558420767576103710054360341783614605248464771084540585787050215372485563434880427653241876310603860874544450548477278031034433603287642374200174807130835462067337683542725204412564185801303727563151045102036044470344241431513253750453344181068301323415742204353382058206486112246730432277510678825603044373307002101505886672800331788627547508848481601812208166603083203168784821438117303781442370283147018313617430171084244275611261755507351877717165262323632087124473071680850882748858017077344541605881657867251885383643636341482257133852421828175577536553188518014245127151435848786816878767508827008813446037762050021601433060112405756553576443238728042504312434387673134061740013051122052603863687228884263102734303648422212081046737102202224817233883384451275044472426612740355787867625181118451686770774617255260137575557073363187168671736888138141114578031460423674014223161125708738168365636487634115108663062235075448825402171750743877411053310363480603171263331785410245534061202488708057726864521028558241854255843757183423680846382543841745715138847777161848558266446618833657585682227476126378777007712556452110415211151557863105527250341262385616773256816580020285012073863107105853065263780724346221555084082217168843148616386286504840733176160868120580618151810200358586663211701312313183338517302461622880660528360255424478558281645501247851806440186653100125027022143448400050752276372082722240442876067275785022216006585466382364038365267686378250502150410212655602182568087652266441770205884064038705815040665563873705223720346716224782001233877143608776246446162061440454784430547646856536083466603722577250585160465535136334037007631745875388337766277366743877607052036743878504071126007836356552360764414077761063784001337335478033158818132673068800873836568074230378648445702875646304c0271d6e8c228b00eafc0d3759106302375985b74ae9848bbc6737ca0e0004e600a1208cca1189f40a7e02deb82f24343ce1dd15b6edf8bfb273ca6b01a29b9dcb7ccfcb3603564612bb0278ad176a72945dd9537ee8e61055db402662736e6d760b2f48194cd3c8f64b7157c0c598231e4994a50d837e29c7153a2ad127735672361e7cd7c50ed7e9466a3794c388dfa6ac647ae4fc7b4fe23e4ebecb77b54b382fd35c9d462acba17a5c143b52df0e5fc607cc4a5c5c504cbe12b8c226a0a954f69139cc1ba4a050c754773e38c5d43524ab7b76179d51ea7cbb54edf38fe67b71031273eb8c38cecab0ef49418716fbd2f2977fb1747e9818db3a8af81bcc4f93531f0e6f1a96666d32b2f5faa306648cb48c670e1597981643cc703056739317310728d16f6b0fa1ec0c27eb3897a76c85a8b33cf7fbc8dc5577c96de4c012563f84e9eb255ef38c2f3ee893a514f854ea1032f9d4ab2f9c12334f1fe48fbd71b6b115f33f6909f154596a3eb69ac7c91455c8097f5ebc088f1f7970f61e62bd19f825e54547c9ffacb0be763f8d85e4aebcc057c4a21d87b24a93969dca10d8ef3d8cbe138dbc8142fe9b25d3e14889d9ebab76b1c578757992eae0242b4fc7085041472ceb93e91ada06a75f7fd0d65cf21535ea945be4c96e6861da836b0a6bc8d524fa0f5559e28de32f5683d83e8359bc1dc63c579612c0b8fc621a7574b360a825e5cc74f24e03f171ef6d1f46e9fa47e2b2b97e377356eb0221a29a0c807c43988ed87433747039fb3757bf45db3c8767136d495e1422ddb72773b6839fa9bd028d9be2ea8af7f2dcdef13fed5f0fd44cc07f6096b03d6d4e7649b2f408b77f77156b7a52170a778e595713055dbac83b783c18765bb7dd90a6de2ff459f71f8171b5e33342a3aefbd500c222bd1224f1a3c3cd659f982303eb76c1a85a54c14c076ec49ff14021d84b51409729358d658e94becc1e3eb1c11bbfe79ef4837e9f0ee82bce0141f6ff8fe89567014c5cb2f077ca957e5d0c8cc77f2c2991f9bd50bfa07de7f5257845b5155e64948f60082027fa48a4e573a5879442420d39868dff08fd4fd4be01f0f4029c1d248bb5f0460cf9ddfbf16ae8f0bf845e472afb0c116f442f65c08f5abc517d3f001c2f6ea767d0ed5392bbb6d0a5183fb9b49410c7cde2fcb06a388b1df37ee982a8a07f0855b19ea4c2debc518b22d2347a1861a253d71cb980da4d9db62a982bba68b5d7b67fcab2d59a12b4a07fa5d720737d3729ac05a017ea2a6a14b1e0d708879561559da4f96721043fb9e525f84a4d5b746eeeb29c786b7fb0067c313ec6c3e1b15babd04503a437fc65f09be43f52deb92afd83c409c3c844d69354c9bc1fa3e4b57b9590efe6c64f185975a82a50f4abfcac043b2fcfec6992c1b0584306d0f6cf87654afe94559a06ee672c0d8650ed629311c63305a9b58679276faa5370a2ec225b693527452edd3a654eae692178995f0020a8f98d0438dfee350430b8a32639adbed99dbd89a32e3a1aac453735fc706369e477c7c176d446dd2a75e39e116643e3ed043d8c1a653a5a6804f5cc5b2de7f0fea5a9dc5b1593bdb481f0de3e4ab6881c81b5785e56a4a4c4651571a063df331bb7171919017a9594334e9befbb31b696a43a50a5768cb523deefc30c681296ca22c6a7d29fe07cc3ceb8693721af0f3d157348b22a7f42fdcb480aee1a878e476add1575e6196ae974075919e7ce786b8ce2b9122d88888452bf8d7d152643dbd3a2ed09d82324f0bfb16322d4cfb5ccbb0ad9a5d6b00a023a2a0a131c8dd26bc8c6ed0af34522c49cb7c171458cbaabfc30d3663bcb5091cd82f5a9564d835cff8362dccd71ed1ce4ff4486faf9f7c1d4f7f4a97f7f6e39cccbdf894828c9ceb0480e1dd8803ae0105deada46ff07bfd10f78e40ac8f6c024df3730f9125895012ce82f4141c1d57d25709c43eda091d15c0516bb88570f85f83ffeb0bc566d4babc7cb000afb3acea4151fa6872bafb8f161959a48bf1350c2de505174ed12b1c8ff13cba9fa06208269efe0b7dfec049990482fbd5e0befc66e6cbfd4a51247777b186fc071d16b6a097a026629d9ac25a8b19c4d792fa83676aeb4095ad170b0444699656838438f44e99e9573843775a513ad2d410c1b75e8387b0f43c85a7a47de8b178c997df7caf16bd0447e58add034c4d80acfc35d028de6cc5bb629b1246ebb814e162580325ea90f11c45163cb54405910bbe326019db6e01a46584672c8d890e1012244c75adbf85427ea5f3ca3885d7fe1bedff5181c4710b5291e9d40762c4ecb01ec87f4c56ccfbce91c8cf5a30cb07971a987379a61884221d5863b8ac975db6cbdeaaa9843a0536db58d10dc69fbdd40d50a87330e69b2f37f68b56eaeef9c954e2ab82ec848c9836877c2626a1e827ffb3e9306b2f5177580fb08796a8c84f45eeb9ec0e39e71323dd29f2cc3efed0e3b45347ad0aafac1a55f27b85a097ff3d472e3433a713fdbb7ade4c5be07db18549d6a8b13e679e5afa6697b7dc09b173582cc2cbd6070947638e5a6ac3fc55395f1cd9d3e721cad91c561c2c6f1702576c164764e5681c2b3b743a69fcfd6f0f83e21b695eb602f0f1c93ee7df80b4bbc1bf9ae1429733a052a232c3e3783a59b8eed4fdd2f3901ed0e0d160075c08c687478ff1156d239e0c21113c9281854d9afef67e2cbb6e41159124d217c57ab53cf667822e7dd01ba93af3e5948541d2e837172ae1623a07ee6155dbde9d2a576df6186de1c2aec399d22682603e7909610e463cccbcdad8addde5a3b37b7ebdb7bc7c2852bc6603568edae193fa204bdb5ff53177d1498b4a6d8eb5ef0a40528fe207567e070f8315fd4a03dc968e3f74edc11a3d2373821d38b074793c2b4bd3a39005d36a787ea2ef9d355fdb535d118af4897c4428d5e9150378e464ecea9a43a791070b64a455729d02565c6ab91771a483375158f24a0780ac7b42226367cca45d1b605d7e60467b50ae7a70d87b3b5020fd4e191e651878b509f5b5fef74fc0cf137ad6d93208a6794f17241fb462833d223a3dff1f179c69d7afcb9d19d803d4c7933456beef432fce5d642f72fef9b0e40211a660eabc4df8354968394a59fab78c44e36e65357e6a5963d828a2e801db6b266daa51de44ba2ac6bfac4a6bd0ae41c8704e290d7515adb26867c4530564bfdc76d98d4250539dffb46fbeaf7efbce573e177378745732dd9325ac98a747abcff929413f73e27502c433b589f879078ea826823d4d418660ea49457b21eff272778b240ca64a56e2349476dbeabb27c57bd51af02cda5b310a0eea25d2910c75784be6910418ae30f36bac9e78f80ea3fb68c681f3556d3f59b9516ecf88b4c16fdc9c5a8b8cf14e496741413903ebd4500b6812e4c3d2f7718d4d0a2e39a316b90f546a5b9aec24606fff6559cdf9ab48797a60ebdd5229a62dc872ec0d36f9f2afdab779b913b5a2dcab68943bebd5ad57a"""), - TestUtils.hexDecode(""" -7C29C0B8E2A111F457E2384845E7698DE4BC9BAEF093F15EB03828664AD31C387B247A525623282460D60290FC479A928024CF62571A57F77B17DB0AC572CB59723490DF79E9B1B31EF2C9488B6D758C43EDD9162D8F6C0B03F43B08D646172A1F8DFD71D4DD805A3AFCF1C4265BEBB71FB251DC9DEAE670A664BDF943ECB00FB7EFA37624953F94CA760013FF1270C1EE7FF58756CE19C204220713724AD03B10F1D6961CDA361539A8AAB6ADEA92AD782F441428C0018D85C0505BAA793C752DADFE92BFE8F033931D47575C9F83547DB18DAEC0FEE90E83967E0D0DC93281000755303F0F5F05DE041211CF842404CD5E24DDFA3C7C83DE3EA21EEECE37A52E16DC80A350B3A18E88EB3C81C74D25B56CDB446F6198DC88F981F2B1ED8DC94194D81CAAD971A9A3933E9319047C5F31530C7C98793A0633875A14FA5635CD1B0441FE267E79C1E874BEA968CB63E20E7C48E7BAA9CE8393FF9A239B5A1D613DA65F7DE78BDB793AC72566FDCD06CDAAF56E18B773737A82298902F7B4890EDABB766E990ED87C94005A2E2450AC1D0192D72468F81DB414F88CBF07707A95F549B7A9EA0760821AD710D52787730EE8917272497E5891656176F991F254A5D582B5975F95AF740421A3C18A82158AF11DB15C154F17ABE1163F997C64A3BD989A573D12642B9AEE87C1612A39A8A4FAF25E35AFED3F2DBFC8FC8A2F9DFBC683CDFA3227107C50526149557CD773DDA16E36782A278A93CD7F4D8FB47DFC37DC3E389D164913316A885C3A800DAD0C57B1082BD4D804BB6A117C3B41E7D8AE9CC9622AE3CA8EAA9A0B502FE3F5A449BA8E768D2C98013F681C68A5F4AD3CBBB83F302457679BCD3F35C4D6176DD8D2B670E87EA291EDCCEEB9917F98CDDF5EE1689DBBC85BBAA30D191F1965EFF8FA9B0073D30B1E2456FAF880110BA9E75E4E29C6106874D32944F49DC7E7E7C56ECB9D287F2C2E87A779052F9B84FF97AAE007012A5EC497C4809F0193C69E5B29940510A354C866505424D4FF3853C94687636543115A73DC407C47927EDBCC4E0567EF4E451F0E464A1385D2A0D740C7327F6E92EC6091845356C2620EB163D9F774D7781BFBC6F6F652A4A2DEC73203DF5643E1B4C3C3DCDF0B4A0B160598EFB56499D2DB1F1E76612356AF3D708F9D61D968A6A0193D9146B2983972271A4C02E2136E6593DC47FDE4FAF2540A8F7744BC3230529AD1C9D2FF65B7671B5A5B16AABACDE8D45A940ABA4171E21090AC6AFF54CD8230F7BCAFFC42C028E6023E55DD02E4B7F976998AB5614A5681C615BF8E9E6959B038188F71C75F6DE44A6B0498F2A9254F3B0968AE7DBB49872D775CB0A5725206D648862734F202DF470770AAD184F822C56400F16F30F8BE40C463CA3EB5ECBB15D51CEBCCEAB43BFAD7DE7679894B90419B65912D67DCF2335212E82EFDB6267EEA331C1439BE2AF62E584C222C1052AD91C7F5DB6AA649F230248A14AA6A532401A28ADCF822089140FCD3B1CF2358DC26939850DB2721750F1537424F6BF2020A1B4684ED79402917D1028C1B59076867DA809D6C5D3F47277755384C20624388EF0AD68BBFB6A63005AD1B6E48ED654E8362B2AF7BF114F2D144A420712FC4EC71D408BE55EBCA8C2F185E7132196B1B76AA7BE44EB55DF7C82C768943D649631E4D87B408DCF8FE470164D9E8DD1F48CEE7F6BA93E239F889119A4DEA118D93F1474E516139036D640EC788AEE708637A619BD1693BAB6C9EE9EE0C495C0D0F8912C0F14199AA69B960F53E4FD8E2771DE4AAF72117A5B2388FEA0CA3BDCD594D1760905F26482459BDE80EEDE3FC89F592CA16B65B27E9A21F1789BD0327A26EE2224C61D80AE8FA6053480048D15019A80FCB5F3B3C6F64C168690E4384AC05E856BF341531045D2952F2CA8BAA0B8926CC41AF2D8BC5A1576292DD67114D521DD4AB535A77E5E9BEF8EA01DDC7C65446D11F90D6CADA94AA1AACFB1BC3551353D09252FE515A465C1879071F6FBB035DADA0BD25A022B026AAA5B5BD420237FF097099CA2402E68E4530F97A003E50CF693D1DFB551DC4695C760138E88B8D11F3075DBF8A6D9BCB9B1242648C0C9DABDD9D49CF132B0766302437C0CD81A0889585869DE92E6CB30C31265C84F58E9437CEBA891422967AA546EEF720A8FCC16EC7591AA0D47998275DF1AAA5ACAD1E1C5868CA430F4FEFA0277262C69311FEDBCC083114AAEC9F99FD98631137A117A9B48B32A6D88E76F96DC58D741395BFC102E147C456D3A78A0FA3D186485D65B4E6755B53D301BD13CC88E75277AF3CCF1EAC6E9C56FE1F10DE05A796A14381551705234F65DD6E717E9EC275E38690B73973C9CAB27DB909C5C13041723BB18EFECAD808667643E87620191008E4D10F471AD153D27F1FF00D8AC6A8C5E59197AECA5AB496D8D10BC79C49D16DC7948C6AF62703D36059587F6EE038820A84C0F287D79C713B066E1DA5B32BD89E5FEEC248B34AA5841E8666CBF09C47EFB17BC82170CCB557D41D40CC87F2E6C0246F0B272733854CE162538DF34559473BA5979AEBFC0D6A16EA7B399687E672145A1149E382954815B41E7E37CC415057D7536E65FA1A35B8EFAABC7B9B0000E08B593496B01E8F14FC950632C659C0A7F7D59787C7FE6E8FA7FA0211A945ABBA5044918CE8482C6EDB366368A9DDB2F2BB66C146BB50251CE61DDEDD8D6A4A60FEAF0F794B7B0DB91C52D7ED1A54AC85D7907BF3A5A96A60BDDD08F60148C0B3237DBD56628982375A67F025B0E3F9EE13DF254E1D6DDDBB057203CEB267200C7788D01342C064FDDE996183646FD3C1ABBA5D2155383CF391FF16C78660D0BBEB549483A4A4A971017A8659616FBB1C3A8A2E83230B610C0C74B8EB32667765F3C2F31F8C0D4BDA3D812DB64448684AEB482DFEC5C37EDE742091EF7EE6F22E31CBA2C9B9A6656888F446A1E9D52D9E6437D22594A830958CACC6F175D4CE8423178B71E7CC81BD6DC2A7F6580A8A3A1207C34D6A1646BC3D89953A63D22A30EB9FAC74103FA527843D3BDA656D1F22E729C3A004B923D08C9CB18CF406FAA89D0D63782C7264D5A8C8078EE6D259EE168A415E7BC83E4F17D9E674154DF08CCB21ADBF5B35AC28883F6943083AA97210C6DAE492C6CA4ACCBFADD99AED15110B10C9904469B4F06ED32546130B0EC4B281622A5EFC9C94B1F2280F251AFCAE857C4E17FF5CF472F038E02E5B7B3CF5CFD2F3969B9B8D5A27C8EC38DCA4284F0280C24F01DD97A618FDC5EB57C45D9E2A05B44E69FE2E47CB50F596030C70B62437F2B91A67FB84205D95CAE259AB1D5FF0454C5B4D87F439DCB7FC62B704ADC7A84502E1BD8E6F52109BF0F36824834D574E07B9375E693AD477A9D74E94BC4E883206DCF875AEF7FE84B9B7C1C9B1858E4BF6735235FAAE21FA566C866ED7C952B1BC19A911984EC25AEE310D8A342AE32F46255E0E00444CB0EE90C37152EDB6C741F5F394B5D47154825279465F0F8B19DDD85B8D9194A7AFAE5FE609A245AD68786C9AC044C008A1B3EFA3A8F4FA0FD49A65B6FF562F33DCB63754BE76244326FB6E416EE3267F93D7B2BDC4705EE7021D5D2EE66BA8D7B9DA7EE6C354E05470B31406DCFD2C32C94C22A72DE90E5A9DFBA99ECA95F73A014A3E9B15EFCBB67FDFA6D3CAFBE3ABBB28C4DEA6AA21F87693D68F0A60331786DE02BFA9E85A8D2AC8524EE184EE738BB3FEFEAD7E19030AE883707DF67ED12E8757B86E6E5FBA26715DBFAE2BE0F90453868931629FDE97712E08A280FF8888007AC27DF2C7113C30604C5DB17538F026F17C7F07D2A94AD5AB367F9CEA87BDBA712363D11FF5CF0590030BE9B342A7ADA48C08BC42F923DE939DE79616CD346B3511F41CE695B3F939C101F687DE7292CC96691EF3F3CB653F4A67D2EE09C791F993C726D574440EABFBB00E5E6328FA70D69FDD5F2EFFFD37C9902AA45EF4E9D06059B0D8E3686C74C94CF2F0032ECF740B31E3F297F15343A0093EE0B8D7F8EDA1118D329D05A1B992755181429D410771E37B56E28AE2ED8C4DDE8422FFE91ACE348E443640578687C57D79DFDF917F8E60E0A2F1C6223056C373F58C297F0FEE3060D31DCF6851856D1D05BB38B1FF426BADA10FD84B2E08AC149F91DDF4A5CB38B290DED4EA3B02EF7A3DF42BDC6B6205D281CE4A48A1C13FA8080B6B4100AA123097A4140415EC7CEC57790D6EB0B4200AD3DD9FB7FBD056A5E3E9D7B7EF47F44A63DC908B6DD8B020854618F7662391DFC35A88F4F5750D282F81DDC50D0132707174914293E3655BD2942C09F88627C0AFE4B921B766BEF41E246FD23482B5B14F117E8EE340C47C7C405BB3692C4C9E541148C2B38281EF0274835860E19C2D48953545247BD1F7A76CA43956C069A17CCFB4D0B0FD478556A209B5376BE9207AB174D2CEC96E09E1F8C0FA07D8920B2ABAC3490216DEBC67030E9285B3EF6767AB11E8CC935C4019B7E68FB9AF8864358E6927D350CC8B9A40662A0987C1C8877AA9903CC89A93E1979ACFA279FCCD2E171A467B76E1103C4EB166273ED7B4878908B67DB77C4FD4E49DB46109DA4BA78D69E03B48518F302647B8186F787F4CFCD87CC5A45B98F7558ECD0612378306C9D69FBE23B06005CD5AD84F73A563B1A3C7988CE0157D2D2703ECA8575D8BFF972CBED32A231395655DDB2188BFFB413624639D361B3388A9C9E13645C563A87C610F6FE79AD50765CFA8149E27F7083A316EBA050860A69BA56D002A78640D71794980C83573A5DE69A697C2CF2E17C90BAFAAD3D421C6E1D8A55B3FB4700B666AE3CC3EC114E9DB428F27CE427E4101ADB49B84CA7855458841DD1F4FE76D9074D940102FC47EA633744C2A664E22B5C5AA2721017F3FAAF4FB033FBB1D508EB98E1D643406ABD4D69C030A2349408C80993D9F75271F913D7417DA995443377E6F73A7DBA24E034A9C4820117D1F0BD69C93FF55CFFD2D36F8078209F5711FBD1587435517291498926E7354558945F721D00A73014C06B2C9BF04B7E695B9109D769BC2172CA7A70700A1D5AFF6F5FCBE699FAE81BC34B0495A82BED01B983444224B4B860360C07F8C3035FC4F0C4B7DD4D37ECAFD32E8C121C677ED263338359E25BC4173D191E869ACB4A5F6D20FD16FE50454CDD269DF8CBE5795482A2B40D52BCE5FDEBA62D9274C9C67127580795BC01752740E606D849AFCD6ABB8340613C61A764B6B92863779622E40EE7A8994034E7D303F07EFA11ACB70419A53897ADD558CFE157CAA3D47917CFE0287500B3D70FE42AFE36853188BC815CFCEC9F56030C83E85C60401912C14A75A082DE2E0400F6348EAABA59312C51A7E3B6A5B39D606306A304B4DD3472C5B89FC65DDA54650392A02CC6761336FD114D848BD889DA4BFE6D32931793A6515510CD802E3D9F2C6F8F2F9DD96ED039462C587395C7E6861FF48B7980D492C23E0635464C7D1969C12A43BF0FFA3089E6B367AA65D4678A571A0D47A75056B34E3F8819F8B6ECBDD6BE580D423D902D3C22D9D787E0F1B6202DFD392AE028292795FCA0177CBCB09AFF8B579A87A854432827CF797E494ADF9F96A56777AD6215F284EA91D35563F25355D12BD155C6C364B0C8423E1BBC809E736CE0BF03E0C0B728F04E6BC8F3F07A0D952AC9D9530C77547B687E193EE2D3565AC755DDFFE880AB0524624E17E019466B7D0E8FD6E94AC2BEBEFC617BCC5D529C83A90D36D57A93BAA0C2ADCF360377C9E9D58C456FE9F3D49CA37A8C3B5BC7C231842B57D320310943FFC0ED2F5F622988ACC7842F8410BEF0E0671673E7BA61AFCD2EA83CF066A169BBD97098F4B4F3C9FE73F5CD779F502C584849D1AAB52D7059D1D4432C27FC9284FBBEE43D07493A38B139152ACB71A171D454FCF936656ABDBDA03DEF3C7B27891088F940C200AD454308001FEB2DFA0FC38FA74F85A30DF4FFA64DB48E7D40C158F058B58174F18BA482AC445A6A63FB54CC6C7D4C8089794E8AB5B38C41C7FF4C6A8A5F294EDC3FFCE3C01F2C5C7FB569CA06567C8D3BD34F82046DB4EE7F7491D890DA1FDDC55B12D90A7853D8FB52E86AA1FBC669C7ED349A2CEEA9EF18F76C23E817AF58101BC5CCB0346A607D6C60BE5CCDE5DB9889E040223FE98B17D31D64E8C1456C01353887D75EE3B82D66CA0679B1C2366C44E52D73B09D48A39D1BA3FC87D73772DA601EF442208DB763F0BF888D28338709FCB008B83671442CD9F7ECAB2C1E26428391E559306904FDE5BA21E1757D94F84F18A5FD8A067C556834AB257B9D2E1290FE0ABD3BD622A2AD92BEB2C6BC61852D58384A20B7409E4F212F630BB280A46CF89DD702B2508752D6A4DA94BB769797B6E7FC318B0B3ED50D7F8C5D8579526D536E4D43F93C055479D53BF6159BCEAD8CE87504EDF7DB35E1D03EC7B4F13802AAE0207A2414802BECEA39664110A54C37415EBD7BFD5D73E871587967F24EA34B7D06CAD805EEDB95F1023B7BC3A74A59A6C9F3A4737FA1BB087012E0162CFF15A539E86AFEE30144F320FBAF088C6884489F84F16458755561C9CB0723CEB6ECB134083C3B82E93BBB57FCE8D51374D38746BECD09A059AD6623EDE82EBCACE009C0C27D5FFFCAF76C9E91BDF5EB895FA1E9C3C0AEC0BD73B1582C067A45CA5D15E2D45E7316CD4B176D9DC7241B05922A682DF919B2D2DE2F45942D3AE254FA55C5D90B8DA3C7DFE2DD8381AEDCC9558566E8DF302022FEFE51F23AF6A018AAEF3C93FD608B0903376E193CB1C13021808ACD538D3426F9B3399686B6FF4DFC0A4552DEFE49D042BA76136719D62884D8B93A349C22E0320B823740DDB3794AD53312DA5608DABACF69767D76327BEA7A644A304A132F2D2FA8E7C8F4AFAC30E389A995C0A2F912E98447CB400FEAE35B3BE089F46CD48EC8E38D4F2BB44F1734C67D5125D7266AEE3E9D1E91F800ACF8038D43B6E10750DADF6CF70DE75176A2E9C340BCD2F6D87F976AFBCDAF5E35DA9B268D3AE1F0F8172A342CAF9602593A5ACDE03DDB482E80B825A7E91E8B0EFC1C8D00309BD170D9F12BF5017780A54F440A58BE4A5257AB67190C62DAF9332F3594303B419D44A38C3A8032E38599B49872D241AA44905CC851DDD0750D04815ED88711353DC2264C0302DAAF2FFD34E9716FDF8A81F7CCB5757913B380A68F153F62E0BA8335F8525CC3A20145C2416581612B9C29C0B1B941946B2624731FA50420716162C64AACFBF94B43B10E59E0AF3836A05B9335B0C44370CDD2E45BA817631FAFA2E0ADC801772F6F71860CC2623E1A802B370823D02442108E5C142B68CCC9CDD0BC2EB9B861D763C715D516540F19E70FB474E120F06BC19A6629E8DAF67556AC60D17C252A44901839143BE5EC76B834FF11DE13762EB23843D3FCF1FF9CEB41CB02DAC74ED6219288575FA294157E532BD877D1B711AF3B98CB0B4BD7286F88C6C00B6AD9E40D66F38525156A4AF35F2FD42A5F25A201C66DA4AB5C4D1517BD6CC9FD9764AE2756379D73C8D81CD044174860FEE5DC42B4576008F13A3504674E0D224A9F1AA780C3003B7856692676A5E581418C65BA9F049CA20C3EFA566315DA220E837639A899ED54A07B5741097C47FB90A81A41700BB5C0D8C3317E27A0A6CFA77292BE9186396BCDE5C654C565754DAD120719E571A4A14207CFD205BB4A66C02CB68EB9E50DA7B1FFC324AD07D8A8A54729621776FC5DF15CA39F3DEB6B810A735CAE0E1A84C6842E80D1CF95FDF5A6FDCD613C54DA1CCAB4994EBB81C632D192CA9AFD7FA662A865C6F193B7029A9B6F21041E3D13D50E5A1DA47D3D3C4B101488D2308954C801DBAE5029E866E869167BE7DCE6476A64FB245247A84E46B5F0D9FA9F7BB10756FDEA659788C032AC654CBB83F23BEA1F285DE190BBB5EC4135E8FA1B134DB5D1FFDA08C06682C2DCC51E0D848F8CAEEAF51DED21830730F6BACC2A4BACF7BA62D14B009116EF2D157F64A7ECBC971D50349712DDB0871D007B2FBF83A832416CFABA2B9CECD37207EB9DB8A017AC266A5FC28DFE64B52D0CD7FD7498F718B32804CF98D2F17D22C2957782DD83F4FDEFC8A6AC5B6A562C939D2D0A0FA6078F7E6B4C95159BEF010C1DF8448158BA29E1FD1AA076972E64A9D534B1F27930BADA08EB87BDE6FB0A691D4379DF0001D84F2F833050E18869F2FA7C00A6481E4F87C75483310949653D6B91FEF1116F25E5EB0A10C8C8723E9C1C80F75C2875FB0C448B3E25E7B359304C08C310148683E1D8391C432A8413057A7AF45289B1363EB203779550FE1F074D3B4CDB77B90700E3710D6EB4BD1FCC209F2406CAA67B98E44AC91B876762D597D0F03A404394AE81BEF8F54A1A898B2F0F0CC3D3B6D84D759D1F1C5788BFDC7657794E384ECB2D5307CD92F3E135F35720A44743D93D111F38791B60E7A64F51ECD6801DE0ABC356409D00D7F785EEB88FF3FDC801C94CD7972EE402217DF018958A79DFEE835B2E7C591D2604B83E2C8B3CEED7BED4DC66B66EA13BDA4FBF5DC3158035A279F57ECBBCACEE3FF346386ABE41D0DBB32E15B02C49D3F216DB19474D295AE0A8DADD1DBA9AECFA9C92F0429352B558F69AFC7070DE8D47032956A9978AC2F388DBBD63AAD776BFAE969EB990E72B7D74A0D2002CD3CC664E77E52"""), - TestUtils.hexDecode(""" -98b2f93395be5e131e0c5fb8a0792062513dd8be0e820804d26f937064f5c0bb3525d053e16da6567186dda337dff3c6f30c8cf96891ddbe0e15b349c03c6d53ea00c6ad4f6bebecf17b32a6b57c9ec32ab4397ec8062d9e8cec7e747a8d9fac7fdb897c43003780ad783874c2fcfec8a0d86ec519c07531a8f0008fd88395e44adff523568e526d190c65ba17b2bd7a383bb3f5df73cc2b646b40c49d2b87486a368d43e6d616e45ed0d9b3e772c7261faa5e5e68ceff3b6abf9ab7677949facd2690d6c88f8ffa3e05544603fed81516a829bd3d9bc55e53f85f31e98b01086c31995834d4fa0eb82ed75d3d510e4210ea4dd3cb8f2a8b446ea8283fb5cae01f7e733d3c60356bfb1411f8be5a6d0b6c20558f77e7c101e99419f94711a98b121fb7f953e0c19f91b3897baa245a62c7f3336fddd02358fc3d2672e9147dd3c7ea8cc3b1813ef8045fa37786c83f387731bc9e3e706468fc99a88917499d8603589e5d8b6d028d2dc2ffa4f03d6359bff057763ba7c106b4ff4dda55d9f1b71ded84896d844e44c9f3b1d174f368f220d7fb6dbe0d844f5b10c29d26ec169dbe54967e00f70fef69096bc8354a8bef7fe0be76e5f95758580c93ac8d9a349ceb388df4cc173f4bc2d1fe054ee7c649d238a656194bf77d5afac4a6115ec54278d17e93f73f9a4658a8f9f9820a31222f327613a2b66ab471132565f9dfe0388e622f784c7e09c0218603a17f83f246fb36a40f3b1d4e2a1bd2a49f388d3c4a7a06de761825b8ba7c580ac8c5ec6f44d371b43af52a62c31968155140e3903d0cbbd19397f80192e356e94523f7d4ecd4b2c55f7b88892fe94c0589a01807eaa594ff962ebad271a1f1998c517dcc3b98c5fc4d73b6efe16c4c45fbfbd18f5eb489ed9e1212bd07bce3e486c1264a595496401be6a914b2238d5f39f5b17a60886228e5e9b2d841cba626b26640edc619a444cfd036c54dc610a2102de9dfee18e18cf32a74245501cca7e49d987ef34f7a9adcdd3567e357244c012a7170b0d375be8a445e5b8752301d7ea633485974c30232fce5e6e9ea1be14f466d3a8241943872a1a881cd4ef436f1ead2ad9227143be6792406bd7c07d925091b51e5395cfbd30b8208eb6103a45fea3dcdd7ec9f478d303132705f3126942d19626d5009ed347db6e75e6a5f4f5651f72265f14a01fd48dbce38b2ebf162d25c4c3b0665a5bb30da9321f2cf070e16fe7b12f7ad39ea6b92755c4ff0d988ac561d310f6e492694ddd4c35c48c13d62848205ff97a58a12602c5575a1f755eb14e50f409b90924030ee3b58964f58dd8c600fb999bbd5daee8addbc185c52d7151bad1aef8d83a3a6d80137cea0f9b731249fcfa996b421b046b7cdebccd240b871a8dbd5bc072e69968f482538fb67b40d13f8bbd2341428d5a5d6bf50c19f89d54d239a0adea5bd89c12e548b69a19ccf9f9402316363aa7959fe3ab63f350f3fca1350b892ca634bda0b6656a44ef5995acee1f355fae403b7e05900cc4d6688bce46227c941400870a3e13bdf468646c828a39a072cbdb495c773fecddde1f37b1643802f565ecacfa1ccccc2a2829a68d9594af2cd44503ddfe823c8117f0cfde7c77397d7da69b37bb765e2e7dba9ab70e3b802a009f511bf762820a8c491c6c19ec72965508a82d199b34f17867be0669b4c792434e6e4e4c1efa395f1c4bd83a1414a51d71688544d57c2d5167a1929856076f7310c768a1919392171a57821109ac3e9b1bf7cef03088d98bd2dad5b0290072d7e5db27ae08e4bffe11d359dd5b58468e8d86d787c9adc8717986408b2d67c9e0e53cfebae82cb27f0919c62e89a68ac8903e80a7a11b7bd56ae232081af3146927271d3c2f2f7247a3def6de720917b014d6f03eb6ef9dceb771cabbc645f2cac7acc3f8d6dd40f6fd2bbe69ffcc5a083eb3a10993bbf6edb5872e001ef31e2a0e86ad58f6829c0f1f560fa7ef734de2e84857e3ef86cbbd0c1ef2fbcf282116297b5de572d10968edffa402de0ef9c4273f793598d94aef6e294d4ace8cccf70acd9f86ae774d15e9a1714ac761af94b446e4f0cde48748cc5db05ab4fd3bac0a1c43bb8f73a7ef7285866ff80fb41dc837a0f9d3ecf93ed0b79bcf6e94177d34084c597abd2fc46fdb4acd11d543f8c0b512efbf63ada213b2d955569da12b88b2d6605fc99c76ebef188881c7dd195e6ba6d5e55f1ca19202ac94c360d76d0359c3cb1f801414d97535313ab2ced2db1ecbbc3cb68e81988bff134138cc393b8ace18e20ee4e0f04c2206df124e4cc496c2acc185489cca0aa1f9848382a55d991fe5b1228f913ff81b7c564bc779ab311e9dcae58e7009eaa806896b1f7cb6718cbc8f8b6c4a65738a87e2338c6ffee4cdcc5ac060e0021a5836c45732cd668d2760de9597f719d26bdfd2403f795b8e7d52e657ae968d027b0da9e5e76d2fba34f1de7425b780bfe96c05f817dd8f0cfe176870201da00deb460d12a84f8bbc43c713793530062dc78e92dbde7a9f53e08259333253a42f5f7b1a7f35fb89e69efb700f7c6c465e80cf47efb8b396ae3455af4fa48b45a1fa87a110975cce3e92bc2394a456eab040c2fd333f70d8165e2b6431677fa28edc67dcae5f0aac65f879ca9c690648689c94d6f657065aaeed5dfae5658f4922439437c65a2ae5bb0853478178b890561a69a24bd0419e2a089ceb0196b232c45c7373938c51591ba527df1f21490883e62e99b0c4b914bc5e7be903824fc12da0654bb03d3c15261691db25a6f6fd53e3d4e9d8ece3d331f42d2c99e9f1fd9af4d68a361922b897ea6ab23d8c896208bcfa6f2c3b06ce3c88fb86994befac763586c2f0c37f55edba60286a764e4cccc5ff915739c510a5d45ead80d14465af87377ea019da46245597bb6af0918654596365f20c63c074c8a896e5b6efa0d2ba7318fb5a42c6eb52806ab9c6dd8f3b160900cd4d71be8262217b9877739e8344ec1a90511a23f38c5b5c2f23552743b953168de2bbb3a993691d0d87aa20cc70eda60839a20eb3ddcbd6abad31d3ea359938e76191507f298dcd7110e0ce6216bf9ffe2f361c8246a9299a1fed48aff683ec8475fabf36126ab166601981dab806616f38bb1bb93c335fbfa3b250e31560bc8d0dc53957da03da2f80cdf04764f2e9fa8e7d2f7a89724c74471d2bf713d4a4adfcb4cb178a492e64c1711761f9eb9d0e65e04b64f9b94f918f4ba6835f68aa523d147414531b925d3d9e7d315e1fdc533ee0c498e9f66bf813a25ff95873de22448924b36e6172a87d7adfffb9abc2bf2272c270b83cddece1cf189ff52e209dfb78b8a952142cb72c969c4ad7cff67b1ee5e5bb40caf0dd45cd37673908c430d0d776dc2519dc4984170ee7ca6365936369df16c4a094b86c1b3ed3d3cce82b2e56a5681c204e0acdd4a712b5cff260f4c27ea6c32e23c227dd8e1f8e99a67df32e7a24e0aed3dc9630b4b3331cfd625072c0024e96e79c4cf2ee92ea18a5e9182028d39b937029a4700d93deacdd4933cc31e93cb234214d334e1dfb5c323c964d90387ea4bccccd0e4386e4d770ea889aa480f0c8f828cd2185c18a49ce112c70d140e18d9aa6ca9ca2bfdc12003a63f67eb31f0699586ea8fb50d44fe9da2d01f0be10d6da99783821c07e892aa6fc6b190d9639d9249492c154b12e45e2009adcfa97b86650649599a9ebe07bbf8dc8d452071bc4f0e8203f81671e3bbe599c76589764c0c1923b141df67e260f7ff14752d7a84154dedad28c0bef90c9aaebf5d2b248e2e20a4ae9373e692bbbbd20c408f0ce99cd7435a4610fc51f051b1d17509a34d4804529a877828c0c263b19f84cc0b8d24b9910f6ad8006bb84e1a4c8eeba6e165efd50e5a444bc342bb8ebfea30385fc0c69f53d04286ca24c0a0a402668503bc94237daa53d1b41242a13050232772ac1b2c6ce9f6bcbb53ef6b94ff5d0c8294bd5a4b077c5ad5144b44a63ec630d84fa559ea329d0dc27dc7b8ba68a96777250244066cf1b8971261826d29f18bb34fc37a6a39e4870878eac95503dc5799dc8923a15a7c063f2e4f362294c1bde18d3289e67cc883f56ae5f56fe9ccc1e5101d67a552be55e06d54df6e97b49b33ca50ff15dfa8b7436e5ea540aea188dff17c3c657544d600fa5a3e7b783adc2065f05ddd72e65a69c7619a0bdd93c731afa3336d3e408e9bf09650b66026a6d691447db90e08800d2aa08fe312b5ed3ca2dee411bd17d7239f143259d697216e2f74d7980dc8ba3ef2ca2c95af10f36d9b28b1bb464155ffb6807e15facbad8b3ab23403bb9ae6546b183fbab7d4fe2fc507931fcfabbf868c6e21d23b0e02952db97e610b8857d84c777863f820978e29efc1d9c5ced05bb8e75b1246aaf401ff1d0d777ca6eb8d74c25821fd9a5dde41eb13d766c30345965553af361395076029184d32187e82dd7aeb73cc648893801441476a6b7a2914ab77063878d53a539f7774abd4fc9d19d5af3b143dddad76ba439466d646752b7ddadc708ac9a0751d9eb72559ab30043f41bd91fee7947106bc185f0406a7adcc2327517988aed2eb5bdde90e2779b5e3f6042757749da9c811162a93999f000000000000000000000000000000000000000000040c0f151c22""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -ab36c995c472d4212dacc8ea95f1ee25ec693ed8457bc6a62ed291a979b6a6e1c416d7e12a3146ac339866453960f2cc24f111573619dda31c999b213756e600bcb5a9d8375e25785b3c7069a72665195ee513f97cc8e28caa640266d2608fe2ff226de704047cf464619bbd363a3feb73e2d47df01f349cd7625d0b18db432b75565336477487553267568843606205253515824068244711850114744643273532787341658558327430044333402256081587535171344517634807008807633370820620716546413274855846856252544627040674022028836536373827541383208773875186683648348251757680728801003125128261155712544258157561003783166005674620687157083581564877088627841842774555801327868575542204308434338323004214761341056456765383014204440531581435680561577131503777667672352532047844617684265448124123648660177808165135746172300650565522412255582600451666165313587027165521854762330581587085455114053121351480023751688405763412618786711845681776135402575773758344478047280051103556627734803186240861770021185247176527722616358816145814811514060536870221854621103182625663607180318144650624216546754871047354164624168153471233044805141080414748807425068851107065574334428366872837263077015337257003145080344316436144048521253116726263513728883204823510034774420126602825342667117084583176238806802150804442282673267271486472381037062547008151325781823217223485168630253776236628044381354407638670266448373507274370405422728852575225681247624224047810183611221407283627210041154333112305767268423663105344701776876275776517745683745418040746282736048644080338088807621666361225348583347786063141187736408336260660304704562625306077687181373631777676838530485071857324430785113302862380543075448275258445010873417527535411864322146042506652578588203571265358102874051054007007776170787482703271464817538581744672845563458322856648331004411805884263244442853851516248334713570062784255773680035331352808764851703537003444265730315085260866221186817288644666201567677688523466252680113168206560036818856824456538181826060511868565280840760317143604778433077304400237144626857286674168627055580074352625485506271072107874512276371843427885818413042213077704005342270702186026772188022317550666001372885810325505652365822465535512370066430047748068806757050035812872642027575531211007684233425471123235162013764134784547815023440552134372432253283276337435244242126148441271544135651721106665301008825258874607420268833040324132761306885310670370146287074551022775376248768550262631878346375634603880661215657881831633748677608483166410002275602835021486452601600514087467338762747001627354482273888861763812343484084480461145702461577820200710217152348451601811752115404520872323133341274887524408314117823537425067462227764805412734655554112853716412560146010777511244114304537730212331208586841302127078636408840851673413682282356472403680742643508655605151500267084283273334113430051706200026602181421815041272467830421155788883212025787175681764014305848564807130860788478271203230488154661057461528415230351078146182662384624808617877187200274648170028523531546858533027676641325203473546874864283376606416207307326881524723857216011843510612852412265535601518443563181343067be4e4e886f61b24e817847be9d3ad4b033e1f03e2c698f42ffa611d25621991861248d97c61f318726b3eb116bd545400c2f5e1c08294e3bc8c4d4846c7fc5bf23759ba32c95bae32b756ab1ffdc337e7d23e26fe601589ac97b74ea1dab26669d7f5dbdfd017586ebfdc10dafa5c641ed6b8d4c4293d0f76fba4e19e83d843e00922c7b35d9cf4f657e832f2ea4878288288e479ea2988e62e27dbddf355d08f5298c763a23f65b0b9edf84eb7e2090056d1ec21a7f666fe933db5a8413748350bea0e5c49530b18529ae94663b12277cc2fbe2f6ef372a78abf5e3760f036e98562ca5c1ed862337cf8ff8e37c1178b4eba53e50f74650d084541357dba684ec0c63d8b7be0e38793ef4085d6e6a5167536cbf29d36429580c7e9b925de24d11a48cfd43b6b199fbaaea0846c890db3825cf8868f0ef75bed833494583113093347b2a3078686a39d0e0f27900771d252f4930f1d9b5a57cabb712f8c6342f01b61b8cdfcce1c61d02a64f70dd01fce50df23efa5145274ed73cb201247a99997bf7996ef04ac8063d1c9c68e714cfeafc8d0ef261bfea3f88f90c573a4ac7651d441f3ea832bb1b648b509e290a94b11a1341cf61d81bd94b3e2f6bdbc4c652b87d98ac250ba30c7e14850cc92b8d97c67d31fd6c6426c9b53f0de6cfc2d2ebada0d2b8524a1682b3ac360084f5e8ffbe980692d988e499aa3e2aa0a7ee16f7180c29994474a01406fdcc9551c3649854beba55ed18c1707e3ed886cf286abdd07462c25e6d54bb7a66a0d84181e93863fb96006c2900f6c88cd090fa606848da29dd5eb8b0becf44bf6f5e519ba99d68d68d3e158dbf604335d8328fc28a52b3a58f2d78432716f474cd7f6a1030db967e4752d55f8bac1280f7ca3aaea99fa77f8129a5dba6963cb419fcfad7b2f174a83210f86c24c824e7b3209e2d0f52ada2a7e4d5ea0a1b1ba9c7b177869f80ee8a279a3a6d76e7dee2e3550471db770fcad139f03db4b99336eff5c3fc01adea008b7c482b04fef014120ab90338ed94c5b333383c07f180d86114484d7e4616533cb4174aaf7b72ced331b8d57a500f5d73c2e32fef18ba2f0999b6a053878f50115dfdb51fd9c8ccb0aaa78542ade15909466212d6059da9e3105a81e351d44d2aa6a8dabdb7e00bcbd32cdb1fa6f362cac5ebafc3c672aec57a6bda2e1f316e83112271fa86a084942214d869e4dcec2b3f09eda04e488d388c9635cd2c780901eef2b9ddeec1a99d3270b37dee43e827ca0252abf972115637c8e6f67ee39736ec00f08c2709ba7d715a5f1fd5f29c470829a9587db239fe562a8210ef12bd2ef28f8d9385da3cfbb555a09d51113cc7d37d4ec2f73ba3d9c3a8ad9b3513839ccaf0be054574b9ba5e230d866ff5238e14bd43bfeed4d597b4e29ca9cdf3a93cba7c1657ffa5bdee1633bb24c81df0fac649ad231db891111762630df8a7b83545458ba0fe51003c17822d1811a033393db4bd4dcc8c34269a2098b144f3f1251fbde8bc12277817ac7e6dfcff9b1dd7350bf22f8b4f8a5e2f4c79095b9823c995a6a2aad82de004a0a0e5838d2e3361a1f69bc3bb6d425400d3470723d80eb9ad97f159499885cd93d0d317d8ae9c6e80781874ec8b023d9db11e1ade79e3e5f78d4ac2256820fa2fe82137d909800e43bf00a83ec73c050cb4fce1d3fc5a18f88f8611f9fe3de7b4ab1415bc18955c02e550b00dfc6c4b14177d7c9fdc5665154a2563450f892f131cb29de6fc755ffe71e7cbb90a199c46c01b5f20a9c0e177908d340433b0518442897a5f00bf6eb8dbc6d46aceda6fd94fd42f7736941f633f6406d4dab88f2eb276b332f3dd19b641a3abe3a2d095893114a1d1996052ac689b059476e19495df304535d4755f3c8b5367b9d9c6201d100622f4aa48c20722a2a1b48b2df2c7f34695264434755a9cf52326705a44e38fcf28bee00fe9a91c06dc6172926183ec2d6963cc8c330d0bbd74754c74db1d5df618858bcb2a6d31671aa72cd8534568eab19ea67edb2461866c12e409695f41314d6bb6609a77625c3799c1d708e38d387f69d738e88cebbda49cce3e76f9cbd727f65d847408ca65ecd8c2adcc349ab559969d82bc3276ab9ae90e827fccec87b549c677597a8e3bef7e9d93584c5295abd6c8b761a56123ec2c75c5d44d23c98bc0eca433e715e4f745cc8cb0acd056675365406aff32d637d04f3591858993ed26f72d5fd2f51ab35757a2b71491029f1e8d7516697902097b2e820a56b1f0d74bd59dba71927c3d05a741b9227a0dc0e80ab395e9d5dda03a4fa22fe8b9fa5222aa682fbd954def3245338f97f8afe2a02c4f049d7c0adbfb4a80a5bb45660757a41593aa1c70bf5c4d49bc70d0d00893da8cebeee56c83061f4ee4448d1e4d0469d397708898f8d435af0ff9b7aeeb81e42d82a21e1aa02de748715f30c5eeef03c95d758612daf29c5553ac143030e0c7c6d003cd7f83f582c34f28d9003611ce06dd96c4d0a29c6117b3d9269435888542adc989ac164868b2eaa7202ec17ed70d4d45f5d5f5582753b66ce243cc3f5039dcc5f309693d59520c2e02b6b0d67d11b3dedceeb13e6d901bc086372462c97d20aa7519f1c3ec1abf680d111ecb51a40302f5ff185226f4e46ce970d83c1271ef7d3b7ac7bdcf7474a169d76f02deca3d60d7a913e79c8c03c81c6050e974a6b2cec76e2d4673a83c606b69f17767b60da6a4a4d659dfc4e962b212cde0b7fe4f0505be5734da9095cfb6e9aaf0abcdb48bf7997f49fb38b5c9cc366f16eded384ccefc725c5cd36e0d4623500a5badddd0c31d9aff05a15ccaee106aa20b481d029f9e9d502094dae21e651740efe441890124dd9908dff0894ffbaa6dd8a56bf30cec6d0d433bb6540162f6f52b8c121294f7d662c3c36b6caa40970b09e1f06d7942c6872c92fe354704f3a38d5ec1036bbed80b11ca3558490c59858599c9a04c06a4cc0e943c12df6e673f5e704ebd4adfc7a2c2c7f3f63b79147edb224782e85d89b6c4bd119bfecc46ff40ddfa36afb45fb6681e1927938c20325ac0a6862d1ef291d63f7356d67c7bdcfd11629558f96d15dc8e65554bbee419a99f96b5dced87c43645caba673b2f66b37466841f64df734b4ff0d20110eedd3b6677757cbd020263ba85c4466a16bf299f263091598b2f3f6b9eb152c2b51e8adf36fc932d4804d3d4d1e398857d5a0b7e0acb7dcb6dfafe0041bd0a8552d649769bd6a3b0e3e6d4cb6afd0f7f2935e00fe09e518c19bfb5668d38417136f79a5665cdef97b109d1ea03df21cec5ee116cbd8b9d55c6962bb452f8f9fe618b267a8883776d237d1175b51140bff60e0eb1c0911250272612976661964e820312cf9d2304f97207ad71cc46bcf4cb4b396dbcc062eef8d891d88ba38984bfca2c6054ff31085f3525c16fb80dce23e4e13415225cde498f84884b5d768dc2cbc517c4a00139cae2ffb60a4906c3fd0a097816d5b9d84970669bb39762b"""), - TestUtils.hexDecode(""" -F55B1A381D9258CAC6DD7B5A57899867FB659A56873F31F815716075DBDD56D6D0D1480AE1242A17485AD259BDA2533CBECE28A906271A3E65FB5D48AAA124993738FDAAC65736230FA07EA27D96F372B90A16FF778D0ECD7C0F62174839B8C7FC50F0B0150D47D5CE9F3715F5964DC712A681626821EA27E912B80D2D04C346B67439CB5E06193B6D7F2161B4F8E0341D8F1C0C7F6E3B351C4EB62E48B555EF00EC0DD5CA6A572FB201D1A4570676A04000C382F4C332C34A0436B535CB3C3F2378682A982034E01211CFB23285395204ECF985F478686817A5F6FF4B694082B3032990597A8C3A85B7FB5C2C49694103811F754DF0434D09C1A5245BBA980D6EFCFC9BC63DD42362477537C6712ABDC952BAE377AE7EAF9FF0CE2E9EEE82FBEFC1CE56063293BE659624CCA0E23DD7EF4412DDB587CF3C5302CE5AFB39BA8613151A04491901DC30706B46EBD1B26D4ACA67587595100AC51770080FC32ED0DC109D525088A2579D8873C6929554C30BDD1E2A0A9797B1676A8CEB719F64A336FDDC3F95BD4A68F472F00C4778745203E1A7736764CEB94F33109AF197C98D94BA3F07E857A5B251858ED850E7E578057E833A2CF95D7505C4973B709CEE834A40F32CF07AD1861CD46CC4DAD37DE66F8037DF1B14CD88E62F81B9DEC286BE4968ABCDCE54F83C5E9E4FFA8144A5877D75FDF75A38ECF60DC180E9B72F256BCEEE087F5AFA5C6D779117070ADB4A671839E8032E55AC52E806C82AC16FCE76A659D6CBABBEC066782C4C068AD4FCD5EC425885A5CBC5A4BAB43D1A60D499C497A2DC06B136A971BE8ECEF3FA6606252029FE5B33661883608702542F7EF44720466D91FA1CFEEB9D8CEBBE4E252CBC096D99551BB90A0534D723B02146FEA94D1C1926221092B97F1A143E6B4D5A8438239B2E2842633A6D90A18DD67D05B2CB560BA8A964E0A49BC1987FF47895D664F92E27F8C90059C5C38B02B42D7A179A09B70023BF7D664A94F7289B29FEF89356BB51959FBB82562F6827CA2A3892E934A9F271282C204BC3C6B34C57882EEB552DEDC0644B43FB28284FDFC82A1148447F2457E94EC0437CB5E0E3B6AB7F7E48F0F53C80D7695801DBC0E96F9C00A4A96AF8D60676DC4A6A6D97CEA344D7E911BE7CC9CEBBB23C562BCEC6992AB1148384278D94913DC4BAC4F73313BF83CFA2591420B18429D1F88D68443B960F61A1AB8E2713794225DF2D4EF88CAACABF6F095DA88C52C011AB3A07D7B71CF209BC84DEDD7FF2D8FF02A0727196D50CFF6520602D9FCBE57F890D19EB7845C6529EE5CD98AA2FDFCF37FD7472D1491FC5267F1D7E6E91EE891D880D5EC20FFC761344BAB59A327F829ECFBF8E550208976BDCFB75BCD996599B68CB29B27D9EF68BC975DAE08AA121F4D95805EB89F2E8B2BFDC61058740881E9B403C54745CF6D4AA1747EBBA56473D00FCFC62B5F5DBA4209E0E7473A0A311619437D2DF22F1D5BABAE064970850CD51D4A62A51E9B3D3121B766632B18F8B7CDEF40B249812A6274D4C69C9EEC096044026022B1FF055A05B6BF1C919230723A952589F540E77D7D24A413F542E7E0D3F7F55B8B335CF3693603210E979718E8CBDF76CCED68396DEB561EE27E9008D7BDB428BB293E1A1BF2675D8A4568D3339682854BCF9E8820A084C94D78E5D0938D66676ACAAF7B411B466B6588E9E2B4A387D84F23963E252EF36A948F25625DCCE664281D76BB6EC1B8E20DB3A7140B194872DB439D89F18E74E1861E3CF9FD442F1CACF4FBFD16532BECBD97CC9A007978D17922A68CE98369240A8D1E8AAE6679CA5DB79D83EAC1A571D0871D5AA28F6EA4A8EB60770E8CC43A78E6BEBBD4FC63CAE26F297F1E21BCE999A509BDCDD20AC938E38702215C398726ABA5A7AB3F26DA34DB3CBD58A7882FED91C33803FAE62E9E69FAFBD698962F2C7226A641AA7B6CED1DA8A400992333EF5DAAC77B55F94D51F74226AC03F7ED8F3D567BEB678D98694E9E0D483815D080A70FCE76255C82FE020DDF32D4BB7B1AE0EC1679B3DAEF2C20FCD7D8F74F6FC684FB678F02DE6B53D03FB656A9B9562666F49797EC658C0E8ED14480A0532DB85478FC2AD1E21F8883F2EF3FD97DFD757D883C1507C44F812639711256EF56BF6F8FC4A73EC3AEA3099F6C2BE6B2380FF3AB7007129D4829103AFE70851917E02EC5F2117DE110FD8F4EA25FED6FBC24BA063B7ECF7585519132884FC12DE1BBEF498B92D6E2062F1A4F7C97FEE96BA87ABFAE76C50729AA68C8F374102B3CFBD69139491836E4587D0085F92FFE2A94B6A87AFE29C84D289293D9CB4A733F90389C96198E2250F5BDC83F123FCC4E42844DF74FCB65986CBAB77B692CA210AC22B5B56E30BEE2BDE84663B22507E00E0D066D5B1F5245EDFAC6D860D0493C218A541A1FCA4B48F1A916921153933383284BA268C3AB003CD58FA979A08BC48A57C755688B0859AF7F21061F9F1B7DA44088ECA4D393E8DFCCA52823FAB812AF36212CD137741C14F0860CBC7ACCE1FDA39431C32AFABB84989CEC971D4A257BDD70EC71192148824C17AF8F18816CA94C457E1023E01012A245F28FF6582C9015153DD7662E4321B465B33B1D5DCA9B1CE2FF49EA3A811B5852AF5C42FCE7FF42BCECD31C798C3B8F685AB50B68654192357CEE577F5CF1F85A50F269C28A1F2ABEA382AF5CD089C146B9473C8965A945091ECD1C02BDF64F9C3FFD035D8238AF974E7111BA4AB10288F105659C9E2847544FEC0B29B6692FB53CEA0DD312B24C1ED3CAA1BCFD94E529F6C27BDDBB7C764DC0161FCE578361E02E0F5F3FDB095B6CD311190466177A5FBA62BD18595DC49C29E8EC7E1F2F3FFCDF17D477F4AF8CA3EAC53B7018A026BC942EED87704108027753DF67BD36221E9121B49CD40E8EA7FA2D6961604BE0095099A4413DC11E93B4A876834776D144269BBBF8A9875648702B589ED4CCBAFDD726DE8E8A58AA5D1A6E142A470EC342BC3E2E1B49C7203F283E99E81E38F1D8D2CD820AC98D8244A705BFD9B67E771A0366C7C6958DCB6921A81C0C9D5152DA37CAA8CE18D6B97404B399052051D7343B3739610329A37B8BAAD173018708400AE02B8DB2A2414CD7DAF038F94714031B1D83A5A15DBA53585B606A13814F04FC925C3454E251CEECEABECD8CFBD6FC04F504508C04E25724807004612E2796987D34D04318F82F7E1FBA83A4DEE3C86FD1884B17E77231629F5D5D11CFDE976E639C60B436DD9D302C380E3654E671ED81D44FC595FA34EDF90710A6384BB62DE0D89B50C14A44215DD1121C602A79A003955D860C88470EFD320E8AFEEB114E547E50CE967572DF5A5C4DED09222FF7821F91598A0A9C41A731D64429AE7D9BCE1B4E90120BBF94EED78098C9EE30C38628297C86DF59930E72CA561A61B6EAE517DB39F5A61FBB8C1838E3ADAAB46187F0B5D09962A39955343631B74BBD17BB2E338E5FC8C43BF8B2DF3A78BED744A481A1D789721928962AF2B9E2187E6B52A19274EF68F329C83F42A28B49C447FE284A25B71FC95D9322E752E28C7B4B656A743CF6C56CEEB758E742CFBC4B8D8DE5465D63D3D5D6EE993A4C47AA72BF82126ED6C7423D3475AE098CE6A7E6DD6F3EFD654BFD5DC4414B8F23F9E29CB0D5DDFAA689BABC7B5A925AB19817226DCD242EE46B588D7CB8E88183CD87C6D06FA1A40915A3F19E2368CDD97A16ACC2DF4CBBC0B30C6289D7004A8B48EFE4186BC4D844EA01BA78E4D1F0CDD2648D0363CA73A19032A537F68E0AC01CE6701426A03E071A109D42EE5BF358445907E1D05761B8F41AC8A9CBE2657754A8C4D83A3516EA465D5AD57367BC58DC712A5C055F68D1CEAA494D9A845474F610BAAAA4CFC96EB51D41493930534D58533E20575B980F4379A80393DBF797969405D6A514AC0A9171B79D6EBC5B66ADED19821BFB090BF76FBF50CA6AE07CAAAFF584A7013A71D54A2B60678F6F02DA726E7448A2379C28BCE7DF968154CCD22F1CDDBF25D91C616234539731B8DF4F55E21F37B29BC77DB4BA802D9BE419ADC292105EAE58CC81A636D479B550D33D057B7AAAF28F743F7B8C17E26AB2A846AE08E804E5D4BAC09D11C736DB32F9DC9CEAD0442AB7B6AAA70633692959A36D6DAFACAF2D7027E5BF9562A93A1B35AEE5313C1E2015E65AB805850DCA7A65FFCAF14200E1EF0DD8F8F05A11126EB02C13FDE38F496E5EBFB09E9E2B4920E619A67517FA4749ACD8B0857C7EC5A6E94630CE3EA0841C64D2EB895A9EB7CE5E757F2FB80BB4F0FA429E779BBE314A491B2D45F9A79655396E70CCEB319C3B405C33BDC91EC2169C3A75C4F5CD7AE5AFD6CAF6C9F81A9223484E7A12512B600794351693E1111401F74E1439C99D77E8932E069193DF7562C79EEA22C41DEA4EAF9E93456378CDDD6C8AA97D8D69C222614E203B6A1FA6377A7A0CAEFE709C90CB91939BCFE926B35970B13A06FFECD44DD8A360AEB5D0432A532E8A3C275E1DC4A07D6A3E100B04AEDEF14A52C09AA90438D65C8E6141490BD1ABCAFDD5925ACB040A91A8E11D242521C1F00EDC14D62E1C6FCE721921DF42164B4B34203660DEF02677A6B8C564075865B030936F472CEFFB3446714AE18BA14A6E45247C9AE1F2836E2341B61940A63FCCFAAD809C84906FA0CB1863625E59B96CC2161A4715606DB12FE3E79C90B64CB9D3A93B451E1C746F6B820B4FB3B3521ADE56DF9D50136635F29EA908FFDB32C6582715B06487B391A36A6A7B96505FD8ECE767C38CA4D0F9599FDCC1BE27C9C60D9190139C4F02461A5C42310CBFD5CF506720C9A13067F83AA1FF66CDCDFDF59B673B6C1FB0301DB118F3F49D1BAB49069A9FBC2D653D390DAFC3CC5CB35F0E50EF4CA808DC69F0134E3EEE697597FE7E5C2A2CDC5ED4E81F344879A0536BE0076D7A351A199530C77C0AF25D5C7D5629641FC8A3567BCB1456C1AE1D216C1E408C3AD6CBC1629E14DD834819F94EE0D255AB1C61BC7C324445F67CB7BA0E5AC424EB9C3D5FABC47081752F98B0011AD389581B8C20333C2878367795E31F99FD2C082B04126A3A61273C94E894BA7ABD8C6FD743FB76CC4FFFBEA78A1CFBBD266DB4432ACEA74350AC06F2EC832BD71FB09481A045F7A17F22F9AB65CAE6782A2928147BCA3B521E001D4BACE5FF499B1462709525D64E72201D5620B5537DF7A3E8DBCCC6EB822129B7768469D18C891A60B948DE2C12F4E4DB574C6C8BC586A1B57E727853FBCDBB4EB148DB234D8759B2AC8ADA2FAD225B5420C2B93D7FEAF051B7B768E64BC6EB83688B5E7E59059E1079DC66C5D8696CE758B42AE75123CA0FB72438DB97D39F1340B2891A19A4084BAA1A5149FAA785F09300B9DADA3C45F19568226151382ADB16617D5E59FFE8029F0513A7156F67D9859A13C2BEA574BE10E319F1B69740CDB176A962810B8AA6C368805EFA56E4AF69E908A205DC41CFC3FE69E4A6BB7B1F541DFE0A0EC1B29E3C199EF07538BC8AD7B0BD31B6A4DBAF70B83443A9C6C06268F597A6D1BC50171ABF56D18BB277F83203BB671DE404FBC4DFC66EE8DD4D92FB1AB2ED20FE8E9327CB15CB90908F37171D10E759BB8D1BE2C895604F87E2307AF7720AF99F0552FB15229B0FE7B45A3005E6CB0DC88A6D15AC7C364189A84A6615A344FABF4D0DD82EAFD42892C86EFEE6E9F7C248462E4C6CCA369CED819AE94B3DC856A3412A0DB90353E6C6D9DFE31913C3249195A3EDF9F84BE94AC6EB82969AF272AB8802BA0E8967EC342834B8A38163C90431844DB073DEB60B388710FF880EFB8283648CDCD75615D35451D8AE4711C1D7DB1AA59675061004EF8164AF3B4095F0E2FFC5433BA41ED72AC2C683D3959C9D265C302E0FEE7258B7C870F62D40961AE5AC43D3BEF8241B38A574F75EC7CD608781EFC16B7B9D36C3844B6FBF477CAFBA155B91061"""), - TestUtils.hexDecode(""" -5bd74b9ad4b08f18b54784c7c6952152a4f597cee14d967851ae2d781f249d926ebb4f4490487d1ab299a179928f69811f39a8a019bd808c500010aa684ac9954aaa005c9319d75d6049ecd99ad4a3dd535d881e8eaea118635cc5dea0ff3d4a7d8bd9d2bd00b78777f6528b94cf8de6ecba3829e8fdbaaafec7a16106457f0204192d88bcc76271fa31718e6ab4be525b04e547f9774fa47a8e4a88a4fd9b058412f92b27a2e191d32f015ee31cad4321c62ca55e572cbb7c2872615e5a2924d7945f1ef161e407f415b4f963d4cf6272d954923da0db3b04649906ef6e2da18592227b2b301a36298861e793b88e7fd1de2957d8a92c727b492cde702ef2b123e9968774604b71323cc4e7e58114c3ec7b59c94d9a17453795f426f706d98235c99ac4b4288d894e480efa3dfd19b14872fcfea1836ca639fc7242a55a0d01e1e21301f39dcc9aa94d2d83bfdefc26cad8614406c70bb96c149ea652f66f8d26ee0455c6cdc8e648fb20886334d512fd940fef6d0d52a14fd9c33e0be6077a10b4729a8f6200ff5a5669b3b533d366b81cb6fab41dbb9dde1581e4f3bddbbbd5f18cc00123c82e9f82412b5fc8970b69bf2e68fd5fdd17b7288949e1a7a6eab8986ba2e7e2f98b5bf2a561ddbd935802fb59a20262a77137c99274f4597d070c0c7ab5eb82aa445fcc882b1dd0a825a1f0a2c8181bb6c608a53704b9d587e555d756333bea70a5e73ccc5ec20260c8ba150a44232aba5ed55f49281b0e697527a59e4cb579d27183921dd55492cfc2abe640e1aff9147927ca2a1d1ac594c52502536d1942fea6b3e52793e2a410fd6ca7dbea45a5a696695100f53b9fe1f28bbc0014ea9fa3b134f2cf0c0a2b0a74525468bccc4677e3959d62f2cff8119e5895211316b448451fee29720a74d0e09bfec52913b0a26d1a60e404b2c2ccd036d73a2cd4dfef3d9a10549287d70bcb561a3d466c8933668f69d2e3f1a90951ae4def67d49fd09dc61342a15d1d576ab41b7f145d73a99faabd04b9afbf8491a28c5483674e9f95f3e4146ea0d9b1ca61359c604b0c821a9cce85e53b5e666cf1786100fa4c4f14dfc178b63581bf502b7909c68e4587892188934c0472412667e552bd32184a306148019d56236fe38b03799c2a8c748c0b969d9d6de27a0b842be7580ec8e186c76eadfdfe4222628448abca620a246214d2629b2be13cfa9e9fa3c26c24b03da758d5870c4f79f68c3be2bf16f97a7459795e1e30d0706f33c4f865348785abc4e6feaaeff79b1b45527357d31ccf575785390c35b2a4c87cca14fe7bbbe6ba82d96cb9bd6f47d9ad73ea3b061e030bc03a670bec41615f86360a01a37a3ccc307e31aa6c32fd558d362142fd5668e948441275f265697e4700d87853b4d1b8f50c1c9eb96d05b96992daf7e9d3dc5b78a62867ebd7b901fc37ff34b67af0ece5fe7050c94a43ca96af0463ddeaebee931bfa9e14226b2c7bd40cc99cb7b3791bd57fbab3d4961fbcfa4d9fac748d73b2de0c7eff554699cee1a72b197d6ad5343aa72d7d0bcfe6c3b458d24e7e75d00a90628100d635f032f24834a3dd0ca0f5fa0d040b98ac6e0ad4a3c09445d91d929ffcd5424800bbf06a747c7a05eb87cebe5d64a383cd77a7cf3dcc80300927443692c50c7aa0d12e1482f071ac1d9acd625f6e8c59068f1a08eb163a11685c7699493cb28b1fcef193aa1151ae7519474629485b7e6fadf01f369f05a1c37d157be7560b38a59643ac997b18a16dfd211e23c1c02f936c773b8b3440115beac0fee20269302ba0ca35d0838799ab67bfcb300e89909e2fa63d83b035d855bee14c47d847ec7f7ed15bf16130ab8fb33eff281407f376b3fa4f6894e1681e6eb025be02de783b22680e6ba9c4646b88d91e18a48f751fbe168096bbbd16a2f4b2a13085158d55c5283a069362f83c9247b0c65639aa21405f343a19dc877843bb72e39e6cda5b7ea3f198cf59c9607e1c5f09bf8962bba657f609f4e9d3ca99cc58f6283689c9ca4d0c4f659831abd54e1f154b26d4b7a103d9ca6b6112cf5bdf0e70103c8147fa7f5223665f75bd153d9e5aa982ac475413083d9baf3cc20584c792ace31ca3c3ce87cc16fde69df770f717bf9b0f10a097595ae2bbab69dce06d1973b01ff9922d8199735d6e16dbf4e7b94493b1106fc938ed093eca657e173b107cf995a251e5b6b7c97daf07bbc2ff89f5f52121522d175ae97cec1e98183f646defd2b15cfa13107cca9ddd0cd9912a23b139f84a2265e35b7053cfb7be23b79f28fddc9e3190b0355d0922543ebff420493a9ee7bc1c18d36e2e76437404301180bd3695d7d059601e204f46da1c5224966fe6c099f0ebf6a2f8c61ccfecf12f9dd4f1a197138e013654280a7c5bd26ab1743e40d8971c8b6e4908113b84537a410faa756251faff8fc8bf0fe8d325dbe0c1a6f7e099535e08bfe584b232a36401d9340ce323eae8e8eb4fb3fb57687037b7b98c6ac8fd7d919b71beb9273f4234028ac2f034685c81e630d57a83162aec955bff545d8d0a9c24d4a023988890301ffd37af5824f59384f596a4c242fa8378ba2b09908c74c8144ef1a6a4ef0b9a6738f8ec52e114b9aea248a8d2d3733f71649222c8737764fb440c9f2972390d3d4ad7467cf238f48a0a299c891210a60deeea020e4b8a56d2b5fa61aec1b341044fabd4abda13c6e85fd70170d18295538bc8da2908c103a799448441c50250455f5481f7a4f6eef5792f97cabeaa99936557b0ca845bea86234c1de788cf2abc1f32a80b13573dc2b21b110fdddefead44d94f01ec772078b1175b0297b0b6de6d6097e8aa3e5278944fc9e7a884d3267632917bf56bb53dc074ea14a8dd6e6c1a73d9959a5d2ae385f5dba4b8447eb451dc441832a69c1c0a3ed41b0997878c966510dd500d61666827435b7dd7ccbd125f157a419ac5b614ba6d65438b6c99e4d8e5e6776809edafe8fa6a76e11f5f400975df6e6769f2c2c1ffe3d40482be08581d5e79088fbff8da514abbbca7b3ccfdfaa1915c373361a971ab7f5c1c09e9499592dccd610f14ed84db0a2be1c94e5bcda339e14ffb27af1ba66c7130f45942c687ce96ed553ad7776dd532ccbb0faf1aa41b7765023d56c9068d56c3c405b8b2890c4fa6bd79466a4a146657d9248d8a348bdcf41e3388993e8ff2be2fc8b8dae8d15269fdcc040f7e72872539205992444a4d19552ddc5e51b778c5b5786f2d7b79036b73e738d7200aafe96850887c44c982b0347c7646dbcbeb4b6b55971004ade87ff20adef58d3aadb40d320d43585e7e55da08344dcd9fd8345a2c612f656ae178c914b5662d088c3437a6e5928d3410cf65dbe2ad31f1fc3781d6a5006ca8136233814be8d655b94152ac70df8cfc6f9e9101f5b53cd5fd37176341e1eaf25f2fb477d1d212333ea200a5e9da88b19db4163a44cd4c9d3ee1af413fc6ccde64a9cedf21c8b8f113d62a63df2233f9a195aa67803d632ca873fa11069b5998c1200dbbdb9647a98acfb4e3229185b8c220a6079c72bd4645b04f32ffc85214bffd8ef2cf27d8459eea21069c13bfe052ef92a070e63d05c9a9a82699676ea5cad84e508d7e811073e17bf943516fd4512d53c7b3fccedcab36921945a19d0ec3d9303bd479a446ea1a5d5e4adc5a97b92db843b54de9498592c4859011bd4df412a6151bcaaa703fcd97e702d96b0ab14d7fb0ee225f8097c174b517ea051f8f8b8af47a75a93fab99ebfa84f8ba8dcc9c9927e24f6c99b66f34f86c2fdc88755154f06d9b1ff731411f35377e14d2375480b688108212f75d74695008a61fcd452b6dd23c4d910c409d9edb69d294a5bb46fbda29d6b31b24613e751b3aa8605046cdb449ba86f27d226e91757a242ec2e9d241aedcabca88269dbda5fe8e5d8bf4a4cf1bb1585f1166d36a388a47241245d0001e35a790d6d201a92f34ea315933c67aa26b4b22ffa7d87482c7a63b7544ab511644b9e95152998af887bdbbdeb6f2218f8936d5fa50686216e30db9686ff1e924c850cfa31ac950bba1cc1124a892fa1c40f62a99eb452a344f65a1410f500ab650f9e91244ce5e962caa13832df55c4b41f53509d13d1765063380b942a5d4e718b9fbdfdf31259b879614b2bcd5c7a637c0868abec9be94a132be2c62111e5f22f420630ca64031ee7f43df2f8709e9b200f0f459d9f0b4bfc370f6faebb0345da46aa11c975670cd94ade1781d56a3ccf2c0729a8238e9cfdb1ee2e575c524661d089f894a1502bde21465f430561a72b835a39a70c60d64f371affb8ea30849956b767a5ad7648be643e0071cf9f08e880f6926ae2fe97b8fd9ba02dfc965b3ef7c102eb207555f6037c634496fe8de5cc8ae0184b6df1201e8ebbabfabc4dee1df3a15a46414e5627c7b99982acf3fcc7806d0e8b9e9356f21f15366d6327a3fe4d332eb8ebd410407b1b57220ed702dba8783c1d7088e66ff9bea1af5794c964cc95c415b26598d39f448a428c575de927e7eb129539a267c3e9d2c7b844e80b1c396810f8b703c2f6f141339bbbd34938cc12ed634425b7d80829a9cb7c8d1f3050f1351587a898c92bda2e1e366b5cbec034750b2b8c4dc00000000000000000000000000000000000000080c16191d24""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -48862a8bc5235f5337a82329e949240dade33fc7d17ace18be0227ec719ac4f772476711c39ed4d858cef667f47b1f58122e3439253b354ffd3d915c4bdd94e14e1437d30cb3ca8309258b6817c6ccbffab6c0a3ee80a7f9fff6ec3cb6ac304fee454d34bf07d0dc401088d8e24c52088a2ed7532b1d1132cc318417a77d907823576447516518710576715261823080317441353842046341354050886265582772661606782518508611552437807857666558606283636012283372443712522471787143475036431221671374672177808348236368861183147027640303725752144220330577506201512281522412264744467558561844471460507113285137145681843753253233607103662808040646312553435805068686713021651551288186147173278000431232842530725086636536773248376333615710033580724287113217601158383102361765586225028003127168204582787754742332377107533753763435244134327846130710212236212502511434853724442254425760443666601728131748563348431443881772136248213437648571843333076605047807073574052864732182876230740017065188788771270704823801338454355646476150321745651674118477033827545476526811583337650082472640360778341752532318807731320471123877320418483134405327185031072657067505600530116026654376786484528715283751501655402235447554314302138750568000710650360358713328803146805241243333606411738065128618661601325618272020045460442876423666675125470876321815280508701035085287150558773181677875461325332283334727340248486766321227570432481736758471138718778336553655678374617640076187623705748317870051465306308631471164143125864382210850207037600801483176770823170512204183673005287714683025272251861111883335402830333124682817107801561558206108211583307868462172333836188447073517304086124212046766573468260178581350370628407538556485260427522413086381780024171423115611318634706688173315285184218216530827364657525801602715121163523751110241061654623125368751825650235250504687050676307022630474870177551460272562683173561881600018327858345460086545888832362730652277030632381537043054430486562858656784006651831205857461151350742124275134228231555266425448144823577652200562843884080828074164108067807813048034752063108461004688565567130111503260414200662701827228631380277228312536583180231613518706187317673565216727460305500638601142676751668444553816121742080426160705368816025138664265303251756273518518730862720233072246811417507756553878850845757381845611611422648644164086485286238466162363344057001121677343220818506083371862137010661622364338330831553574200538183745361417458005568372756687548621686745287630528168882410633428605048633053118632852608812837104176254134662751162608810027054020624335538722216288583065164064022144016266843214800315064071387443667213588713004105783804025667840388024407076618450445474568131706508618522810713016468684712241576080034862203542207230705607763336537074655487503315215184658500108525582024400658005247070468306680407777644277626555608647187201348840567607555587763581721687238845086303878721607273784881465433510511023765272770875070743787323471685410337833852203753384551444805788008435488871070137354718580371634437430075140476153835584426742701702300124680652654464582223832650777543526458673251282420373030035772844807176263355c300aa552835b4adb640a708d6c7fdcf8276730c8d30cb56df2cdf1fcee402cbcac2db33776f7f917458b10a470c1857d61131fb46e412a18569d4b8bf289e72bdbaf3eebbdb5fa6586c2b06ee55c39b2bc31db5dcf959366eabe602be533c08ae39d64ce46396bb1e4a8be9ca49afeb48a69e0084b4aa124ed85548ec4e1a992126bad1b391b49b3c711623e17544ec5afa38009bc99696dc6c1a749754adce3573aefa80f8a8586274159a2ac3119b4a8ac94d3766fe22f6eae181c619ec2fd487fe71505e6abbd6424f760b085d44ba33ff9d1a4f4f3de4cc1aba85b44ba77bb5545e9d652e264899e52d91a6fd02fbea09f7eceaf4837d74c8048c18bcfe4e1e0b9800d5c9ae5bd36ecf89ce860fcfcb0ee2f53feb79b1befc511e08fef900088763b959c7f497356c89a23436a98f70404c2d8dbe04c6fe0f82f781fd2e86c20464720363d4b84ecb44c5c282f665f28e0255fe98f260f711619c4663978dd9aa860b768056951ba1187a2c89436b89a161f14d693a230a5b6a65e10d8976f08b30bba4c59969a571216a470a04ef29a19b28b346093349e9a1e1836e1a9c911db91e73636592af1def9a5d6ec2a1b92683eaec682a4746cbbf8c6d5f72d724c41787cb5fe344fa20bdae6c890df2427d52f7bf6bac0234a763053727d24f580c68e890fd0157cc671f686a3d119996b3d3dc93ae2174c4c0883d2fa3edfaaa510b649db5b7d4a927f71d577f45dceca495f031898eada50604d9e7858ef6ebabb6f6249ec499194b5943488b010bda13ae262cd13f587c8ec42eba297e0f76ebf1be24f727071ddae5e32234742343fe63dd4cf59ab948a32beafb14335cb6d0eb60618ba5dac68c83639200408d90f5238ed455ead4851b71f21b7b9eac2d2e63b54ffd813c7366656100e3ab0f7f2491e3abbcaf07fafcb145e5ec677608a3a3c02cbc5e33d9bfc833ddb53d4da04fc3bd9b518b9c604a93d87a7535473f44c050bc73ebc62ba042c47d9c384b3de5e043181246f9bf792c385201173a5c759d18f138e3535e42f540f50c42664992425f57212bfb294d102a1a4094feabc90b27bab69ebb26ce4f49999cc217b7bec571b8c8b4aed446ea4ea105a68e48b9b73e4213c9f7355424fb40f78ee68901947fabe7e8c8be7ac7cf15eb7f6c93d424f2695b272641f83f028c8e13e0f9f2708d319554491fde76759b444681a6bc006a5bbf1bf9f115a37fd99e7686cdfa1312f9f22e915fe65501ba51df73e403e12baa7093088c27adb9da489ae95aec3ecabe59da3fc9036a801fdebf5ed75ab072e6ce1c4ba60bce26a3a4bbb204a22e1114883fc02471931b9aa472ba85731d3218255569f3f3938cacc9a0a9c86130bfc6c50a8574aba9dbc0f1423ff1c195dae72fbc1d2b43eb8bf59033ca66ea7de3968e1e21c3f1e8123a8e9696b2512693e5a2a29346ebff481192f268497b5133854f906114abb48efef96fc4d3d085236dcf5182287aaca94dd75e8ca0d1cc27fd25f7f7c238e8ef0c76d9bce030369e03af39b667a87044493c28a5e66ce15df046e920763e2c892b92216a563e82aaa93410c69cf06b32d76ae9c5c8be300c02fec3c7f4c578a7d74861e4d088670d71de16e56b0e2fd10c6449e877902dd324754e831472ff2559653f1a4a3d00cbef4c3c9d78d93fb121a69f3e1a0d569ef3a339c9f22e2fc10db1fe26e009016a7af39600f4524fadc422689de41fecae27ba755f39974acf21532f94b47cdab45b42ae49e89e80be15287d8f63e8b5cf075055209743c7e848cd1cdc0c24b913768ee317704601a258f31c46a8b20c1740e4f3b2b672b4c5771ae8218c8ec253a1644d1f36549aececb79fb169b31aa0c941da99c26dc4b6e3310ab69fed8358576332c82f3276118b23b609437242ae6b4f0897f9007a661167662b7bc381df4bf1bbc0f2df58f854ffb42d9735003a4fe0380e479e3f9ac63be1daee8adc35326206dd158e8c574f3292207fe4ae5d0500b7ef5a8d15686d2111a040a010691a623e4734d3ea7c2f813a897e81d1d26bb40a4b19e896294bb47602cb0cf1acdb97892ef3aac21b35c5c7cc111a437783550388aa97537a44e700eecb4d5a090c929a785ab5c1318e731c93378ef929e153c6f5ab343da506188480e502bbd2dbe9053df466d011e7c8a29a19eeb71e947286ed418618a6fcdfe157b4dcf86e96c665dc7714f68f0c61c88715f9826b85cefa4788aedf6489dfe53e26db0dcc35521ec218940935e9d02214962ba9c826a136e8043c2e4287eafb348f427ff5fc56f3b0370e5e2d0384f195398e88cbd3817479750b1aba1bd61199623623392d19e21a2edd0887766183567e087889e546971429180f0564a91e4259306a73baa9f12e142c4107c167293ae7bdbc13dc82b698d729bc9816b266edc814cb4f7e844b30e4fb6f5424202977a7220f11e8065c872e63a2545bb12d109f162c8dbb4ab9963fcced90b1735a4e2de740968a6f9b2ef93f9166a94809e9abd21d79437821766afa021909d075741f76c6412a7af8f05d03bb28a30064eb6935838bfc848046b214f43f17bcca2290a8e769f51979bb7c2c9ec7d5fd960a0222194e147164ba3e0552c4c225d31aa053b3c5d3927910769d40c26c300c8ae8b133266d2d9a4ff8a2141fc77863e3130e755c156a1c672475f4b091f956307525357a7f894950c8deb0fdb5c6700c2c6558ae00d29aaf17daee47be70be6a2206d39b04d49fd2b27e9e3b95ea995a2c721ea172d3ebf3ddde306942a030a5acb5b25b4ecf0f9f42d172a7863a12df9ab3015b5a7bd4b370662285a55690f05fdf3d66f7f924df032cbec839c0142917b4321cc8546a6ca0f32e983a102968c2fd2bfc150d1e7a2a61b8f6584beee3617e2a287f26293687596ca6378d7cbc19b45855eb8cdf16985c0eea06acf12a3080918748659fdee069f88310275f606f5232b5b41471aaa6e59cb2e534ddc4839cae92291dedc946a16ed408ab5cb607264b8e789d7e0cc8b693a148e0fd3c22811d8474247bb90c6f70f706cc58213d5d56b875903f7ad767ee3d0193421e69d88b6be7da34736fb36fd53b9566ebe0394b458a1780d1f20b0c155de48e58afa27fc211526d2f4ecf4f1f0165488cc3ecdf15c102c9eb7a22cdcf062c41664302deae6a3c48a6e1a1faa659dfabf0539c47c9245fcc4f8f356d325a36aaaa401486ee1a375725064423a5d9114c35b5e753cb8f6162bcf3fd071f26cef612017f5648fa0764faa4b805724e798b3285a6a93d8226de734cdc63602089f84fbf2f09bd8fc3c23d1e57573b0da75fcfbfd0101a7921d6d6eea998c6659444c0c5ad15460906b653adf7ee831206375dfa8611c4ea5a0c429253bc6cee49f69ceeb4ee700fad3e43cfe04177a4838ff2e4ffed9484a4c949a85268645f2494c01ce621e39c3ee9d168d76e3dc596fabe4a4067494b9ef6308b74cd7c578da7bae4bf8ccf566c2997b583a1266d8ca9"""), - TestUtils.hexDecode(""" -DA2755DCE32D07B6D2C2DAD6BBF7CF5D4C26FF0C9B6FB9E064B51829A1ED51A712E26DF8047B487FF0755CBBA8FFB60DAC3C45E238608F48205A582BADF82C2E7E83D672057B9A9209386D2AB8D93BBDE0C522CD1BCF2AE95573749E0D51B85EA01494E3BD97D3CE0A61B26249E4BB94F9667D6556CC4313669409D94AA4F3BB9AB70F736D34245E2A789A5FE2917D5F4CBE43010C5215AF880118E1F5FD47A4C195F3C74307523C688AB76B7CCB157F75FFD79149B5508E7E527ABF718CE8E2E4162BF810F35E234F8CB65DE0930202C1896DDDE02BBBEC8D03BAA12AA1C91EE798FF7ECED608E3DDB7BD04A1DD9139F4A5613AABCF7AE495F9CE18D73BDA0C91583B72CCF6A722C319AD5B1051E65C1B91DD05AE5A77220BCC7576F9CBFC8A12CD55883AADCAD1AA109522F286B00B70C8E3D4C6EDDAE7E1752097C85233583BA0E1C05C5624FF65A3F3894158982B633EC92C24382AF48EB2DF5EAD30759E99D67B8BB1144939F4080DF0E1689AC0D4CDC73DF1CC2FB72B92D5A69019087294D5F2DB196CF82B7BBAF953F0568663596F78B5A309738BB294F7AA3FC5F3ED5BFD4768CCF3304C836B476458E14B233C156C8407636FDB3EBECF49B97C96C31F51353B79C378C6F47F1913E5B14A82DEB126D688133F9139C12C45BA24CC9C7E2C16A26329D463ECF59746F5A99C6B03896E851815EF36F499654E2764BB8BC60EBC821C4D0B4C363EEB7849332A9F1053A975B092AA3AAE33F06F760BA1D76DE07A1F48ADBEADFF1E17C34F9D69E409DC5AC83C296C402E042FDBFB0B6B4E023B15B318337B6A1CE69F1CD3D93FDD0FEB7AE259A41383939253C317DB949E3BEB9C8F7A79D083BFB46C50AC00D382C846B78FAAA7399ECB902CE8B73A1E89374B1DA65B0723C67B24899342DF13C07A0BFE3565CBEA5892F8979E404BA84847AF30BFC04D8EC77B1C5B9400CB97622E6D3360836639670BDDF4E9CF9FE3D6B98A5FDA42422DAD6C829B9E33F53686E2663D232162D3A78A7202EEFBFA4917BB8E89375279C96C9054C2570DC3D90DCCF0E418B69E6443C1B2540BAEBE022ED9A9620C030377C67FF4C186A59459DE7DB1ADFE2923C01D9B8D3AC940486052DB67EB67A257BE7AEE0D3C77BBFFD0FC7C94540F11DD96C5100463C27D65D3BB6B7D867590D573D1C1BEDCC0E8D122FE4FB82F1404CCD061DD7C3D15287F39CBCD2448DEFE1FB4ABA858DCE13F74414E1A8C41B730A1DFB45B859545811C2A9DA01C342A1F3C8B916F60B5E4802BE672C2BE31531DD9E7014E681A8AB1240B5E3D5C0D26E7040D4CE05F9017A32E1C760F466A8D7A68FAAD421B2E2D886BF0007858129DA2F6B92C4CACBC1786291D7C95A3F6A12483B750FAAF1DA03059F89C761641C0AAB21A05E78E1131B8F45C60BB5E8681086717B918BD4FBCFCA1BB5DDD740BE289D8DB1C24FE083B3DCF0E496B1941ECB7D51182F9CB9986CF3F04F0CA4E01C63EC879FD4A3D5619EA1085B1431FFC019286ACDF3B4AAB03D6265A7B18F24CC2815269681BD37263B44DCCA5CF6FAC2ABB1DE317118219A73095D1BDA10B66B6B55421F049B71E759DBE6154F1DB98A7E3FC877FA90217A242B21F39490F2116A2BE8067168F26439C8D1928255B5A50CE1ACCC222087536BC37806FFABA03B7E787B04C2C67C1B0BEAA871F39D3DAC2221AF44CC7089E520BADCFD840E5EE24AC53FCFF1E7D6AC26694CBC15B80E48B10C054E8DEB00AE387CEC9972A28448A6BE3A01D5EEA837703D2FCD1EB2521D444F900846F59074D715AEAA2F46E956365B7E67C5528841145C442E6FD7B3D7171BE05BF8BAA415260F645E2FBC93C46B9F94D2997929349B88C2FB1AC6743B73DE66B30B44E5DB3E07E0FE9713D9D7575EE4E40327A58DCEFBA0EE95E22D06FDFB720993EB134073A80A4F06F8303C7758DD37CD7236E5D80AAE2E9569834846E7F6C75051302486B2564A1D8D987D1A3648192A63EEF4C2D25AD41FAA02C9F227CC9F655A72CF7207ABBC66F9C822EEBDC89833757013776C11C310A22C226ECD33E5B0772AE2DE8B8E9A876650D4A57B863BCC6197261D7D06903D414AF0922312B7DE6D9E64F99509CAAB8D808DFC5F046BA2CE55817512535EDC2477D8462A1817E45D33B9D7390A11E30C3860CBE2C4B519812ABA3AF7050227759DF3B6FCD6D3EE5C60C1042DFCDD7880888A147AC47A282EC51D0DF664451E37D7C40672A27B965CDB805CECD3EEAE38A0AF4C2349FF39947659686D30B9ECBDADD80C9B06293FC4BD5E7A0E1E9E883D7A4EB05102CC1FE45F1C9BE23043BB458E6B8B6C1C187761004EEF59E398B1124B98B0EC0F7B29394418B38D8A3003ACB85D96CFA0C3C63B2ACFDC2BF5540D029A261243E06393253B2C3FE253A220DC7AE4BDE0AB4B386DECA15FA2A05465740B072FBB0C8E81663E320AE931A2DC7A627C805AD80819B9D12EC271D9D16736156195302C93490B4F85E8B4F5199CAF233974079A7AD590374C4E5589D0FC26F70FF2CE51FFB3E6742AD5BD9840F62F745C42D6085E46182FF73FD079BD2625338105FB39110B660F8C55D0830587671CC802AFF63FA7FCFB3BDF6D65B362CA0B68B31FB802E7870C3905B04B41440F549583EC87218DF6A0BE0E209807AF053CA121D704DC0C90A499D1742658BB096C776514C89F6B2D3FC7FBC4A38C10DDBD3C08F64AB076C9BA4C7BF24EBDCE9C82B1BCB8E55C4135976C878B95B6ED108C2031F4E53DBB19205A7109C50289C743818B90ACACFDEF20EE33F5C9A7142B5640F4D875122E0E5"""), - TestUtils.hexDecode(""" -1fb3b6053f9518cc51b4a20cb33d02a7abcf1cad4ae7806efe9fbf8652e3755275a641f27879f163a1b265e886a1b21b129d48807bc4933df0cfee53f26305170c547145f3ff67fc6f317c5ffcd94f96fcc4453ac3fce38cbe41b6dc01c2146ea3d1e7a0bf001be3136362d75aa2785efafce667640dafb1b39d555a106b8cea129c5432867e0eaa493c43d21ab388aff1b6037621c1f134adab6093ee7e5760e9f33a0d8e8c63cd70c86438d3f94461a2d4bc9f41243e362bdfb4c809fb28157a6e5ab2f5c6e16a7336cdc4183ac4272920485fe34fe03057ae7b1440aaf99f28ba89ef1b0021cd863ba36e8deea60aa14cc7f2dab46dc401f12f5b61fb82a195781e337c195160fc474e52aecf4c6ff277908c481d51adac39219b29fa7ac703027354491b869e3ec404b4c35b214196822828079ec85ed0edefa0ed2a426ab9bf4c3784238390e8eec61cf7fa1c4a1ea1308e0815202f1109250fdcf69309ef634c4f0b134ad6d33ccb4a5e30c0472bd292c42de895de1c5989922bba6004283fd1376a0a263ebf74e414da5c058ed9788a862408de4de14b54d2adc7fb5e36f827f53b779e549698c8ae7fe4eccbca4b41b81e7239114720147851f0a72cd3183e33c6e82c557a5eecd4d07a824c6ea653168bdaac37a444fb63b29cbc35bdba265c5718421dc104206d224ef985992786180627df4b2f3ec5e6c200c2e0cbb6fad82db3f54d67f5fa7a9d1396c3b8376b3d83af731fbe8eed49bcd99e4fb693c87e259f20f61a6d67c8d87c967d65d03fe81e5d5f14021f8deb4d1a5d25902065e4ef707205a8159f02b4469be4c2094aa73580572a3568481f63e470bc86cfdf7b809c17801918f2a6f742892aaf696e2cbd2bc617f92efc482dc6bf8640a91582e988112cdb6161a41ab879e8c3c15e48bc2a7dd6b4fd25b5e7efd7388e6f3959bbafe518db3b73df504a6f6cbc6086ff160b3e7391845c9797a494000a23a9488008a595334b7b92db4b2f9a267869ee63b8d3b83bce7d57b9018bbc858943f0c7e8fe0c94cd0718672e4473692a2809423b2df248b2e61dea545b2f1db86b7246a345ec591083f4662b64664bc9200c3ae8ce7006cd795cc146aac8315129d62eb20e940aac6430165476742a19c17d906c3fd94a543b453a2f5d3c880ae6a1f64125efef20d7a0091e4bd66801fab9f7a396c84c4ed28526fc1b0042d4245d3f57731d56165e26e1ee72976cdc40b3574801255709cadd4361e7984527e6b9168a8f1b507b1a3f94d20b76bd4a0fd5ec81274207df86ef1b18c09e4f77d0670534a6ac9eaf076052d6d037ec469ab453404749c3c15cceef412a87301cd438c1e5c8d016a2c125a296c4deb4a12b4bf04d9593bd9d66814dff60549ec0a91acc5bb00a2f445c7989af4d3ba9d35868f7fd8a3687495f2580780f8a4c3e9f012f0cd07cfdd7e513c9a84bbf7dffdbe2934480ad3cb241a155248e9c30ba5f5d1574d73488beb96ae47913ef87530dbc9c941bcadc6a69b9acb06be7ceffd8cc7745a4fcf978c1fa126a22864e912e9c14fa73914ab1b9ff31988e6c859bf069bd1f912766680111d9996ce8565704046ceb64610f0c6162f74de87be26889ba868eaa8e3fd8c1c4eac20deba9467f4fe5427c06192a5ef0e84d2a063532131a366ba13b48a3735b7ac98d5d800f6ec7cb5b8bd604f7d3c72dc56e126ae14cb101afc3f5832fed4e94e5e7614e1232e970597997cfb3b9e6c5bba771552c38c9d6729ba0ffc2bd146754a3605c64718e9744e4f7c1ea184c477de17208f7baa9ba1913598889ac44b1d30f5b81aaa06a42c8f31c889737a8d15e6d473e0eb16fcb57a56f2fa9169a56a4d5b687b50e77bff964522f14530608fcb7f405cb5faf36ff235869b99b08765fbc6e21c91833a5c5e6e85aaac997fee4e800dab3c8fd5b35e1cd639931690f656f05b325ed80bccff2013c683b0419b5f43c3c14c245e40f537b55d20165a92e7b6bf8af9c81cb4b205f327b946c39a0ff087915b015c77930f221bb6c2c8d6500a521ea549f2d7fdb4108aed7a5aa6217450e238f1727535b3635f7e1b15b583743ffc9a2436e99c8f6e2a46bce90434f345090a76c422d778ebd3d9f4364af2c89d1353d64ec72d691d414f56c7a1747c7ea3ee8b284d3aa6612fcd30a08eb7eafc3dd42f221200fd0b394c99235ecebac79fe467c747b3ed5c09ebbbee5dc240287cceefe186f0a5b5f4fbddb0675f0159c750d715d0b01978cdd4e85ba77cae57024c6e6348155071016a96575e5f9b227c87e82db0a8470124b6572da0cbf2cab372d85708adadb04165b6cbe6950253e2c1034537ade941ab6633c1ee634371764ded5c131cd57eb9d3a794a2d26750d01498214ec9b78ba4c9400cbf7b910643a6ee5fb12fe1f2cb348d566e63dba6c1fddca6a0a6644eb7187a53d0b5d8bee99d31b92981fd81cad326a8c107abafb623a0d11e861177a58f1e3307fde29d63a3924bbeb0e946bf7f667599b92d98ab6af9d896e2ede95ca65cdc98b07456bdd037aafdc4c91bd387204ba7ea14dfe387430d290ada9a8296198e89b746f0264ef95c45ef3748bb9806f24a61565624fa84326594a572c701602c7317fdfa1990426ef70a5d3434e7b1ffd779e13b23bea25d63dbd7d9fcb713bca6c203d1b2f337a6e768ff8d5a1b1fed4d69f973f0e0a59f3c3527c30a1942054d3cfd04443d4611259b63c14f8eff56d17465e29a824afe408168acb215b5bb0252bb7c705280cc003311303373f30074bfa769676ec7a48df2d9f68fdb043b035fc1807fe7457e01e794a5130a857c56e92a8dc234f03c5c7fddf0f385f63b4ee438a2ed5a027af36eadab17dbd7eb9eb541e6ed5af00e1415622b083855f23d1c4639dc7c5b95c71673a2580e88092e446c29236900f685219aabdd06720f0e50dfca6bdf53c09ab3477833bb835304ffc65f1d6513acee999682bb70665806deb596566ac785afebd6ae7227ea882941257ebb10809923ae562cb34be2acde2b8b0de3f2a8b81c53d47a80a3b1d360c9cce2b484cc5dc62b948a6f990aec5d9c34b745943ba361e14de27232dadf5c72ad2f47e24d0872b2517843f3c43d1f348fdcb5fb589c4b304ddacd5451771ab0c53c03a33dcfd13e2720ddbca5fcd3f112eb81ad6bc1aa059e2261d7cfeab30fccb952a0254d92ab6c884ebe18c878adeee97721267393bfc85a5a4ebb7327c6f69a71a864e8fed0665b0ef302f16ca3d6ae033bbdb9443bc40c78eb7b3c5af66ba91ecd852e4682ae25575cd7d09adb3b74798d14bffca4f5bd837e80afbd77510ee78c32ee219f4156076dc6bc9ce87971e232aa4d034366a3e079e21cd17ce42c3f60f47225ec2407147bfe01eace5552956e6697a0a64eaa3b02ced7a39d1a1c2eefee96c2f8bd2c122ddb0960929e57247fa3a85fca43f63de635ad5d4fad02565aeb7f00db0c55c5552fcbbe5889b6495c59541a77a8dd20503cdf916b3bfc8f5e87b217134f2fc7a6cd13a736059348b3106bc431d929c09d4d6c0e39a93759953ed35f1df0ee90366e73cf0ddaa03bd39293e95929cefe9cfd06079b592b42c6e9f47ad6c4263233123092155047ee7c48e3e4e62f531d3810011a76f477a8650bbd7be790606775e1f932dba57e5d4bb2b2401a01a20b83b69ed97bf1ad8c765c93d8d4e1bdce3a524eebd6e54734d568711804d4da19fc69997129876d235fe53c78408e78081da0edb8d9c085c863c6603c06b8eec7733dd5713d79830b8debcf6d3e9183852502fc9bce62e85c20cc098cfce099d0a810df722d67932c2e3fbaef6efabbb67a83afd4cf9514598f316b72551abff34d1d13c93dc679bb58868148fbd33628d8279fee785dcc605073a000473e8ea9dd6646242ca2dc3c4863de1d0f8ad955682a9ba9fe52317c2e5d130892d5b6dbc41bd0ff3148308393d717ac0e96fc1f45e0539bb55eb50549e508da7db93d68f1711342a9d6ab64e178f55cd6eed8e8c28a497336fdee128df52ec475e46cefe3651ab9935ade5adf0b29ba5358d35d3b6516c8d3996aff1e2cd06363de48eab1bd00120a0d407b092870c2e76b276c70d4d7ac85366f60f2343241200253f92de66b037fae4fdeb1db275b7ae6ec196902ac69e9783fa6684584dc9067c7cd4a68405e0aeb2a4eddca1959cf788c0a516eb94f0824120ea24b9fa2354028afedbafff79917820d4d15b12def7f9efe49899c715c7b500f70980a8c799b93db838ca2859a06cdbdd5f84ced9987e1dbbf74ecf24d5f2484950dcd57347da8b8aece55d4afc7adcb0b232082157b0bbd455ca7ebcd0ebf257b184b3eb0d1ef736dc7d02681624622947c4f31f0dec5b430616a19b1300427495088898be15f27cbc4688ad4a93fa208ea20bed26e94984525db33a34b7631018e55d1b8ec54dc75c85e0c9a95c4f212092801e1578ea2e1a8a7850952a1bbd2642d7328a558c0fba8c167eb38d105d31be1cc497460fdc3973b7f004f1aa58fab493d29501e09568b3fdd7b1c8447cf154bf57356fca7c412c79417dc20e2d34485e6c757aacb1d7ec1c6d7bd97374b2c2d0132f6e749fa2b7eaf3ff2b385c6df71c232458babc000000000000000000000000000c10151f242a""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -4253129ba04cd46ebdd117f477bae35bdc6eede60df6a94a580b28abcf8bca383dcd4aca34a318f090c2e236534f4553838b273b1e19dae5a0a6e70df38f33620e3f56d4771ab8edd27ecbee13b41307dea5ffc221ced73da8412ebf90f75e2aa93345937b9904a2ed07488ba7ed7e4a81090fe062407bee215ebbcee51da2e828261181076284017672316008373864314512556411366470351751143502866044174407124820856040124488104747272515157471031535270113332160138362452220861568703310713026080445200335431724117012102776173821368242414322435313184718783246033107615466525681321552700103062228600000840774147702724033480557386354023651330688348535523803036286522510808766140743508450507325777827878388653358828424230141362086225062486351844571254365553532888807256428865656187770583403731862707663306640370460154257323706150367768487752435420042742000513678740407626635145864204641386338346560256308062427383571700177385585843713267024345387573110261418834745377370755318806263742534245857530816728343281562502028178701327753748533284210485466764187235630784126521676840661086401264013631703807186376500638136763122620442512142676466534030816270880344503216655687600047664410317731124621554758747218007662107353206105566073663637081672051334882604615032232175024506440432064120430260450083670328621582421263218843557281084706151204677842415170883722854410034757158564146427433758348366115784744267072344336485111151074443578456122766023544273207851855377881232551654715102510021504036666050106505181807202727601475270388715857665482658610113502167076780287676474561852324234606005157113274325186444642470880201270443712501306260351304114821810185605303043238284024437451570501376818478325118637534878857561622073620761344171515046664327007668000250703168414702270712204854655478324382503648846018628324746162773268200331863534240746136243061806136513225515463704681748620517137525684815620567421644267582106184168262077744160744640345713287127475166803710860415216047606452515703723634771387073742473032414765016712438084131313707771744375662530042820602754771770732427347323015241056073588430468326642327633874772054784104288772127348184355306138573334063016081114262046005810176822754772155254184315401382566282513565023308512153305535166000375507505468255224611413162316477215685285240584136066250035404431257447544533343721406440410427154285517050886855413301515367856571818385181216353325456801442712220023633562061334384508683454077205058063306076017652740557282608146518640164805154524586314027143055784545430125532435466675334181613266512656618060266525616044526063355534408344640284357448206104624813586486385052737045107351812257722833754030787678053325738580428316055350681501643208864705287440678342323163267667345570457764846348710225558572315558323425473721125854230718764686451881373313105016726435620741154216770706556760718055054212814415730370754160475426486577163328361465582221712086205043168328155862243642470841072233880412735188447232451728835468422631647766377207132637428468083840544508143008035708525281067178685206541635074543234105443801377662237826630832273024730474837626134806557367081725831768171583080066473638657717e70bdfdc8bad9d0d859850ac3d18cbb32b70bcba14d4e918230a54a8132484ece197ae8a2a6311d0966f800594271dfd7859fe7b49e9a8a0afaf0ea5a4196428683334fbed3b2925023da8c6db5f6dcffe45d237072acd40f8c75f205628f6be070a24cbe2f41d1d4c08d2fdf9576e08845c31fdb9041f70dc18add5a64d548cd0706d8180687d15b98bc2973944f951ce63765f9a8ba439732a76554223408b658118fb347942439a2a1a38f9074b64b9df696f245b83029e59b352f5811a11ca86a46bb6a84c6eee2baa3672bed15876f1ac1c7c90d3aec56ed2907bb991843b6c2421b4ca6e503bea965671f85dc5afdfa79fb5e512496ee8b096e12cee410c973aec9673ad11fc802972195af9395042c71ad560ee16476b56c12c94786985928874633aa61c5396f819588d8d8d59b0b7b507c371060a974fa1afc142116a1fd7cd6923a7234050edec5c3096d11c9ff9c73c374d7a8e2415be0f277716ca566ac3760c87a98b2b7ce7b2f4932d8f8f2ee9a20a17532934642f39712948c8db39c9a8d1de46a4bfd6db147546db864f9bb95bae22845079577b771f7bae4ea6df336ae203185f9b08803f2fd4c2f0c56b3924b9f3328ce242ecfa31c5841125d5c16f975087d98dbc3f8141b1e4be6c9ab3f3cdff90a6104d2ccb6bb6e4ae7db2519432b728ad46308ac1f81e96568f60dbf4d36e45c663a29c4963a0c51350cddb77d8112ccafd4ce2ba45eef4cdabe7a83c53d5d4c98ed9999666e71d2cff7b07a9a65e35670f23e7eceaa04eec4ad1db0998ee5cd9e03496af5c174810266f7fbb2abeaf568944c7dc3f801941304d72f3644dcd8e2bbc034374750d328ef5e8a52d13936d7147af311cbf9b43c36e32df55be0f19cca9356ff9217bbe7ba2ac63af7d33c43702edd8aab86cb24fd6debe0678dd230dbde3fdbdc2d0d8ad74229c377201b794cfe1fd38bf0ac11f59c765aa3ba2eec27f3bdd2f6440b3a93392030e7338ac012622e4cbcc854d52fa39314ab36269d0848b8cb7b84e491de5bc55f42f147588847b48d62d72b448d112d4f7efa2279bd970bbf428a1ab9b21558e1234638237607adb6c74a01c4337cacf5ce2148c8b8fa9406c57e2c817cd810e552ce2f22d7833d1baa56c791f20421ab96f4b1786edd225b1d1b86a1c71d069c56d67da303aeb30aa7ed170370b04da8a325860eba8d88636861afe173b48deba835f04bce8c723da490d5c01ce033d6f360c3f13c07f77b8841362a69ac1884cad08871cb6b5b6d44b3aa8a6379d52c3d313a38f55408e6373d67d90ce7aee2da39a5f4baef11cb029f6185c4095b9ebfa0c21e3868b048a09cef166ea4998baa869e7bfcb38c4f21a355f268ed4ac94622654992d81f067556f20062186b7371aee40c2e2039d328f4055fcb89ff3ca2a386854c33187d924b5b2759c115c5c2db629ce439b336d84d24e3757c29c2cd942443b2d25d82ac88593da79a9e94b8f2cd730a9b11b3a3b4c95ee312ecd6252f3cb75642e74047f0b9091704d62d79478b199346dd49f3ede0264942d9c407b0e1d7f6351ef62ee2c4a88e0a33ee3292667711cff0f8fdfe8ebb97e06d2cca8a2b1539922f076e21656be5313c37da55a032b9c63b39076b365369a6774e2c3912573f6074a9d53202540465622f98efb447c57dee9d3d9be834824f9a01272293b5623bf062eac9be3a36e94a30df6631e5192194cfa4598699be808ab90935625dbb76e49e868328c19aaf6f6e0627e52b2ce30dde55da986579772370d3a17d2fb7e996595d8c2f8c8c66e97a51dba18174f4bc91ba39de6027318dfec5b083e2e931c420fe04b33e590c2010751013aadd0088fbd832f4318026362963e9e74e1eab1b7634f427040ffbeb2be690f0f36b55ce72be3465f7bab45f0b0861871430f0f063e7b3c3ed1fdf5f2eb2ebaea3763d60cbf578899a76dec331bddb4bb8730597c2fd13c97192b03d2d9199e3589c90e48042481f5169129c52f12469d8d20cecb8cebd5539dcfbba31bf02af7aa6656335530c51c2f9685aa9a658da2cdf3db47d841dc3eacf9ed9374cf07a02adf76cba9ad3102116cba090969a4cb3e2fe0ecbf73c7742645e718dc141d613947744970fdfcc3104c99e742e1a2e54c7bcc5e4530eaf55bf64c4b8d5639026dcc181f68ea40c5ceb84af301e9552474fea73695376d6c2e48104e61f8a9e0c5dce582c50433c583cddfe4ca40fa5b3de2a49b18680f0b07d1f1b563517af97ddacb984ab391a1d1c6848594b68d13389fc110a04551bfbb6d937e300d4b2d73013e052b215189ba0c11523f9c1f80482fccbcf438dba0a68e9fa6ff9b08b966ce916bf46951dd2e03e9eebb47adf1db15abdef480ac1b5d4adacf0142d3d8c33c0c959157bbed6c7240b48cef19112f2bb1cd98e84a23ba46c494a802b194da40aa5df2401c1423ec0a14cfab7728805c407413031a6d6b1998e7c6624343acdd90ac56a3f158883babade104802037b531d8b763050816caea682b0484ff0ab5be3692b1b59e78648087abefccd2314ead501a9f5928d42b64ef5fce259c69d2208143384b7740ee96a4aa1407cbbc4a6f191637168f0ccd8e7e2c21ce2aae1b363d7ee66e44cb53ffd1ec9093650b1f436e311eb16605b22fb1b3bf2e44e165f1b16c526ff0121af634d36a3fb594046f4ce5c9e4f3282a3cba9dd859fb957f20195d591996db6c55308978c03b7e241f7f0ea8026f5d324b859e5a4f0312c7d15c694be788b89d1bb2bda8dc12cc8591a1f32ed662fd3abf7c46be3ba804df0d3e17693fe1702ed8f360f1f92294e73d4ab2e4fa003a8104db60fc88252165272a1e9d1fed431727b06907605e3cf92bb60631ff5b94675883e37951323623b49b77ba5d477908d943f3cfb6c82c1e32a17b0dbdd3ce0647cb47a483e2f036ddef6c8361f15acf6fed93b751e6bfaa7b7a06493aeded3d1659945fea951918c0f2162a0f56934dda177f745d5734b4ba3503914ed460e56cf844bc82abb4be5ad413c0b4891ea5eb16e4bb8ea9984b20721231a7d2d3242b9941bda7df08bfff643bf9683f50b130a194d53808cbbaebd350532e07f2ac5857464240b066655717af04e3e9e5ec9d39351c8a5164055b28b411f4baa88540f8fbb0184eb8994181691e20cb4c79ff2a470262da05269f08a8e6c48fb2071f8c38eae0debf788b6dcf2fc6ff15f6a6be15450652089486d9e4fd0742c83ad6f7898baaa5d7197268c1498e0a426dbd32d2afc73cb44f7917391cb5ef2888cb46516d7269d098d5d63e3e59485337ed26fa18b9a54712e555af1bda8c1391c131f9d0113d058aed3c20cbf0348c65f110766b1a24bc9049ca9fc8b780b964b941065c66d4216d3c78462e6999c360f50709fe1de08ef86d42e1a9957990ed615d197fb77aa1f30b8ec6cfec3de1e3580acd7b57006140e680f3a3b9cc22db2d7d15e9f52db332df876e3d9f6b4340f6e1d84130db69e2a31cb8fb33"""), - TestUtils.hexDecode(""" -5870BB288AA6130708F7BBAD9FBDD6D41E249D620495ACFE90C61737B57DBA890213D4741718545CCD8B3FFFC2DB33C39AD631D5B5CC902DE4D340DF03E09248F67E89D28071AA50FA532E94C391D2D1A61B1847C6B1088BE555E5C2694EB0FC1F029095ACD9DEB21EF886BE577682CA96AA2EB3DCB24B871336AC5F23C8488011860B455B687BD4CEF5FA11381BC292B4098BB2CFC1822B48ECFD28AEADA71809BFDA190836D3215CFE755FDD9374115E5A0CCAE15240EBA0147C2F89D8D24454D7A5AC2D20ECC0D46C040FAD233FC51C870080F1FCEFAE6C073AF5F7A78D610E23831D5990985FDBFDC6D101ACF3DB0A74D71739E0"""), - TestUtils.hexDecode(""" -4211c0fbcd62764b125a8c5263404d7848a1812dad1056f3368817cab3cdc97f852487ff9d2bf404029ae58f9ddba2fcf1cf5006568c2f424aa647b4024ef30a1ac57d831cb0eeb85414d3b9069918d92e0fd933b640f0a6a777637245081aa0d27b2fbca9deb27ca1d1338189124269a14120101f0fc279ecedaab6b5006ca4c7c0baee72c5d44f4c330c56bb4a822ffd3e9c3f2602ada56da71ff40a712f115cbb4bcfc484b9e778bde49ed7df2d9f233ce065d1a9b3eca2c494fb8b7ff6b35d64ce62ca335c27a3c157c801ee1988dd9c7d0cb0b6d9c2295b17f88ca760496dbdc9f68910fa07e48986bab423f9059ed8d4ce90b8d1943d1231c8442dff36a63d28e667bfd075a66a7d729a2d852e89d8f580ae18d6652d8c06e02bcdd48970a658ff1293b6eef87108f9192e65001a21bb2e5dbe932a524cd0a44155e52ed18e1f09b9c5d46483774b49a6559fa78377442c9652b879597b0569cb791731007d556a6a26efcb57910692925f041d4d55a71c7a221f52cc578df50d0b5176a262250f55bfa3abefafef82d31d1af2facb5b6d46c554f67d27a143fe7ad83d4529183a02594b584baf860c1141d50ec50db36ab24adf208289635a7106c3b0bfcf48c6ab881b75f379779fed7f1dac26a4698d1ab9334f88ffcbf9a96eff8e85b34a6ae4d2228b7ba474bb2bf32706ae6d35409477269baf4a8effd70f98fe8aa791bc49b7fda540d80d31d699508d3f9a502f90ced18fd6512aa02a22d941acd43e3ff4fc802f05da84ce5c367f9497e165ed4c5de86fd284e0c181a2cbd1f16b66bd3221fd07e368b1e00193020162ab47e61d05f54be7354b497cf7b6e8d77b932eb0f8161cd015c089ae62d604b647193819b21171c1f493bf0fc7f67407045f56e022ed791c17606633967986c9d93219b7db49f3ba21ccfd1bedaf84315a770d978ab657ec5d4e3e39d8de6a163ed199b5d713d206c9eaaaca1ec4415b015aed58797e4e116b366081825dfa54c25759212f4485eec2cef8f455109e893b4732b437c301db78978831edc4154a1be9972d4facf9137e59e2b04b89fce1b6cecbbdba092518d1d78d7086e55125e22edbdf53dbc67f38eabbe9e76c69554fab97dbb290192f1a5c66384a062c974df996b618fa8478fbdd0e30f11549040643d583ad80480c1fd0106c1f2367cf2ab8eeb641917381815b064905ed6e900b7be712d3ccdb0b1004ad33bb6e8a34b94c228940afa09623c85e490c32023e157b451f02aa6017c1656ae1dbb4e795aba6198e6b6abf66874acd91ea4028e3a9e1b68321fb6e707a72443a0a4749ca460cfc0422c7c6b2d322ace8b51270514d0fbe36d6dee137a89d32e2d55610a60dec2266fd7218ca4d925f15a7c84edeaefe84cfe9a1d672b551f5f2e32308d0a456d59c26b7a1689ffb0a3e4817c5e385a0f4658868814272451015ace5bce4150306621cf53e232cedd3dae72eb1a240e625de8556f5cbee438cbd913b3cd744146228535ea23f310379ab18c24ceebb685d0f61e5c81a2c3c9b4f4a7a533a49c8ef32ad14f2e77e210eaf1eed44cd6c845aeb78c63d7c12c6e5f91b59489fdcf68c4c0948a858933604033209a9d5a2bfb68b101f604f6f10bd9703fb9768c2aebca6ed5b00e4974bb348da101f7f2653d55decfd624a7d79c13c05a7da0ea3211f7bdcf7bf1df8d21ab5f4130f67d5576a4c8a927b7c7890fcf42e1a431c0befa7b86a5c56b283ec96a2f27309ed629b8bbacd4eeef278d7775d1c5ec5bd331cf622298a343cd473b905abd0904803d72bd2463d9a88cc11d62068f0d7fba61781fbbdea6842bcc58385c4f3493ceaf5d105a2ec7764030961546d89a8aa5252c117611c8313ee2d7c96cfa76b1f3daa4e9c885b2d271781c654b52ae904f5ddb3d58335dd81e2e6202925268eff4a6676b80f9042c1e1971fe8a9d6b7c8d88ea282e1696c70619a1baa29584c0acd26967b4dd0252fdc8dfb645a255d32b6065951e7c3da633b92017bf381f1788cdc24b205dd6a7db1335440d62d81ae8afbf2640162cb92095270a8ccd65ddf5fb667fe2b5d33fb1bc5014a6af35cc4e4232fe052014cf4bf2ad9b46684704532f33a0f165473ed2850293f6bad8fa8cac3d74a995b02980fe5275aefa92374719e218185a5d62a6347f64f9e64ee8d06cd9d509294f18542d432ee24177a0af0d2374b5e29735abec655bc4aa1eccb6b8c6cd5d0602b8de15ecf20dfb64f5b0b57cd4bf2e88495da925e98f46799d344c070d95e7527ee7d2bc1e5da7e7e857b2c3c91489d188b4b43477082773c95479290b13779c25682dea8fbe6c8d7cab9b07342894eea86e708d1e1e7f3ed998df17cd752e947e5d2cf4b4c3fb9adc9049bdbed6badc20124a694dcff1deab7a33fc3f7c8a9c7fda5ef59ba4ed3f3ee925aab58cc74b789103500aface7eb0311a90c13b1740a54541e95ed0982c9409800f89c9519ebe0f1f8017d639ea1f9cf33a70633ebe2abcaad745ef5edbbd50442265b477a2eb61e89054d50c8956e6e2743c23a387d316cc5d0b02182989c1f01580b597e0a9f578d3a3aa6d5f0ac1534497c5e8312055e434c7719567be933cf6d213be58ac37527999a9260e7a0850cab48097fd68175d24c6f1b1ad8e104b3578e4fe746621a50bbac09fcc3a0951cc968d708bbeea3e7437bc269416d826e8ffa279b755abff5bfca14e90d791ae0357d45a301d166c19dee82f2c2e6035895b294f0ef30d003c60422f78178c5305996363dc281f8627ac75bcbd28c2a7e1ca918d438c88cfaa57766a372513615592861b9872ad6fc4639e885bf03e32820a49687e0df3598b45a2f81e33fed4e91b9bb458fb55ca35d99351b20dbde76038188f01935c261f07b4287aef1158a5e2db5fb136446cf1ac6bc8265f84a1314f41cf40e283ec5da03269307a31cbc5a3a80b723b63c0366febd211a0a448604bd7e56d4d5d9a7e6d8a1247f098f01bab54f27e598fbe6483744e3bee936adbe1fa4869ed81931cd1d7b4f9ee02ede169104f910cb6dc75e10358e1ddb3f2a661595eb44cb851c53c3f2835f5434ed0945a354483203564d3377e78e3959b93244e836ed4475f82fc829946037bfe7300742203d35d55cbb5c18eff04f30bb9ff99ff1b45858d5a46774088bf295ccb5e03792779dea64d4318f800e10029995e3bd7cae442a8d9ab8cde1a26c1de7aea6a9a70bc16597e54e93729fe27d938b205a0edae98eb80c95e6ac8770f5a2db81bf1fef6fe3063e4681751e9003db29209d1f84851a0afcf62eb0e6605fa69da74650cbc4fd7347743075d9cca143a8084c15d4372a1d325adff6f2b945ac8f7e9bba76b6869abbf9704ccfa718d6926562dfc899c2498b073184ea1c6824a245be772b9276f279e2dbdf62fb28d3295f364f18032361a5db82d16cfa57b21b4270af55130c029b573ccceaeb81293f29c1ba5c0cd6292307c9f0c88100ae57ac1892e422891039541287499d3afbc1d3c68e93a14d5a3b0efb6ff267039fa3aef140953b23cc1d7882023407e7c77dc0924f58529e18b41b2f89747d8f1fb6c166807193100ee0a26b57beb8da3c34fd134a28d5df3cda61683e0ca0f9d92266cf0675081dc18946586e5b9e070504d6125fd485094f3df2eff6d9197b3c7953303f62e276df391c8abf86aef1931d60488556e412ae00f7c201e8d64070aa72e291e804c209c8dc3fe968d06311d569d726fca4a094c7d4dd4b16014d4a1cebaa97131ef1ee66d734b9f85c9a6e70afedb26e7ee8d150d611b852b0bdb34513ee3db302395492b845affb16680f5bea4896b866fc13081eb86f509970b69df9d7c023c160456eb94d7eba2e9e2e076c10ad52b9c966ac387f808811138b9f7416bd0a9d21dfe8b706ce321f284342aa301f4d8361bf20bccd478386673d2afbab6288b8aff15eebfcab25406864842b7fd6bcf6c42fbd8b2cd526c5dca80e46a04be95cd7d63d936eb8f5430415b9b1232e4ad3dda1abb1b1c0286e4d89b9750fc67eeb22342a2aaaf83766ffd72efd993dec4a06dcfbe5dc3c067dca721d41b14f8a3536e69923d34bab47021bd1a16640da14fee5e587a833f2b415f4c454b80c700a4d9bcad4c94b6db9cd969d199f0a3f4fdb7225d445cefee5c67b1d6ac63e8e51d80cf32ae75247436bef80affa4b36096b19b1dff52a88f7a3f2e29dfdb9c5dd994f3bcbafd976f318fc59e3d1ab60e92a2c0ca7eebf68da24253b4bf1bc99c98ac429becba641fc2642074a07a9249ebe6508dc5d0d460f6c7bb873cc6a2ad7b91f03edcdc731507ad451ee3d9a4527721a5e76a55dc008f438014fd0797066a51910e958d5a0d92ee2245c853b4c9a7b2e7efb1e9e749b420b126f0a0240c516882686660b38c60007f45d7648eaa2d7b1c6b1bdba8aa5ca140e8c38b0cb6d54e3083e903f7c3f6ac97d95293506613b3a35f1c2a8d401f66d917906210c758563e4722d30b05d375c8ecc41d898574c3a20d218b581db4c85ddb2125e56c4918d021f96bac324ff9e9789c921cc5281c0f0c98a98fcf218232a8b99a2bc34a4b7c9d9031b1d408bbec6e3e633555e8fabcb0115324e000000000000000000000000000000000000000000000001080d161c20""") - ) - }; - - static SigVerTestCase[] SigVerTestCases65 = new SigVerTestCase[] { - new SigVerTestCase( - TestUtils.hexDecode(""" -36fa0dd4a24ec6fcb09f2302dadf25bb8118be5ada70e1eb7f57b93fa96b1b842b748c1f9ccc78cef5d647c28fe8a346ec60afd8a79dcf46d5a9666b0e50816972701861835ba933a4ed0df8b13eb32f07761ab2f9fb622346059777c7c75b2f370fa623cf1d71595827294cf14bfc36f0ccaeb3b9162825737481012d4547d1843873aae1a2ac6f262ec5d4b2403ff7cbb3e6758920a6dfc12f48396f8f96e144c1afa6f0a150c1a05047e35e95a3530748c121f953682cea77ac0e4dc7cf205cd63e8aa64e278cd6ea2726519fef2d0180931cb2e06739ccf01e2bc1ef7cbfdd6bab7b9bf82092e18440945bccd91ec8a703765615cbc42492925b3515a20c8e676593d0a4492011a3cfaaa78a21ee10bd266e27faf13ea69691bf5bdb89bf7bd13642fc757af3e5217696b6d0f25386a8e2e2476742b5b050813afda57377141f0fbea06f83544f14b1f027a05d9fe5d431ab6adc86623824c466f3d37b9f70a9318b52688d209a869c78a1f063742380c18961fd3cb19b3e0d90898025fc8d7785791d6ee155899e1c0c082657dbe848c1c03ef6ae62ac00e1ee2a71527338776085554a3929db26d61d842c15e24a917fff823ac1bd9deb37af188a6584bda29bced6401230efeabdc5e96bc2c77c23347e5f60ba29c581877edb9eec6831a9db4f93c383a5f2f770055a50c9d4579e69a22899901d1c9f2c5b892976d980ba4ad0864c0a046837791ef23540b603a5f7cb074d94620661e924d017d29d6fe6b4b9168cab2325a6f35e7d1dab818d4fca14f6af4b0eef66f869a0e1d7a8ed15ebb9b1d3cada4fcf106ce5d0c740c9d8eb5771933226ad5af16f8364d506cd700fb5270cb26dd0b17e04d7db7e5f503c9ce3c44d0b8297e619dbdb382c29d7801a9cde6cd5e6f8e4ecd6cb9e8e89ce2782812496a0948788fefd3fa8172df501475cb6d68cde63edce6b7b989281b2b95d60a301f10f60fb23d8dbaf6e4b4b345b0249434623580936e9ddb6440d7ef60fd96e1115585d16725e224a4c86356bf5275ac911864cf1631c6fa8e6ca3f093914638f40517a2102f23505a571e8578d4b5a7b97af3a0df8ba735d6e53bd6e0563dbb21c37ce4ce99f45752d69322675bd522046a89dd447a34fe781095126c774bba2b26c9d7cfe4df858e7a5304c5183d24bd59f41d7f22414dd6ad5865dcf10bb42857b738d11b2d6712d76bd252615e68c91aab09c8de5cc36cd9ea66a8ef4b65a91e86cc39bd107ba15b1e5be3f7e856070026827a16dfccb6943877ad4d3dafdf5afccb3ead3bbe493fe4d2928c335a9ec128f11dbcfffb8d439a7807cf035c01ad29d90f767d7f8456b4511321919e0a27220c411d94639de6ee232da1544671981c200642de22f01a8b14e8ea8ae91cc05f2a41acd085239ee00dd3e31bd21673fd2ed5a5692b3d163d99b1c19539445a3aaee990daba896e67ac125007115f126bfb6902fc8f53501656ba204677dd4b6132813d9064000d024cf0b2ad70168c8bfd6f78ffe6d1e6ad8731e880bdd52056f2bd42c825ff5dcad7b4b42275adc52b8eea33e23178ca2361d55d829de69edb56bb2a9ec300a4691cbc1fbe0b8f8f999eb6259fe49d6fa63d665722e542fac9a2ab5f203d1403ef328ed290fc2bfa1da1240076123d425e485589eb6c7ba701658fa6ceebe2fc2d211d0c14160ca5518aaac2c7763c4393e41c31a8b62b3af2ab12bce0f2324ffc1bf4d1cacb245da239406fbe105310f494502d6aed8fabd2042c7b1e4bbcc8b44d22f34850db34f8d8134ca2d7a7e7c57e447d66660c83001a54aadbf616517867f1a9a127a7073ab120ef4f6ebed8b66640dbab85f7e4f6c379d6962ea30b849b1919442aa6cd3defcddf35cfe6e4e9443b5c130503fb37dfbbaec995cae8b2bee478b99cea9a030368aa1070b17909d27024bff039dc4e1916d8006480d83858c04f22e0876e9eafdb67688d62c94252a74c1275c135631e162e4588b3f6d9f8140f28e8ab98e11cd96c7d5a528dc8af32ac90831bd74f2481983c62ef4111057b02621f89c85731edbd1b17f525f0a7c732fe8738df6f20912159a3a44b9b1518017e59e02b418dd08d066642c120af3ce2d22e7925fa7d811aad41328c66ec31ab05e1185351ef5cd3f88d931e70e4d60175634a8df275a96b669024f2a5d7dd9e8fb09ed16d5a754a25bfc0148b6b690ac7bb9e44062baab6f2c7e2dbda94a641a07fbfce7856bdd329ffda4a6ea637caaf36d1776ffbbb17241c7a69533adad3c242dd98168f0dddd11df24c0e2ad33db04cce7d8422d7211b6b04a93314655b7999093954674341f25989b19c2cc7851f8d3632543e5f706c1a4a71cd37f9d9aa06bc81220e8792baf65e69a75b9f1f9d709cf73f4819300efab7505f3f2a3ccf913cdea82c65a446817b316fe1048db8e7158a80ec221497a243a16b6292131573a6374c68deab40bcfbd4bc955778345eaa8fd9c8e405a9cb2ef79842bab9f48bbec5764dc6159cf34f4d6729e1451dff16a92b9920301522650ec397c4839857a03e991185fad483898e37485b7329a74929e7b865d1805ed02158b209fbc0661d4f9324f3be701928d65a04784b8fdae59666d70b1ed2d5310a2a66a3d7b948b160e16dee03a694403b7e10f4c9d860ab54c34b49dfc4789118f0bd4141158be72d710d9812f66f2070f5542064cd9fb7030e9b8a82e2ea74c2cfffaa3ba0046a59f4cd06ce680f5a9f2"""), - TestUtils.hexDecode(""" -E3D54DBA675DE7530D3854C8CDBD581C6E392F69CF9793D8C0BBAFEE7334C5878BF13B3BDCF1D993A47A7E8EDD4B6C3EC915A5E8FBF2071F112AAC41F08CCD8CC731143AFC223213212A5BD6B6A4026CFC9F7A41C08CB99F2B375D0E04FBBE00503533DFB869DE43566574B49232566E38B13CAF8C1EC1FA11CCA3DB66887996DFEE090D133B1D394F075F8286CA6CCE13C3977D929DEF5943461BD5A22D4BB5E8FB7EFE016932D02ECF4D7B7705412CA14508B13E61925EEC0B77460C4C089C83D687C8F70D141C75D6DF24FCDB64BB8C2721AAC9CE8C6FC4750C1686A7A70DF34957DCC0CE53C3F0D280CBD056D4F921FDEDB35AFCE5DBB348964AD105EEF5A1B07BD0D586B87ADA7CA7AFA93FB75AC0DE1C749C48BD6F192D6279482D3F9781290B88B095D73E728AFC186BFF0816C1DE78119D701FAD382C65ACC42B04D69412AEB255793839EFB9E5BBF6F69B7FDA27A44C04D3AA2FDC6101E9CEC6F75745F20E077EE23D652B7DE547A0FB0E3A153473BC824AC8A31A2C9493DE64B6D40185B60431B1B34EE32797CC77C45C71F4E04E849BF8DDFCF640B83130208DC2495C0CFC6C031B63B80FB45F47BFE3D25EC5B36C2700300D8223074C156C5D9887DE8C5A97BA36A84D7585CC065F20FE8DCE9E8EB814A1D5B7A3B7A3AB68D93EDBBBBF67BD70A0FC536C81C8D6E8B139C6B3B5EEAA3953464549CB38B78A15CE3D5BB4B798E6B142BC48C70C5BE61F82DB6E2EC03616999073574E6FB35D441B78DCAFF56B8CA8F473EC0543C9C69E93B97F95FCA58DAAED511F4440DB252EC18C90D2F97AD901716AD34EE103EAB0B7982994E21ED1AC4BD62ACE6DFE12C8C2CD092E7A7E37BD4E61B4CD51D980171F8D4253A4E7FCCABA0A513038276325372527621B0A3DFAECCD7CDFE98CB79C0662F5D0234AEEE9302438B778238BCA409D5908768779155D659E92D12CEEF3C2C954C3F1A4C2912E9EE994209B608A604D0CD87F79665A25E774E6DC1D8819B85852D9ADEB174C75D982DCE29FFDD24B7AAF5946A74C14A301AE09F1386AB17ACC341D6DAC040FA6527FCB8E095CD4F1651E47CE02E6ED76C085B2FABE9FF5A510E63E73EE386AC17D5C2C94C2D528B3A9C8902D10C1610BA70BA616C58D037F148E6332107DB9F64C579064F19481669C7888C21F0A3374194FF1A72FB6180DC01D29443BC52C318AB03843357A5A98B3D5CDDE9BC49D3ED29EF73CAF44A7849AC6DF4B2D353B6A562386BD480512108CA0ECD63BB3D3A0695679762F8254116D8049488BE6389FAC08916E6407944B1526BF03551504E40E6A3266D4E773E892EAC4DD5128374BA341EB4097E20A9BBD4E5EA26BE6FC325D9B71C232DCE1974928516EA2519974C82AEA5247627F802C6442B67FBC10E359672EEB9DFF768E9333A2166336FF0004DE5E7BCA55998C860FC1A86B75CBEB3FB5A5A2519D5227A6B5A7E0EE058FEE0CAE2B4AA75099FF098089F0261C443B13911CF3250CAE2F2906CB6454A20D0FFFE8C5AFB1DE7C5BA8CAAE00CD7C2D7219FC83FB158FD6D15EDC2924AB41C9B881566C538F5E38978C3182FBDD0C0C532A77A61E5B8E666B3C540DE976098D2BC68C0CDACF57E9BF1BDE8A7BFB13256BC69F2E386D8F458D303BAB781E537517AD7D0F0378D2F258B013AEA01C97A7E8CD2C3DEB203AA8D59084ACC2B09AD3C97EA613A2FBF297038B4E721665D512DDFE5C13F11DF4BDC0200BF610D57EA7232914752F75A544E01D5AE0DEFBC9E18695824058BDFCDDF4D5884840D2B55D6C2D6EDF475CA75F3EB4D0EDFAE99349684BC9C533EAD591085BD1D6D4E4F9B00A54C97244322D505AB52B2D4E0438C6AC5D2C3983BFB2359FB21174AC02156AE11EF233AF40A695854C84E620754419CF7ED9EA4FDACEFC8879B2EBC7B29CDF9C4CA2921E084486477C1452BC3BAF529DD92748E2B1B684B1103CF4C6EE11999E4121CFC7E2F3F6C7BB9C055F800DC46D78D9D94C3B20BD1B697411FF0B41E38173D2C9FF1CCA77B27384026ED2EE25223B0007D2930D700A20EC9159A66A4BBE0BD84DA52F006D7FAC6D59AB2BDE08FBCEB76A57FFEF59C077F9008A4A231FCC302E4DDAE9F3DAA55707C1EDCDE8042176DC7DC6377BEC58B236990AA6C5876D5A27942FFF7FD74B7DA1D2EC470CF71103A64FD2917AF4C45D4C59C13F58472AF408F9C5F907C7C6AE0F402B404AA40CF8D962EDEF7B7654EC8E36C645855BBECC1337EC18F0EA65933F4D07CEE15294139F479A16133D2BF412B5E46D5B06FB170F0C93DFB8AC3F7478002CA76B67A272A3224C8172CDD8A616A4C52F5FDE946CF5733583C53835EBC90DE3ECE34299D7E5434BF072F08A44905818EE9708815CED10E9043E88B6EF12BE72FC1169FF2F925C38E03B827CDE77740C7C2848AA3B09F555E2712B341E248772EFCF01B99CD5403642448B5243F35A3073A6DA7685AD42FECB05D46FC99F7D6B8EC56F39A7E7B3579FCD587E07C05BB7E1F5D49B9015375E09A9A14F2CDF049AC392139EAA3C2547426B8CBC0C4BA76C55014FCD3940FEA2631A75CD2FF5C22B8A65C9AF2DB1B831C30EDC8EB79B797E76D045EF0B8EFF8D41404F626DE8551FFA445885CA1E3C9BF05B5C39CD40E3B37CE3B58514BC70E2EA94CD694CA88C1F47AACF9B4FF6622C555AAB7C71EA210FAA9C0BF9089DC9C9DFA77C2C4A92F59BD7CD24EF4F8D5088DDBE22DE854F8966C017FB414464ED6B991E289F7E3FEA783831CCFB51E227A6DD4F5EF50963E80847FA6B350A2DCDA3C875D176342ED73BB42B416E58D1612C4D066F1207B6E16A955DCD557A9EA37A9F24CCB20E74AC4D6166ACEBCD7D651450E5D4AEA86DC89528DFEBE07B39A160160FEBBEE5B11122B4177FD04B0A49803E498F1BFFBA898BE3B26320966165E136F7F517FEA35EDF01D36831F9AB478CFF8241E01AD7570C26EA62439013F61D48797B92964903802AAAF356C6AF7645F5F4338C7EAD5AB2898C600123888AF42A2FE06FF03D81320FC08E7589E19887EC86CC1B08204C29E86CCF187B1240B81F7D375F3762CBC10F3BADCAD7431E59A4DC136440AA72628E17D2BCFF916DBC8A66B8A83A3C6400EA0CC57A82DB41BB28CEA9E9CECA1ED826719B9B62B6CED5B52FA518FE47274DC6E22E5F8398D42AB23572CD6623EC307FB7EF61892AE3196C48125605F4F09B9C0F0DBBFB9D9015D325C546CF3B1DC886AB0DEFE2C35CD39E2AFD13AEA74F787B410883EB72DB8CA7D225E6FE8143695BC0FE556C6CDDA493F92ED62A38E8F90CC4C713A4798984007A5CBF68F0CDCC01274C96A15C3C4355ADFC75F7DB0603918ED6CB4E4491A8569FB1A9AF32528F6E26B2303C7987E39015573521E024B2230BF1BB803BF2B358880F2840CC58ACE31E551C8E2A0F8349570741F8E93066C8F17608DE35AEC342415A4BFDD13A9757501F5246ECA49913D0F02EFF35F4B3D40DF97A64B0FD02709C0832C423543A850776ED9C0574C26CDAB8DB371F5F4B731E6F510BC09FCE3DBB58BBAE1074CCAC284D5F8068D2435E053A037E3ABDC957B74339EF0063D367F7556E49D2C7A7DE3616F5E8B703B7585F526E9306C59329A18E76B85303C31E3616831F2AA2B173CD0A43CDE76AE52EFB8CF3C381097D7A7598EC833A75E97AE4DD539C31B3E45216EF9C844008C28D12B12D3C7EA7FB89B3B5D20EF5C7636A8E83D6A9F8F7DF29C9716B7D92313048A7E14B9EDF77FEBA874B9410DCAEC4816D2FB57050696F5D4F0DB47C6183D447C5AFBCB948D09944F4271368542E377DEECD006779F6F7649B946E79BBF2E19AB4E93F142BB24E6D962F6648CD0BF1BE876F6F431E883105C3E86B973E30735A6FE17346ECBEED5D101EF0AAFBBB4C072BADAA2F4D517C272F2BD2190F5F8C87D961041A121D6B319EBC959AB0603096017BF7CBB74DBC74FB866358EF8C1AA5B9A10B2C524E822278627C0AC577AE9383C2A529054528E58D56699540E4931BC65A125EF4B459A7A5FC10E0324ACB641BA33C83A7E100CB00FFE0ABF6281F8942AE5490DCCA37BF464D0B061028E46E025FBD5F6DD6CA1BEBEE282B749FF5B002210916B9CDC4D903A95972FCECB9292A554AEBD821AB4CC50D5EA0A33A699FBF07F2CA520FC44D4A9581182290294A8FCC66DE3FB5B7F5EC5B267D1A0E6F84C27C02253649F5903389A0901797A7EC8B78AF12BF2B1CC22D291347A0F8D6EB2698AFCA7CB4C23EDF250A5B77E51EFFA3C675F1FA951D72467EDAF987D5B63DE4177535974BB2006AA9A8DD9E624108229B1C5735BB039CCE47162EB52DE88703A8BDB8ED409BC01DABADFD31EBB95CAD9026705DBAE5A2D06376320BCFAC17A7DAC957BFEE98480C7A111B5ED300447A21FE62448F62CCFF7DA68689A73A2EC70BD13130337EABF26A00BF86E52077EA00DA46FE7323780CF98B3E998BB30C3998017F4BEA455568FCD567086EC68ABC40113DB474C6C88B1C1C7588E7A8C8D2082D4C70DCB8FC3D8FBAC53CAE95286F13254253861567E4715B03E682E422C111169D96359EE18265C3CADBAB3AE61F03F86D096ADAE9A6C4820EBE3B61015995707695B42B67802FAC2D6FBB2B67801A3E48843EB83288AB52C29C1F112F9233860612BA015D4B7CABC19C6294F8871E2ECF6AF334DF9C8330971277E32CF1488F04B4B285AEEAA83BB81D54B6B8426439804B027822373AB99868EC068735C816521BD75DC19F79D2E2166B1A551C998318FE19F5079BAADB12732528BC8B522438AAD252C57D3899400913CD124D2DBE90A891D95900C0256D9DDBF939BADCF6E37E6783DA2A2BAAD872F6C8C11878ED6D5EE2988135A39F2DAC7CF127100C36D2D4E58B3A9B1D7341120FFCA0EED2E98E020A46F1AECBC809A21EF79E6DBCE76F96B6930107F078A5D4464CFEAC414CA41A5EE4F87CCD8868E7922A14C247885F0DA9E23A7604EDE703C2BE3633AF9CCC32B9E5F51CF51978F10A06F5D77C67927D80AE480E7E5E005401ED95467972ED87029029DA05DFBCF2F0B9D50441E8F15804B0A59D23CFC2E3C0FBFCB10B69AADF0B37C06DBF972E264C6CDE4142C04FFD9FA0AF2451F8BEC3FDE9723306085ECEFB17C591E691F9B4D4F796E293C0CD322F02B96938A5F7D1C8A7FEB94C031DE24E71020FF37E00590AE7CA48CA876AFCA2BE3723EAAD40FD27B90FE6EA039C9F3F6069FDBC70F16626A41678A31E8AD88DE9BCE8A25D43B86EBF80E5E426FE21606E67545FF8E55FA7D9802D65AFBDA79EF40DE924FD0DA7B5C8F6A2CF993FA6D27B2861C629CC9BD2E1E6AF04F88065614F7E24CDD19C88CF2D7D2B93B7408D898525E5141FF71D18DABAC186DCD432F3895A1027C92CF8613C80BD46E4758CA26C8CD92B74EEBC5FA5EDF9C9FEC54FEAC40F0944E3FA165E515A03DB57C205D383C04B2CBFF703939EF321DF8A49BC3F5B1409EA491062B7B9982277825B52C6CC8313BA05ABFFCDFA525445B1CFF773D28536A989D257967B50D7BEC4FDE5F338D2AE81BC8EC592BE93BDA0A7DD089057E675674E8B997B05D049CA3DBD60B7F3FB23BA5F4E5A48ED8535234E5C66C41B157C25B5D9EF5C8C0ED016D6B217F4B60BFD0DA223A5D40C2A403DE8268AD5E6207C54B217C2F009C5DD052266722DC21D4AD8314DE498692E3C77C9F8226A14F27D49E0DA1101E32E5B86BC0F0348A20A360A919EC863695D2EC318A61F654C9A1526AF1538F928DB76F9B14EF598F2551EE85D6E0429192C5F18D339DD5A280DD5B1A8F59EC1F2947996C7E190C87502FDF5004772224BBD1C4DD62A8DA1723EDB41176A9AF04B1F30D09050E73579364360DB4F98034FEC1B43E6E9E0226409E6AF1609FEB862D845994BC20E67010237B74DF1AB59EDF14B1623FDC990B87B929FB7E837B1ED905286A886F59B023F40B07A989EF7A99E974EBAEC49B45FEE1F405D11A641B2B150EBE854F7853F06026CB1287FD8BCEFB15D2AEA623D7C3ADAA00B35A105ABF2D8F9715BE65AFCC1381D29C5EF398F2B76FE1651348BAAC147CFAFF34778242B32A1620E0332EEC7AF5E750DFEC30A899452ADC530DD933A07748DD522AC20AE2B2889FAC3237D23C4472FC8C6B236D4A4D19F67264F54BB9B25318156B30EDF273BBF3598AF5B34BAD41585982F6039F6E488308B47EAEA5D21A91E5838F7D9CCC8F726EB2DB82D022BAF103AB2DD444489B94E8DDBA71E62AB6251DD5D5F69E44F377674A5C2B032150C32664C96C072867BB7A2DC29033E6BCCAEDDEA430E5E155DD0724FCBC0415B2AB6DFE68A2E59403B206BBE7F421FAAC53F66040C5CCCEB19F17BF000AEA7E775211E48AE04AB32B2EA470FF97707D9C073FE72A7B77D49FF8DEA36610C2A83306435861BE01DC4B20DBB8AA6CB780328DCFC2A32D74CABA83929CBC85E406E74EEDB727A2FB5BD9D304AF46225832858B295A17B9E710BD7B0B5D19DBBF4FD021EAF29F4D1B6BD7E78C8A3E3235B5D0BC687BD5B428D2318CF4330EC343566D42D17BE838EEEDF70F1E409C189DB1AE0A205D222C92A1ADD33B8E3B126AF62818A2DBE3E3C001098A986865C6B57D0B2F5579B97B6F101EB56FA839F8789F6774074185A8E0F383E9D8813CA1670D8B7586A3A1C27A3F5A3874C4E743EAE21BC519DCC430E281D2F73C23BAB948938A46FC24DA94647150DB72783AB3FAC01D834A8544F144779A51480643CB1ACCA0BF88D203F865664A5ECE18A88CE31B0D8FEEC585F9531329002D4FFABED01EF42AF52DDF08400C58D07E98046D77C7A142B513DA0EE795DD57EA43F4CE36C8F6D2862044945DC293C8D47D9F207B0344220E3177D6E17A4B39B22CCAE3C53D4E0DC87F70CBE9BF743CEACB8932DF8F84A527C9FB84C6CF5206EC2E43D1FF8E846DA06EBFFFB87BEC09C63E9633713768060ECA6259AAFE7C787F3947D5B94A6B80FF0A7A4785836F9A1396833347C13034040D1C6B1F83782AA6458328160FA04971DE04A16B6C031B2571DD131912CDF2515DD56983ED6EF3BBE5B3989E951BF0B99C5605C38181E96690487E87240059DE21BD220059E5D7E3C832FD4569BB7DF06437197CAC141E8FE5B369B542CBEED2F9025A030C54F0B5D2B1E79011CF2A0A0DB14312E352D07BC03E654AABAA95AFD30F1483B57BB1A74A0CDF8C9FDEBE4B0E156FE86BB1E21D861F8EBE0C4AB2B23E776EC01A281F6DA9BEC4C560668B4EEC71856E6CC41741DF2EBBD4E95B661EC24FE31B1DAABC9373CCBC82F3C13C31E478097259850221928C7AC6BB933A5631C896ACA87FB6F5E3EEF36EF5B9CE59F5676813A1A7E768FC9B8AD4A0A072672BA23CC21B21A95C9BBB1A40FDFEBD2D611B773DFA55F87E9AB1CE51CC42B0FE2FE15DA2D73F656CA56279AA16722ABAED5727519EA258794503F1808E4EBF056530B318B99A74886D05D042DF4D829C425C908B58162EE30A073D4BB7D27275B548E7A90E6D178DD27F67CD955270825FB96300C4645E4CD9C175C1185707D4D365955FCFD245A55D64EFB66308A47FC85592BFB755EB4AA8B78B541274E2C225DAD649C248E7F2792A56BFBEF704551588460B192DAFB9BF6798B7D4CECFA424AEAD675DCA081E60BBED670F9AB2316F5012E2290770D3323403DA5748BE6681565A713873A5386A6F1299F0E1EDB341FFF08325510A7F2FE5EB0302727D7355EE48ED5DF4316FD34833238690B91D47165CD4CC0454DA33B87569D38880AD92A92ABA0F24D99ED4CC977A2B4E37954FBE9B9320101C80A858122793062C7AC26E71BE2608DBD2A97CF4E884FD3255D008700FF3531C045750B2EAF7730BC9A51C675D94179DCFCE9EE63C1473D15B4319AA9EDFD19739CC05C5C3C8AA618FA9096C6648756F8AA74FD18A8CD81A2D248B856902B4D30182BFC2F392450F902973043EA0F5E6C872AD43A2D319F99F095808D83A8B02BD380D6C3F3DD227EAE2B4A4867713853D63CFF405621B1EEEEF00D5BA2FF254CDF97B4226334A9866A2B5BDF1F8E8AFDF1238DA9F48FC388A339F79D648CAA0A0A69D6F16E297663E5F4CF1AA95427E68D71E74C0A2FB6B689224BD9978F7A3A4505334774176FD87097D8AB454CABEE138F2CDFC6EF0F3DB14B09DD02E7FABE9F156654433B75B951AE3C196D670192004DC1924D1950AC597682EAD1C087ACB1461247DFAB3CD42279F9169B69B33435DB9D8994AC04B15D45007F0F98334AC5D783219B376D9ED7553F52CBADF159F69282050A4C843467AE7E4C4A142A61CCC4C48DC3AAC6B8E0A8D618E06C60DC924A943AF9000F896446CB62EF4E47AD6D1FBE2B8984A48ACD7C0519D6E87A33106E9A91C298808BF04E1267349334E6C2AC015A9F704B2DDB56D27A8B00D876AD00F62434095A6F7A5E9CD4B27FE09FF69019AE5F27330792CF9A1C07FBE98D23C4E615332A77DB5B6182D277DDFD7572DA75748DFB3B9315294EABE4B6D0FC3114B2AFF5537A6B05A7AA9ABB4930E17B7FD3D8F81AA2D674DB69AD967C8306FC3E1CA8BF78F446B26D8F2FD1AF6F7FD7E52867BCCC3B4DBD7227EA992DD995D77C4A2BC808C7A3E68FA433675F489BC503DB70115A824669E4B1861CDBD557A1F78F1A4B3582B2553AC23F12A4326EF943C56F847B8C679695614BBB1DDEA9CFB7D799CE42DF8B735FEB9DC119DBCA306DA4FA84A50F79905E5C2AC1F61241D88359EE6F62DC9D3E4A1593F41CC5F3C02241CE5EB62C28A547FCAADF1DD688F3DFBA870D9BED723B02B0B1CDB4C08D093C48977E0621930A668A5CD517A0EFFBE248B4AACF3009BAC0D47F49378F30A3D2C2800CD16B3C9464563DA4A7321082FAE95DE5645FCCBC5569E942B5F860A32F04082723E9E53F2D18099BEC5E23A916354198325FA8DAEAA3F6B7AB6AAD6EF12A03CBDC27B83C818F44"""), - TestUtils.hexDecode(""" -7dfa6f43cf7e66cb9e8830871ea48edb07de9845daf9433d74ba10cded10ae8fb4955732aa5f11581322d945bd5b0c05ca195e5373453435602784c9e386ad0766d81c9c954614533a0ab7407d4eead99582655ed634e9a7db1458e3f91bf0c4ff63adb0b62c4e813c396d8a640d0464aff2abc80dac7a5d0329e31eb34d00c2d90142f47e1dcaa203f730de8723ff5f6e9db3dc53923c1dc413ce54f5049496cb69e1280ba7ecc7cb540a62e441c97743e196a0144db65e3c0022c9a6ec621eb1ef79c93b4b224c4a1df88afe1c4513988a9aa4d6aa2a440a9d2b3946dceb5954b0f5634af19cb9de528dfd8bfe857375a8c903b124fe6b9584fa68f56dde10114aa62aafde3159db334294c06b2774fd660a13e997403f04f5027bda9745e16684edbbdcde4155adfe34e0febff14bb05057ee9188c2f7ec829389e7fb24c24d3ceec6f37e53b592b40fbfde40cec330639e585017f79fc86c68de2d24e49b33b5368fd1c7d027503f12b339aac9a4dfbe711918e9eda6bba049154d4f3aa0519078e9ae18f5a94f31adbcc199a72a7b09de94c7a9ca94a04d016fe4051e5b778d5de31f3fb76fa68a71574fdeafcea5e72b563e99982ffcef751e8422d2750809786b57850b832c34a1ea88176861a4176a6623159d63535b5897ef1621564c1882e2ab954455cfd5eb080f9e979a580fd8ed7b02bd504c6ce24c55c1e582e524b6aaa8ef66c666807aaa994d22df7bd5c1a01b128a408b9dc762f2a5fae6a61da1ff4a2feb7e4389bf3fa4357c61acefdbe386b6e55eb3220eecc005cc0047b45bff02e87f1f55177c78c16f142c27e6e9c3ef81a5c5cc77e70695a7ca57e93da2b5c0b32a8df6a77dccb47f3c9406ac58bcac1ba5aa511e417648c4160979d7cd710d35f4b405e7b3d09d229d011013e7c84ca8d0693696b4028eaec2993755bddee22be25b4ab0c5541d6379a067b9fe755955cf11f7f83399bcf28c331c69e2f9a80431da37b14c7e854232037284e91978ef928fe68021138649d3cbc669126910cd648e39cd91efae120eb275b114d33629bf451416ca9affe96d67ddbdfea590b7babfbb49a8e6fada738b0f2bb907e34a856a835e09a8c9076ee222bbffaa25a30aaa21309449c4cd0a7fcb6110a1c82fa8d4a737bab8d92e4bdde60827442e9f74d135f3834073da3867b5094f4653d88607e8551f0c2951595fde2880f0407b60146b5f83ce3e589ef16368b7e058db6b3e8b98d6d459428635f1fe23fbbae5e96d5afbbded8dc22010c58d11e84edaf7ffb8c6598d15e8d3800cdde92ba519f3773ae13219b7e2b967f360162431f50b0de5c634dce2a361760bf2c656e47f8d10336c0c8a0694c148d43dcadb3f84ba52a2f8a167732f106df835e50af089652c7c806b1f51ed4dcdec2cb5d97b5c06f6c64c2be83ec4c1b228fe5615b7531921a5ab4e2357deff9d75e04586f0d325e0bc6306cc22f59e26dec56a2b0ac627f95be580a8efc9d7c27104a852df113d443664a9fb27c0a7e9181372eab430394ef71bb5327e2ed828b60a7b93a42b054cace4b029a8f4fa8fdbabd0b728971ba99c641ce864b627f9fa17c33a6f50d3df9c97d066546a37ecc518b6eec761351240ed4ac606e498daffcc4cb2ccb061619377d33d791938a32cc3640f45549f625e8c2c284a7fea4fe1a864417183177f9c914348d7a693e2d53a95dff9fbe6b26604ae005bb1244176ddb2eefc07942edc0b0fd336f267006979bd82c4499460185d7ad41301fbf5b17e78491a02b8df328aa35eca2346c1f37ca775d11facf01e26d7473956f28551bae4afa6039faf145ade0da17470beb6857ff7435b7ecfcfe51417282095d7a83316d16bfd0a209bddb52461fbd14a74bfe06183c01c40cd6086c6594921073e6a49580aab6b28c71b960ad575471fc6276b4df624870ed01346e3a6252b8e9ad82b40cc88f5627ea5d8073efa300eec86ea921cde8cec9e172314081eee5f6cc665f2b0f6e5a0e56a9d55d8fd1079ce1b5ee10fd69b1a1e8fce047cf7264edb9c44e51443387f9d2fc54b3ef09055f819fbb065d6f0f09e53b3d5536f1c5a98c1778a5a45755894290e45d27f93fdd72e948fb5a1e4b2b97798eb030933180e8aa5bef5d89770c546320c9e2080eb7a1ee3c03a424891517c3281a0f2a7865a138e7cdb1b417809c3c3f62b12baf9b02f9156ab6c774c03d698a9b52380124d863008bf3875dcb7a8a80191c288fcd856e138783a0fb301e395ade94de2193b7f316c63fafeb388a52bb934409064aa9822f5582f632324e11b6e4bd668c0c3d57267d64311556bf855524191565c02da543f1cbacf62a1d5d9839990ce77590f138e7db0641e51ad911c3c116addea6fad97243e9ee4efa3619e8809d67e8907aa0d63f4d9ed863999212e5edfc8e7c761795792e7d9c1d05af67f10645f76ef119c6ce384e92f1f91003761c9203f2e2e6afb3ed4daa3c24d74b9cec3526159f7f88b6df5354db2e7eb0dc1240cddcdf076b8b8f4567eefb4b27e07aa3a6dd9e17695f58a647002283b2f853e9c5abf16b5c4c1f4cf6dc67e14e2ffac3ea0e98830d8613fa7a149109d054ad4858fca3ee6bcef6bed0ed48a877ee4d0c758cae7394d1fa4d65e6fead01c555ed81e9757641d48ddf8ca28e3a6448e67eb0daf3dfdcbe10a376db16063c1a3c48abf242a5ce4e65ab7d3e535339e5689017337b6051820045bee408764b4578c6d0d7e1e17b9bf537912925cad18cda39c8402e3897ed04ca387dad9cc68d049350c2b9d8440f4195144c5704251e5164cb969f08a4ab01d230dcff7c769a026ae57fdd36abf805d114716a8bae45c099994eef19abaf515a0963633763fd2c42f4fce201ec61da3b5dd9d2d89c62b9dc8dfe0ae91fd52b67822cddc9e4604da09865e3a5f9db7e19f1c13420b07afbd84725095ffaa7f3f301937842ea821ddba3e138a0e2ff251d03830a885b5efa7f38492e376f610d89af18c7878e0e179c587d33c2e17241a570496e9ff8e0e980d8d7eafdea8f6cdb92ce8479f21d0a45855a41f5f20103389d3edcae037113c6777bea02de2fe919c021476b8ba937d1272dbdf038cf74e5bc7c94f25e85a8314ab2c1ebcb0db37daea22c2411c77489425be5a37509fb21dd995badd07c3c0cb55400f3df5253d856068a0c643ab1599a30844664e0c1234663f447a1d6eed317b362ca8574e724c263c29221231e41f980c8a773736572f282b5818220e34ee47ea2266f9291cc5ed376aba26385a5252e44d05a49755b1f7b0856f855070ab9ecb1a9de29a5b3920b3ceda55c0aaaac031f935e563c50c840f9002b49dd06fec768a9a258eec5b6aebb997a9e2fade8a95fb824c9fe7332528e62b23d82f99cb9e13e9a339f1f086a7a60aace5f34d2502a715df1d1ad9ce421ed1802f6acfcc96836e481a9f3963b0f28f5ac8381f83a7447e2cfe35f3f95276d54a8143b458bd195cfd4a2b474923791e8edd3ce383e80c9a87a258734656d7e82cc26aa4f038bff3d13512ca976408466f32fe5202dfef7a8bb8aa0b24d798191d8086b5a3ba1742f2c105439c58ce3288d19aaa535818ebcabf73678f27856da1507aea1df0202b01965042602c582bc9a3642ce2b04d4b0bb4fdf3d82fd3c4f4c99ac960530b04bf5fc3b885b0a5fc6fea3103ec3649f40ee24da9d140ca64f28cf0fe98d57f72fdedd468b27601cb5e34d34beee6151ed6e3c452925fdf6b9601d69ae3c36e9fff6d6a1b6af87b9a09c3f65e121e21d6b5d02e068098dd1394894e472ded09f085396a4a71cac238a878c215e7a955cda7f3742fdd1e2dc4348f9abfc46df4650e82373f08e08dac0a59ca8ffd419ca2886c891e88e41ceb85e10c57a915f14c79f5820ed8dac9a6bde0ad419198efaa1ce3dd2f30bfc82fb37103e7091d75c23ccd5b7d7fdf1ea49aade37b3e7fdfd9892597be68b47c912470b518667c28e7c8ed0fe339114bdacfc4b61ad2268929c0e3d49e77ea2a3a4469b79977e928b4deef31617f8d97d879293318ceb5c16ed2df4f1c0a7259786270836ed39ab184a0390e0d0d084c5313f9cdcfab7490c0f8df7f9fb8d2ba658aaee470524d96d90fb51f509ca6db5b0193f817707b6afe3faf49779c95976d57eb710498d9e7d4e1dbc7026a19d079bd8175ce4f98d07462f1ed85fd34101b213cba0cd73eeaca9133dc380031f6ebdac8f05eb29a4f22ba34e1a6fc29e5aad9fed9a74ad8ebb6463858bd894e390499d715c5140b5cb342effdc7184c53c33624fed2f9aa05e085cb7d68e7e3d425e6a08f91dca36e18c8061453bd980f41d85df2924f3903b1ca62841d4545f8ad8a4949166990499814a3db50a62730c88ab592be1209aeb8d2d5bcb3597d5160ebcc24e8601900010fddaf5842745be0b72359e5b90e6c11bcf5cad521bb23fcf452dadc00d83a9cec6f24184e90a3e35eeb3ec473cb0a9ece0ddb5418734231a399728a09387d82acd1690a66acd28ccde630704ca4e7d232ca5d37eec3925a3874581d181b7391af5d0adaeea556515a2a8e3b164a7b85adbf667992b6bff10356b3c3e085fd3d676d90bcd741577f000000000000000000000000000000000000000000000000000000060c1113191c""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -f91692cbc904c6920af9eff6f57b6134b45bda6ebe9ae873a39c1e0f4330b9bf87aab1b9261fba98fc8681bd292e3e83cdf26046b01439457225d4fe957d9fa30e2edcbe49c1e920e9b4e1da4144a7918c575673b5728a3317247c1c38bbf42ba2491adc298d3f93d9061053b72d2677a5b168927d1739bb0540b3eba64ad0ff3869c7ca75bcdef3e697ddd18282f7e31622773f49cd2de94e93ee48f947c537ab55ae7cf18455a3b0ca3a933b562c51515beee14324e51416669fb931e4289e73ad6180f11994f5202af25df3c01dc9d8aad259c310e8bb17a77787b6492316c1b38785e127683653c33df908bcde08f4d4dcd56f70d44f3e37cc978019d04ffe2b2d940adb6e12197d951ee44b1c6219d4633f750066e86d3cbe36395ebf0e41f124522a6bd13f6ba9e95271ca11e4f6ed4ff76c08b3d3449ef64585ba266255b9f331d0ef2d7ee81cfa9918cd806b88cf3d1eb2e2e8444238d78929c3bb8a7a46b54b346bd0597d9bfefedd0d9267cafd84b11dc0793dc4bc9476fda6f1ccfb0c07d494345b50859a686f39c3aa487b6709790fad1688703c27baa9c783b77a07686c98b66063efbfa5a8de3ef43c59760607ef2b775396f096e3d9e4bd4bdc30a28bb62dbed11a0f9b02c64c1b43d98c2da2efdee1edf36dd2883a67c619204f0a6317899ea0269bfe5c6708920401e78a658dc4dedc7b35f5249d706f70c8b6e835093cd9b7dcd3afbcd8a94cbbed4600d86d7019a9b96d10a7a0bb4be62169195ace3dff5ddaf4c18815789ef97bb91023a33c3044f14068553913af1726ab597c534ac7011cd018f4a85b6d78648a3a1e5ddb20bbe862cd31b603bb275738801de06fb2133af9eb60a38daf9591c03a6c74c56283f658ffe6e0758c3e732bd7c0dde78ebd95d71302f3ac2d8f362cb8dcb5e8df32924e4c508c2e0166524e9f183df5933623ad00019730d2e8586a14776daf9d72dec6e3643aa32ae33fa5657bb00ebe779e4e9489abf8f768b181826617893321310b72e58f751d7a0d85bf68ab81daf73389700b65f8d16c2b075d1ed4e8db23619e960945978bd2db49ec1e17a9b7dc62c8037f20c45090d7482c0f66a1099cbfaa74669a2b7ca33e009d2a74db56453bab247a5bc28454435ae4196d74749904e790bb9fcf0108a471278debbb1002c5474040be81778077d02595a6b55123fa463a84343bf3501405b84fcf3921ee4e58aed85b623b14ca1b921494b26cb1bf53f5129e1f2184dfbdcd6e33675c09b4b1af71415849ad88c8c8a39f28300aaf8eb394776dbe1f2663014521011e41ed7fa1300febdbb59923bbaf121bba4dd42f3811e5d785c5512cea5e2fb787b26238a97845a9a60402484939932a183995fbe89b34120a839a91732bd0e7ba6864073967bce180af23f6ffb12b7e47cccfbd32a52d28a4acacf8e7abffd727e8c586c93e72e246f36060e88bef41c42a4ee0fd3025e24e739b6a648cbf2211d7803f9c94e3fa4adda936e30813aa9448dfed56b8c06695ac3605fa8754b4e6f1308cbe5237e0706358e1fca470c60757b9880f471f6655d138cc1dea586fb6765b6e0c2aa4cdaff60a6b2a696aacd5cfd433fcc6331d2cbae3a0f260079b692055012a1b684996ab5fe9a12ddc6b6a04437311408f938d634be38437928406ce2fc62d000e92398e8b06ce73def5fbe7d9f3f0e63854bb65269c9fc96590cd312d150d8447444c0581a4f6f35aaa90e1370c6b676133f2f78f151f223ca2131f2d561b7d08f4f83b255d1b33b9845284310ed342bba58e1f3ae9b5285803c7575b0e8c9c3be2fa58ed1025d9e9ca20ef203e9362222ddc0009a7e33dffb4de33bbd0a0aa7187d583cfa935ce26890f63f97caf2afcb8aaa482b5b6dd0ad1570e6e008b28bd9679046b9118d187be2e7f7f8ad6fbe10094b1fad46f78f372f68fd870566afd524e39216aee752ff5f9fc8a9eb6f5adae11ae83da416b982408376a99530f1bab6119f472a1d45864e611bb2a474342000938b5f9612d876b4278596a00d3db2351ea296fc2d606ba494b07b0dfe846b04f9899af02f9116b415279470e35663fe7e32d3ff5a2162e9f10b1fe42a5d04b14a55fb658e86eee8ac3a2ad85a1171a9e001a7a3bdf834db3192c5cdda3b08d31fdaacd3667d3577d40e0f79f037f4538de224dd3ddc62232e50e61b2f3de62823d58437a7c7462fee714a29b5cc366617fd12bf924f86a3308f8e57609dec2031fba77b52cf2888df554f814ee984f0108e55cab728c7af61d1f4e4b12ea7d027788ab973ecb10b7d668c3e77f7ae1b4b05ab8cdd73b0722498079a246ebc7eac75e831aadef51153d9ccc0cf5e82f7c57a5c57d95f2e0f623c24e05a3e8497e3937d9b8d095745beb6dc6c7a9d20d57f89864088a1bfb137726742e2a82ac544428fed5725b4e78ee4a9c66ba91eaaf4dc7c6c7cf23a37ca8db3ce626cd0c3fb086aa2866b6ad8113e2349908dcf155426d1c208467bcf8eccbfb74ab2e84a9de986b16a3a4bbb822f5dd6f9fa0ac93c4af7b4b332b0efe11e66482215102e0ce72617c1ae45d6f5fee32b27cd5bb18416f3f6f11d13c75be821dddc55df6c5d736f44371456b3827cbecb9d06d19513b8ca24dd0ee4dd31e9a6ae9d1b1a10b10e5bd7acbcc562449da200aa2ad9b3c4663b1be48fbf0b79cb7ac43ffd106699301c4412aa7ada34d1166056ab6cf9e0daa73240a3b0bd1267acdec0b04d5eb48"""), - TestUtils.hexDecode(""" -DBB70175E063054DDA24BCFCAF671F820D674F1D09CA173D4A1440AAF50F1FC8FADC1810F390286AC101D60507DD285275C6F97C0D2B2CF3C7F50609CEC64EB029C3DAD8B9954807E35D4836BEDF32501D0E7143BF488CD5B4D1A53C980BC70A3794E4392E4560E609B9C49900E1C56D319E1495D085440DFD081D1A7C52C0A8F64917834C64EF32A441C9045689DDD2EC218F58B3BD534F18309E1D780528D3BD1B23DDB3B18FC1F7C85324D45C3E9B25961FA5257EC31927CA35DB25E6FAF7669D60952502680BC7B5D777D77B194D0CC40372FC8F711EB048E01BBD5676CE3F2A9FEEAA4B5F29081C34969C746208E6F2329CB53A22058C0AE0852B7127FC4C74EB3A8300403F60B8AD1F95FD2991CE0C8CE452C2432B6422EFEA8AC0E1B53BC994C606301473D7855EF86687287BF56B450D2762C5E03AF26A987317C4BFB013A6BD791EFD141AB34718A37D1DCFBB63014F7F92C9E2870DE503452E271E9D02768357E3DEF6BAC5A0F0444DEE1FF5AFC79B3562C12696FEA15815B7D9BAA38C66919D137F82FE36B140B960E02966FABA1EE9CBAA04941396D665DD2C6B0559502577541AB0CEB066E066553A2DD407354123DF14F4B1DDE6B8C34E3264161796F48DB5319B3CDDFDFDBF5CE17BCB5924984143839B4EDDDAA8F0568ECCAD253C48D00687F9A07785A67B62D28B86D70E511AE08A525F66FB15AFD112C184785F91E76852DAAA3E78CB96E20249F38979031712440DB723B022E1323818431B897DACC51400DB25635EEE41761089DC47E8EA56DD0DF60B56FC682D000E9D660D0CF38C263B716359F41F3B190D201950E140D67F50287C09D2008664341A829A074F9629DABD88BE69A6058900DE5782CC621A91376E5CA31C66E3C430CD00FAA83BF765A2E6B2FCD20EEEACCB996FB5C4B63235142BD5FFB4390F8CB95BCD5853D0226F931C38FE972FBD0D6E10DC2CF29D1FFD2653CACBAB8B81DBE44A2B8F1C5DBDA7C56252E4B35888DFF7808B3514F4D7E5EAE9B51078E8D2E600EC57200FB48EF946F021CA8209E7DC6443B37D7281C73C6A3B43AA570398E62CD5ED9A34ED23AAFEFDB7DB3141202D940C1411CEFFBCED878C0D325E8CF7FDCC520CA3377BE97855827D2E6F4EC8786EA1374E006539387924161D65782C7B2C262AF9BA8FCFCB5B1477083836129DA973AB8B082324F74BC6320646448DCC8AB56582EC72EB192D3F72255D85FFAC2B5C62F245B73191A9176BA5A9FC0ACD3AD48D37E23EFA0C65F0423AB5CD0EB76BDC035112C7A118ED47C0E67E510A6F7A28F26C3D6A882EAE74BAE6CF1FD969FEEAF6B36C85F62D40CAA26B6CA98120D612598F360CA2628F6FD608F4E1E290B32C90FF71E181D4B72978DFCD189D857DAFC7B2AF8C958EEA6894ED59AD56B9AA6F83092EFECF9EC4091BCC9B8CCA245C30B54B9B8DFF3636BEFD417F46DDD2F6136B983CFAB532FB623FAFC3CC4CE8A91434377F4DCD1607BF04E431"""), - TestUtils.hexDecode(""" -5c796ec117395c38a9d7fa1a02d81e3b51522aebf68f3fff55cbf7d584ec75e547d413562c4c87f28f57433cdbe7c96644619b9f03d119c7f87f0a970a46075cb8c29c506f67007470bb4843af6d3dd1c91bb3c2c62443eb18a69e675e3711a08dabee5cc1a03d35a1399755566dd2f07084a9039c7710ab57b380712b39cd6f3cd2098225785665bbb94f3761d5a8d431cebcb533cbee5afeba6cc877fbb168009b3f05f9829606055e71638b50f4c6a41b0b226134391ae0efae4cb1d2e31c782b55035cd9e2d0bb53fd72749de022537ad8f8ec49a297f9bc81d1ee0f5e6b96470d30d6b78f48266eea5d3d4805028f90abbe90232fea807b50323e722a42fb455f02cd2c6f5d932b9bc606f9509fe2b1c133eb12de12db0206d78b49154c34adfe204fbf5469a0a50301be999015c5798c567729b60b2690ed93db0eac4021d38665a3a7db7b5ad55d94b8cdc9171a00ffa3ddbea750e83e495f7db132fc253c82b6b901bcd00fe68f0277988a1b0b2cd1d051d10ee189cf971f79ab6d1bb641b1f3b160b4a4d095144d1f9ce0dbadbdf6955622a8b300c69ae67dec7f1b777f0266e71413d57b454cea0dcd8cf3c32b9bbccc36e1eaeb17c87734afde3feec5432a18ab9a7c6a1fb30e2e84af2c367b4f47529bf4e0782a26d41520df8ac3cad44d4e792af7f427c75221e4a5230e282bf938a6072574e23f4cd35aa49758829d521360db34cadf94f9ba90d5139179f877723150d4d6f53a5300ea3e26392399adb258bc8075cd19517cb70ed48ba9c61e5e5f3d245d45f44f5e6e033334dee3a95bff8dbad0a1f8ecedb431cd52530d7c2d06ebc8f1b80e5e30e746f9b3b3fc192e359119170e2216081dd908d0a5b03670cef41420585653521ffbdfa58957d06d7a0ed23088a5835690df344473f44b6213fa10832539197afbb410556b8046e06d814c2702ce1c50fd5677de3015575e42b78aea720270aa303e3a6539bf343c52ff933aa238770e7fda2d0d0702c1c7a829e798b0677c1044a7e4af1df817c4167909c158074a9933f364a1800e76234751e7463c78255c3d5189c2a3cce7c2e55dc55fe97131cd4255d92b3f9f5c888029d4b92ff3a544e25b80ac12e73c9a65fcf0b755ffd0a497c6113897ee8bfcff0dc8c9bd583af6fdb71523be596bf0753b25b47766d5be895dcfb63d7c7d9f6143efc509629d310dfff428a1d5328b5307edb41822695f56a09ff2202567ae1b80318f827e0bc29c5df5e4cb075f1d7c1cf2df62dc258544e3dea90239a1d997e52e568632e259def0bcdcfc6f9306c76558dbb30a880d41fcb4f99988e6a9186296e7a5a31c7b910fb2624a0400bbdc6fe0657865a6537131f0b0dd2f56e2d6e2201a843bef51916226577e6bb0e891247f93b5bc36c49fb37e458d363762c12b4b95ba75ac1b38f177fca6515c240c40007eeecea8dbef687a77d3c09f9b5bc5450231ee83294e5a8d0fa79430fc2e701ab39d3bd891e73a695ac6559d8a8b4dc4a6ceb7472ad032036e4aeaff3154099a6f2e8297c6e4bf121631b545b472ab316aa0a3e1192874793597e0fa0cf173a78507ea55b2ed0c13fb045a96acd9d9bf8cd5197f968efdd359bc4449458ac42e2efa187190790de076f56445f92a79be0469efa11c98992ec82e3a2ca311d76e282e91665f5659be663a33139e80952b444914fab59910ac08daacb6cfcda1dc75c00077391e2b38ca54c1e056968c4c41fe7201a3c637b37f48be5672828d5f20c06bbc818332f48e0a4c0cda579d4c114d0446896b60392bfb66ec8e4eb5c3e8932259c423025da0611e06b34209f35413be186d98f8494d18eb0b2d56aa47c6d72c5b57e2f68da8ec1039dc565dcd5c5937ce1d358d6c83ded381060647ddb52badec80e92a98dcd4be27a5990c85192e2989dc2553e3606f6e6ef8353202671a1f2dab2d3130946254a686121a26a29ac8553ef5a58d31f9607bf3912fd4340562ff48b38a12b7f4d8ef2e058c9c721467e0787aa0eb2ff53ffab5c2b3c40f52524d8ff1cd0df1edba1dcafcf983a9e8e9840ef269f9648d3ed8e7778e086bcb887c54e49c8848d21002ed58f163a6888b171a945a9269f410b3d541b07f7c83c0e6b80dde9bff6c3f6da1f780f52ce0da11c196c0493b6765bf01aaff22e44f2b538672b4db58a616e2d2a36b1a20a618acb6e7523546e61c8ec4b593407d0ccaa0ca85d2db46a6cf188939ed9583f591499fa436443287fda7e49602dd8677f171b487e4fd6229de805f4693fbc8f27b52f283fb0384a2994755c5a6c0ea99a8be6f6f743d05b75405f9e70d68d4904b258d0f5f3ad0b23d62767d54ec493f15bda17b34c31eb50210788d38ccd4490e0b65ed46e50875da092c35b0100aae8bc387ad595be005bb52ad0f3281ac662305e0a62ec6254c4e091b1fb0552398b9cdcf2c12069b90b6ca5d67ebeb22b6aba91a7ddd85ba31addb18ea61d98429e633e5296eda442264dfd6bafdd3f26c9d6cfa7d8c89f273c4058c7b88ddcf79d7cf5c8bedc4ccd69c4b545a0069906c12c0b5dd5514cc1d45a50173c4f51e0cb89e2e56025539394be823889e0b7cd3b2563f756bb6d95336a22a1f84215915507708fa18e425a6de61a7ac74689bd85bef8aee1a48226a96ac318bb3d8fe95be46eebfda3662e04741f93995e5c30b1b3864feae3b476f341c473d449f3d675c3335617a201e992e9e96d35640d0152587c7edf50ee5542164e12d268c0bdd808ebe067e4891172a4d765650decb3e9baedae4c39834b5b6df1c8252a9b588c30b25167c543f389f4d4db14fd1319161453311572c85bdb5fba5886325b5118b6bdf774c76fce3de923761e22054867a19a06e2f84463a737ee6b4f42cf97e062db911ef8dd2a6cfa15a4698ab96c9e70c7823956665386aab0ae235b485391542ff57967b67274a4a308818ffad47b82051e674ae13ff73a111c5da089500f14c7d05af77d777c612628b157f3a921bf8b0cac0fb426866833ee35a2176653dace88dbd03cbad446bece7c6177373db768d561aba1d86ef2a5680f5d71e2c4e35832e8ca69de760893f3e6dca2e9b39dfbfa2bd4e1f3c2f5ac06e7b07c9c3c85de16244a273385f9014263614cecc9ba3bc1679d8b2721211b7fe7fc96612abc39312d8d05dd530e9e6f00977bdb27b0632eff254f54213213f608177334ef02f79cbcd5062c9b50f9c3ab14a8fb019d0c2b11ed1a5f93d769d3fa14eb3a7e2a96c738d1a3d62dd49a5dcb34ddf6944c066ed1d4c662752fbc961eedf9606c40922c43c543f6c79cc4e91432d652c6ee492679f84ddf1e1e6fb885af725a63168a6c6eac8cb180fc2b71f8d83112b81b168e96e42d3f069b69995c351c6b2bf1344f98c5fdb2f3fc503dd6ccf5cbc9a1bbe111ba2380bcc2392cd3726bba4afe7dc66a103a2defa50516d7d0d5bd058c7361bc6a81379a6c48fe76e81cccab97af3cc2a96d4abd8d5399c8ebbec651320d66019aeee16dd9e126a4f6b16ddea40a36f2ddc9e5d91bf8d5a39cf7069ee917c23770c18c54a5d2ca8f23ca2c9d21f9003b7381c077b7607dd3e3b0c34cb12c77ef08547501085370c6225e45c40069c87161bfb45498397c5d714c86442cb1489accfb34531a14199cf29e0e611f4047f22d40db532956a20c8f5561d9c6120a80507c525dd8584d60f41e999686096454475a2c92bef5880e554a09cda2238323fad2827d9ba6cac319b01d2f89d708a593d660f9c19499328167c5843ff20a17bf0ba26c8418fef3ad764a865f471099708048a624c39bc7ac317badb19226d8c0943e0fb8aeee9789c0ab6e43f932621e89c424da8a6eda10b936218264161433976904836c0c913b5a0f2fcd701ae18ff8309f583f75946a02b930c897aa85ccd239ce2edfc7dac8689b8e678b620cc853e5dc57fea9221f3c5ece3a1484022934d9457b6d3a34b801baf8afa4adf307a8c7b6092168dc5fc35393f772b576345b2f6e1fdd9ccf27452174b8ef6bde9cfb37dfedc43755be905373f54e13a1a40c3757a15bc36aa21657ae4a64a16bbd4463fbaaf69cf4778306876b62abd4305d753da808f0728c3f51f838b640be0c093b732595b153e2615da3c0d5ce5801322689ce85f91767bcaeb81cabc3baeb76deb7154b79528766282bbea6d026687d2f823fc25b97ae523e1eecdcbebf460b447b1a2e677c0215fbae2da1dcd182bcfdc912b94c732b793588ffb0d1e118d02b093a3cffa510d159ccc74ceea63ed881ca79957dda6db1329c22c10a082baf48fd6a2b635b3f1b896e77087734528d0943da51d31b1619e549ee1366e9df05d0a356aae84cf8f3d0c8fd5ab534a3524be784eb0208501f17e3b8f70a52de886bc691db2bcdeb63f7bd739fa3dca52e4d44a7b6b57564f17076104da5169b46d47bfd01d2610a9fe55129e6249956233a911eef491d9c5877e55585f62f1d17a84bebd25738d11d830c2bbc5b55d7fc60894f4db0bfcc6639277d290ebffd8a02e4d0593f65223168240e528822a90d4fa94febfd55e5562fec1f279af1bf7333d5b8b8eabaec3ea262a40586d8ea1e12b3b417789ed00010f333a787d86ced10a233e7385c3d4de1c3450557ea5000000000000000009111721292f""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -775194fa9e30c689e7302d8c2fc00a7f00841fcdae64e399a53e0be695466306a8c2bcff2f1de6a5c7b2034f2581179849bab2b4166de1c203dc8c85878e9309eecca9cc75283fc90ef0e01e172630a1fa8075644c31e94da3d541eee7e08a1c3bcaf746798113c7a7d70f4eac26fdc630b692bd734e5a65b913133dca7d9a432e2f1195d4a76a6a011f2577a1699ae37852fa0ece9f007a429411282115ac4d55d1e7f073758e8dce2d93e2e81a857985a6567d28a155a0cc1dde48a3abdfbba3e562acce270827c77421780fa60556ccf9764f636cc54d094e19155267985d066b8af7a7cdbd0e76e18324bd77d92aa27795ad2f9abb5d68d0f768e1b124189b2078d133ac72cdf4d9d697c24aeab5684386c81dd11f5bff5039c0da8fbd0143278660abb563248fdcbe666a708ce2988ac38891a4e953913fe544014b4f05f75a92b14e29de39eb008b6b23875bf02076518036aebe85bff546d326d9bb9f7226271f5f6b655a8824029acdd548c075107e8316c839d9e4f94b71ee49ee62101c3dd49960eac7c6bb9f113bc7ae4975f50dfed974dcec3bcf3b90c77211bc4304ae5a73a277732ea37247ae7410858cfb053316ac2426bad05c656c6fae3f3c762b384cb6a3626dd14006e9621d3615249a61e39d665f516ae5720ca55f5a52aad68e5217a0ea27a8a02a4c502bcce7d9f80d5ad0ef395b9e55bd2b6f0fdb12cb7817908f2907f8a625e65a13d7947f15fab77009aab91ecd20964af49d008d32fab27589f393a36c088578f7b8207298cd028731b614ffe2fadf0b25b940cddc8b7d80c3885f437789d5bfe7668d51cdcf0db684fb4afa7506b828aead4fc51964af184c63e94424520c99a44ec01c1d7074d09ff0bc8408a7a6cc9b1d6af804794c4d81f71828e3ee97901f92d4a8ce677744492e15b2499ac9424850bf89126d8e7e895fafc2581ae1b593f9bdcd1eff97ada3be693eeb7316a6b41ae9cd719d7e1b0e9f41ae109a15ce1dc9407d01941826b7523e2ca34e8ca07ba1e94ca3ae63207c6185378dae26e4c675a676406eff2e89eccdb516059edb647c79aca7cde5a17f592d3334346b3148b34fa723f4a005a0d16864128560e805db41c6eae80fa1d8f0a07ba509baac7a10d0d34eee421a01a4d752853bf8cf5474109dc49d0a2e25b08cf36481902f911031fef980c5cdacea31f22949009c540e033e21495e740b559b3065a1ea6cb602979f331000dd442124ef0b1be09a4bad6668ca435c34c2a20ed8b254b12bf84992b43159efaebb5bb34a8cdd692c41be6c88dcb42e802f01d3a1ecddb061ff829487a3f5055c6aee621a811100ab764c7a20d662af257bb0def598e59b5d7c3f8729e5dc55535ad77e611fb20662a30f8267d20d8f60614e2a71585dd46b6762b93696bd012ed319e7c8f65c253bdcb977c063499672901214616d8f699ff0b04fc074384c648014f15225e5786fa1534cc85202db0213bcb1e494fe0da6110cc806f029b27625275f9b5bd783e86e494795fae430a042f90485cf18adaf974344d43dfb5ad13af1144e85ee57836702b2133774451a7d51007370b8d621f155980a417789537f7e1012ad2f9c5e70a579f7affb84e3a41cbbf33a1dc197776f816dff08e2e0f7e0537f4fe16589c66fd28e36feee9fbb959e269fb919f07ac55cd424f6570a55bf0514b86db71bf626786d6ec56073151b97974ae857eb651bc6a3866ae5fd61fc16ae29db7996d277b7f6c85b3d78928f4c84f0789348bf122768e7b17577667ccb5b7bbbbe5373e1b5aad9c3c4f7f3f1a96d6d4e42ced4e18760068a4a667550bee909946e57d5fdd66e92cf2bc195b5a2b2bf0214210640891a71f7be9aceebcb9cb463dd8b02190ad9aa006413c2784d468a2730ec70225c2a8eeab4c12bee8cadaba579c3db5b3f4dc210994e1bc26c8c548b9ca340a658368a405db1efc98114e24f2cd20fc8743261a262fd474ee6c7f254f89f0cb6c16161202342a8d1aa31e7d8a829a7e1c980a62306e7a3032f4addb96582966b56b37818875a14aa80457bb281a87ce72a5f90b0b30ed57cda8146f9dafb2d7e8ae79e8b0067f3323337c799aa849779ebf718ab52b8bca6a660795ae5a4adcab49f9f5555c1241100962d2d8f1c78a330b5ddf49bca2e06baf77d8480fe32570dc55cd009e94106de4cbcb6f0efb3f9b41308a5ce341c573ef085735667ab20ce51320df124806e7afbaf9cfeb57ada0aaff578056993aa5fbfdca313b1b0142e9159f89f25def669c8846feb01d2e06c6a1c1c4faf302330fa223ec9b52ccb85e284a98007e61f889bba87dd520f2f9d836741d01112928363a1e968cd77108fdf0b8624d5f01cf4af2354377e70c61da9ece5c40e8bed1b62da6a3c9840975bf8854f075812ec58c4d814d7c0d0686438b5d9a2bf273a54be6930e336928fc04657a17865a073c6ec72f8eac813b9e944edeab724185c75ab2910ec4a9b47d7abbdd41865936fe5cd7778bc0fa0db378c73e404c96f093123b183e5d9da04f157990bd3274892681d40be1387f96776a272300f2b3ce6d581a8faebbff01e6e0d5aaffe8f4412cd7bf3e593170dd0e3fb42cdefb4201e4448278571ade12a62f6ec6240951ee8e731a0f600c7c008900818bf46a585d64fc47d9897abad71a258a35e4ddd78607b175b60e3732ea47ec5e06b1cd47feed7f4116cee6e0c815bdd06e72c9206700e10a60deb5f2a7c03"""), - TestUtils.hexDecode(""" -5F8F32FE68B556ED1D2EB8D2BC20AA36DEC7900F8E5D4BD3715419B28771E5B0A080DEB2F3EA6CF415D40EDA46FCF8A439954471B7308D3E4226E9D5A96BC22B08FECEB4C5E3CC2239473F1C9B8DFA5A29C31D499CEEAF6E34A396BF0DA53B54F1AA674056216756DFE15F669FC2E1D8E6F67BE5BFB3D5703F25D62D3AAB0398AEDEDF7C65E051A4A8DDFC725EEE940BD0D06B103EEA32D027CC20A8C61034DC54BD5533CDB1A85107B9CFF283FC3C5FCD9C3D6F8857560311AC2E0E31585E77D0806F9A4E61A70D3FF36895ED447C55DB52002488045CC358A39475BFE8456F4FBC36005218B2CEC1C573E41BAFA7A622EDF776C8AD340680C1B3002F69D3B3D8844494EA9F42D2C9C9D2BC0BDD850BA3C4DE929C1DF49351219F95EA7B9794827FC1A1BB4A6A00809393BC41852820569D7BC6FD55339925FFDF55A0C2655C85144234FDDCA91E8BDCE8CFB7199330763F5750D71CA8C4B3BF7E6469F5DD68624BD6D5B69E5FAEEE53E3A61AE659A364484B7D2BC8A85BE9F8D35C8B97716E8202B610BDF878C1BD83187F7892BD861C09FCDA64606A185B93CD2F601C3107D35B38D76D75AD6023AFDD95E103EEB7283379BD9E44CABAD923856A599B719A18FA836749E5BA95C79B1F2F1B443CE1FD26CBD2B74A0156C381BC270B74FC42DFF8D91DE4ECDDF3053007A09B8E3C964B90DE55DE5193F218685327D8C0C6CE3BBABD57DA8772DB7CA9234A3D19BE16A895E7D14337FD9D50B4A556C75A9D287B44BA5AA4E52C3262218DDCEEE3A7BDBE1B8175E84113F515623C07BAD4FC0985112DE4D77D31290BD013562D12FF8CBC5F2BC463223AA82991D7D60E38037578BBEEED70631CEADFE49823EA3D87EC384B3FBD4974C474FF9D47F467110EA4F3FD94B5FF38D8FC1C75392896394671853FE71DDCF7730C70ED26485F395F180D2F5C31AE0C2C20691CB4BC81356225E6A72DC72A1CD3502E42C22B594118D131BA5EF95F2C18B3061139B047A24E32197F89780B91D36B28BB5EC6C03232A3CDFC5ECF687BA5701F3958FD87FC0C8D09825E8BE4E5CE9089C674049C38EC5E0FC1AD542F57B4770B6E5DDA215D319DBFFBFEAD9141647A508E271CF3B0DE7C137A5AB999CC88082FF0CD495F1F1FB1E367B57BB400D8697B4620B75FE467D9B8BDF9400E14047576B3AD6AABE0C0714686015B8A963A0DBB68CE9E41FFBBDD5A792920916538E4C33F12EF0E93D249E562B71BC1C252E1DD8AA646F8C7B489A2BCFE7D29A6D3FDA2C21DDD78179861AFC766F6885E9959F753C66462DAA6E01C8B06A6F581104B583F7A5B1B4935A4EF08219FA8D114A963F3FF3AF22C3D1C1E3927AEBC886AD0670FC89C08FD4DF68EB990A0F7C51A4439C32F5F51785B20DC82586940C35D80A91865C3154D6C925250B24D4C1A9E76A267711A0813E8CCD2DDE9748FA0464006DDBA963BBDABAADD377239442DFEC6F7E8098604645D63AEA080C1F749CAC589F77B4AE0955FABED757E6576966D539FE1BE5965D03882279B2C9B6899205C9DE8D0B1819DA8B5426E573CE785FEDA3BE95A18A667AD5AA8FCE7894BA11A44B266EB7571A93CF9FA64C1132AE07F0F24773C83DED2C2885D415ABD96A21A0381811D66952252786C39EB68EF0B9B03BA7E2B66A49BC6CFCD8097C321A932E5CDB11EC6E43A8E50DDE01EA5A28F08F5047C67C988E8B4A04701A0237330598ADE8EF8F801A07F2148B44E593B0ED16DA30BF37A341073C6A92066645BD7042C3A59B374FDAC00F7F69BDAFCAE5EC0AE65FCFB785C93E49102F5A5029876BC23B0FDB7FBBC376A9E834F0D19A276BC4E22FEDA18FAB529F15570AB674B844703B47D726AADE3AD4015F52D86843A01AD5DF086E07A71A0236765DE6A777F94B1D69253A424193FA9DF54899AD9915634DA23E6DF351E9608219684EC8C8C949E900718DB6FDCD144D0BBFE1079C1BAEC516BF60C1E24B8EE6DC380F55E0F65DD64025C937EA89FD12F0404ED0C03CBA18CE2FCF169F9A1EC9B96830FAD0149D4A90B13446347CE4E5C6005BF115385F1D22EF6A7E40EE87847BFDA4CF7FC3135C4164091F49DD08389E1005271E9AC76E27B0CDF360EEBEA9C08E233CA58305CB276A8BEC9686CDE0E2DB5CFF9858029F3A5A42759E4AC6DD40AF9617CDEB03FB1F9D7F112A01B87A265C4E27BBFF596695F127A97E1558A68BB5EE4EF0F44D20F318FEE1CE988051F3C09AF6E142932EFE970C1B0C07040E7F3DB9BA53BC4AB1433F7A4F1E480D920C23A07223D7E43570320B3BA590507D580D29CC3A8C85A442BECED5880350F9D2B1AB5C746C1B9909E446D9508D701204F2427F41E043A78024EE3F60EE19B71B5BC925A2557FAA8C7BAC7E3405C920FE3FB3A1BA7C559BD75DB1E4169804B6627AEF19AE6E41B8A40CFB977C1AF53208F4D775A48C220A756783F41E13B7780328992947D215C5B5682DEC76CB035B41C007CE1017EEFBA426EBC423F710C1E962528F7636F200C2E79D8377D621513BA7EB3EE5A0DA55B81F6039D2E8BD42EBA5B2A82C3F033CFEED6EFA7D970B1460CEACD13A0C67AC0A7EBE7963F0FE21D20B2A82EA922FD889253B5D4CE4D47698D43AC11A8F4E1638AD3A4C179C522A3ABBDF420DA3E89B9FB7608822904944CAD615C62B28EDB15D3826D33DCF9FF9BD5DFD8639AF4CAEAA55F9F8409B4E5F70681BB7861F88283218E15A4282E199BFA12360FFB9BCD68D9BE5A3411FCA4E8279562F595FAAE0CEED4FE675DA4A8FF94B180AE9D0C8C687650730F05715820F67248D02EAD4C7BC0D41C880444B94CCD60A66A1C9B5B6F6690A2E1766EE10B5D03AC16F175603A1B9D49F97CF3F91932E97DE67CB523A38839468EE7681909CE997BFE5EEB364B472220403EE4A9AC1F8A4A8F78AFA4D9010A0127C0A75D3CDD87DD269F19A47C78F696218F25AE8A61073644A4F791ABBF1B180267AE41DD44AF65EC6E0AB356CFEE86095B64F4190D69D60284A1EB42744C31536F736AFFFFF186833EBBF43709BBE6903A06F7F06E8776D2AE41CFCA33A3A86342BD11B67EC10F525563A1843C8443546C1EE61DAF7310802AE9C00F44DBE7E04030BC4D0F53AE2023A7647F08A0BC6F5013A61A84E994FE0A20092DE133FABAE3AA24F8F3946812396B0643721AA13417A2423F96CA8A6529B0E17766E88B2AEBD79AA9D4D31193533CE50E4EBDAEEC976F156D5DE5917D54F9CC0527BB4F1F795401210739A42D10A0242748DE5FF6B50932B507057EECF8A1E37800223378642DEDADB464F5CA251D73DCD28A1E3772CC285A33B34C6701B585FC03C94A847CF7B16616D1C3DD646669546D80A27E9DE6424AA7AF6F1694037E774259308E71E15D7408BC1EB517CF0AA2C9E16B802CC8553458BB66D96CBA233487DAAD6E093235D901CF46F31B9A060D88DBD0B7380652EFC73AC1A6BB5E434EB0394F1EDC937E9A99A3867EB71D6E19622137B009D36ED7F9890187CCCE7D884DFE118AB3682EC08CDA8BA6DD4B79C9C18E7438E6914DC1C403870A540B74244964CA31E730A7D7591E42569532DA8094559241F2C7EC182FF8BB5A3F88DFCE3020D8B8CC0D1F54CF67FFD3A97CBA7F5EC79333D9A545221C963E0685763E59F1EBD34FB2394727896CE638E909AE6DFF41D17EE1D0BA036F8AF11335A8C1B5A0E9DC58EAB9C12F46740493A8B5AD0EAA73AF462BDF43CE44BD0973688D9C8DFF8FED961758E1AF88FD5D249FFEC179FE5AA1D135C0448D80F4B0CB68492CA399A3916A2EAB684B44E407706CC3C2F48972BC9531353091F91B427FA32693906DCAE862F34AEBBAEFD30666523EA9C27354F2FCD99A6E810685B51965571E4B4B5AAE158636497B6F952FA0B73617AE35A8D7C272DFEA1CE06E983CC65A501F73BE9D69EDDE6A4A1764DCC4B74EF09EC27C74B677920AE8C49CF4F18160E04B5AE7EFA8D5D92BAA5E4E547CC8AFB9D55F1A9DA7A6AA06626673431889C9996BE0A473702450B960231A617DF4705B07B47DBA1BCCC0EFCD5713F88F394EC4BFCC49EC24B76D531A356A6796785D755F027C664D8966B5CDC82ADE776BEECA8AB0D9DB6ACF5E841BCB4381828DB8F7358A637D04D97598A8B3BC823B891F5EB6ECF54E6F9200C380813FC3210E68894A656796C9A5B780FF486E6A93DE055B8F658FEA17035D9C212D23BB5974E1161E4F6041E5AEC446D70D52CD2F21F1A33C9938032487D9ABA74C448EEB8F8D51169E8B848242F5C769B471F0AF04E965BB0F4AE7C6F7B4AAD4E283DA762DFA49FD01D21887ADB28781FEFBD931AD8E2A26BBBBE5D88B52E8B7133134CA76C6648EA39E3D2F102177F4237219E06CBD05174D503C9288EC9C3E0128A824A7ABF418DC45EEB3A67777F74D6EC52891EAE0BB56DC756ADF40D39151E3A68719C563E99BABCA4C785BF4C2BB1BD25C7EEE22A8B0C1E90B948FC3A691670E9A3A331320CA4416B492907C3FE70AF9A2E765F9607EE1BB2CE52D2DB15F5DDCF59BDCCCB5BEBAC2784FA0896BEECF38C24022046E5DAA7607E8D2DB8CBC65541CFC6A0F20CC3AC5EBD4560BF5E9A3FFC0BAE917B479D960ABFC99EF84A696CE5A95720FED90F3AC58D77D48BD5573A0D85681238AC0EA8F0B58A01378929C691C146068897C5642DE74D79E08E5B94B101182200FB3E2BBFEFC8B44D2D1203075862D77A184B25A7790D76D7CE88C979D73E599C212F04A8B01EC3CD6CED3B5E25487957C56BEF6AB4433FFFE6DBDEA396212A6870284FD1BAACD5F7A5D9FAB90D5DA39D3C5F9AF196D9C46100BF45861679A7679638BBC8E5B5A7606D863478B430BF2C61F52D3D88B0913BF12597620D337DEA52BEE9CC8A1592698D23B23815C596981152C99453FA16800545EE781F24841FBE5A3E5AD8D08F2B898127AF40A681DF9DB68681533C349109C29D19311BEAB4C2F2DE97A5345EA7E41CC0988B2042925F1F9409D947128CE1D38F278863385A19B2CF8338D0FF31B06FD865B9167488EA157C7965F4679286077894660F17BC7289BEFFA93CB7DB990A0E40D998945A77E536902FBAD3C8A278CFE0AC883BBEA0B20E5D70EC6E10B59C2449CD1A0B55F8252C91CDC87E70E72FEC175D6D67BD43CB5AE4EE9C7F9476F4589E2BBAF89E801D5E14458F8A0B96ECF9F080E5150E2A5004C5A89B735639621157C4056DD1106CFC727B921D5890F37051E2B906885C1CA3999C18FB8C9FC9B652D82AFF074EECA9976D612ADDE990DEA418031FEFC4E972B31CBCBDCA0469E3966FF6F97F9788650298DB71CEDFC04659D30FE673602659C19A869FB3EF4262EF3FFA9E3FFAB1A3FE7670061EBB0D49BC60AD0C774913910E26E4213B76DB72AEFA3CCC197CB6F6DF773F86F12480B5BBC2068F61E16D1C0C141AE6F1811B2E0D713AAF60B90BB2F00EEDD4651FB5191DE5A246A4D8F3E9999D85253FA705CD4B94A6A64D9E9B6E18BB6855CAF6B991494A8DF75E56C2A427883E0C27246E5854B8DB2EB0FE639BDD00AD678D1B61D799AC59ADFF6A8616B357A4B12A786EB612E5613CDE533D92E87D51D47D860BCC39687485EA814DC5F5A971EE915C193ED52AED98D7AB301E32342F3D207BC03546460D33B733E1008E48D80E716FD717BA82403DBB520246AC3BC9CB91CC0ECDB7E35E6863C3C11558A8EAE9E1DC49FBFFC0F92F397828A4AE7107785939B96932B9EACB6BC6D8B3A189B5D3F6B0C7A3A413054B25318792AEBA3F4C77629F1E8CE1AAA98FFE1EF50C2E60C11AD76EDDCD8EEAF858364ADD637AB97ACBE4D2124AC0AB559E85229F1B5D81701EEB1D6834FB215984E9DF3847392EB29D2A428DAE7FAC283F93C8FED86FD2377E8216922D46A51E628091F6F8EAF967740B0EFD84F002358D3ABEDA0993DA16D0D8233090A2CD9C27D78DA0A53962FE7DD282B276A30F91C2B734EAD2CCE5E03137205BD97739F6CD75A08491D4ECB22591A6FF840B5DF123FCA7DAA98B11C85C1F8591EB988024C206CDC4A4239E7A91DE75F49541FFB6D91BE4699C0C0D8B4A44A8204F7E90AB863C3183C2270D185643D6A7165C1D043FC5108C340650F38A8FFBB13BE4BE68858C50A2463F7BE998286FFD0F981B45F5E414FDE71637D6EE77B33E10A530C630D63F21A212E844C2F7A26BED4F7B4DCE0C566CBAEF4EB4BDF2B53E743EE13A845D3C7AD5E9525C50CFED35DAF5D993B6377CF1DFC5236D51151B046F4904A02D7D51B6E331754B0E3621DE4CAFC9D8F7247788DF0EA7E6141FAC4B24608282AE29D594CEC0C82DB05C0087AB377D0D504F64F1CBB2D9F3121087AB6F35A70ECDDD15C9AD2A185C16333BB901CA069BBB0B80CB6F505FB3F382CED72CDE60FC050241B1D32818D11AC4421B66CD85D0F7B479C021AC111F8EE8F1C60B2320585EA276879AFE4034DBA277806FEEACE548CA0A5D36CFAE7B99ECB0236CF4838254A20A13A2DEAAF201B09FD027BAFC3F0C5ECA9EB5850A58C6196645F051E57B82AF4B6C2DA9441358BFD2412864950022A07542601631A00E27BCE6E203B1D3F1B844CCBB2EEF71A12AA4E725188073004849A225D733C77C068B0D2AE53E0DA6F759A8E7A5486C529B29A3EDADA69924E7DC200158DB4B612C62039B321CDACE8294DBB1A56ADC685B0B0122A4F3DE0A264F47B00C903BD30B5E4281B0C75DAC5C48E18BB0BF642F8C2CA194AE56CF7EF3B4529FB9271774108C61198A6894FC9FAF896472D1CE78DF00E714045C5F7C77DCEA45B3ED5BE5AD545D8F3833206340A5E10DD3375BDE0A068D050CB4C87E0BA95CBACBE59280BD5CABCEAFC88F5C05E3D8DCDA6B15C487B62B467E093259230D47B79F36572972BB78F90BD384255CFB1E4F1DFB7B5360EBE1230F154C3645A7A233FDDC472432F6C845CE86B078D93A5BBA3F8800C5313593D66A8A103B01377FBC5C6D5FB8A55DC71EB0BC9904B24BAD2F505D6DB5640E914D84FC71FA058902578B72C47659AC07AD4D64C3D28328D2DC8425C4039EFB2F20E3B954BD0B0483848F2C2D9528214514510CB0932F7506E9B98D0E891D8183A907FCA7AEC068B9FDF7F3479A128C6982BED19512A4271D8B682525B5028B77D6B6301181B403E5F62F64BA3CF06F0EDF321114855839E9198E5BA2A65ED952B2204809215B9BA3C366FD5C9D409BD71ACB748E653DA82EBF617D2D57C74CE37BF20AD8D789DA53C086423D86F94A96ABA379F3425554BCF92F82FBBF5C2A15947455D7D7478A84BEC6E3B9FAA14E425D2C8971DCD157C1D9E210620E891AA4304CDEC54BA7B3352556C49A172EAF19919184CA005A526349918F9A7CBFEB83510AD899BAEFD3D1F689DC3F449153597C8D21FA1C7BAF18E689B51F89B9BEF196193B7A781B96B38B9145AF7338FCFEA109542BB1719C9C8540B551A35F733C394F7831900452C0B8D36BB90824699BDB587EFCF5E8410E4ACB8ECAEC5F96E74A5DD3DCD4C85720064A14028FE768041BA1A13A46CD8A0D2C4D09E724591ADCD5EB907038853D8C92C5BA7FF57D5B54B2B324073C7CD2EACE0C521254E9E5C0CA197FDB3C1AC73FA8EDA729A858098E6F5EC11A19D4F655C6DC9AFFC4E67A49EF62D80EFBCAA383DD3DDC22C2A9B7590C16F8CF23D52392186B95EF9E947D851079C35FA11595682DF4EF4D770EB16CBC3994326B8AB3B2C279149122D178BC7B53318406738290596449D797F61B3D0CC8B11750F8D841FDD9D333A5FECC67CC7733824BBE257D40E53B43CCA19C95ACCA8FFF393533AED57D423BE0C38584A81689248BC7F78CB7FA4C94A7BDBF3015B4072B83748E55ABBF4A334AED679D89E2F18BE1B249B3F61363C79AEF6E1FB09D1948610F77A9927AD6D57BEDA02BB1E77415DD7FDD3EFC683AFB1E20C08284B620EB091974FDF8CEFBCEE1461C210E81E86B61F2D5D1882261D60D60689E39C81B981EAEBD9A42E608A34155516E4E385B86BF0A4AA05E3F99B6B3B7E401724D1442A45A696A189765BCA3240111E9259DE161DADB4E0ACFF27818C631A8A2ABD752773A83DC29CD619A58556040A7B27CF56086BD499F8B8D283683377A21BE120374B8D4561AFE781F246AD987E828FB40306366B4BF4C0B4B909ECA91DC85F521ED5869A2F2AD58C74B6C959AC71DB6F11503F026DFFF6BDE6BD70363B5B38BCA0590A5AF2A1054209A36B41B2A671293F2805568400AB282F783C356DDE30E0F87C001D9B1B9716A7C4021928253622F2DD156B3C3038A077A5768AB8AC070BBD9467E9C9630754934186BDA122CEA503F5E274EAED746065CA81A2702B582E82A33CF6CB3917D451FF59B0909E6BF847E6B610DA89AFF98B3323E1385954EDF1175C0C1B158CB905BCFD9AE7FF9389ABB9FBC5194A45DEB0570C58F31D914F9941B0242717B243ABCF5A20676051978C16FFCAA8ED2EA23B8323CD58388860DD64FA39971F9FAB83A4B248EC8161D32565917B7E6EB4937B4743C6C236E75E1747A1C83377FD1D927D385D81A9EA7F4AE5034097A0A77E2D2EB1943D3128BC0134F2D600ABB929A5281C26EDE1C12CDC80F8EAF2E893091EA274EDA1A246AEA3263E43D6C60043CFF6282AAAC620A21B523783E0CBE33F78C89D00EF8920CD53C6EC0E83DD7E1303D9B6D5280BD2BBA26376C17099758F34C22054DA031C86CC50367C81C3059114A71C565B1702981D77040B0FEC1E89436ED1896E93BA202F11ED2BA4EF33A76F86AE8E23B8FD064C8FE894244C97BA7BDA6BB56B7517C236400F591E4F28050C2958A7A79964AF233CFF8655F1603F6A0C7ACCF440D0C82D5528876721434C163D86858B02C6F6A660F53B3E45185FC7777A629C3E4392AEE4A96D900B0F19783DCB6E5028B6E56E160A37D37FACD7C3B992773ABC8AE1ACD6AD41E7340CB198C9BBEA1CDC185AEEB51E2620F0695C2691A29CBCA8E23328E84B6882A59A8C3C2A273CDBD26965564F1F1DF0B2CAF83F30E782C049DBC00596BD85426EA90ED30ED8EAE8A88C0D1363E69868E8CAE56E8DD62CB36D9A15150FE567DF7DC93CE78706BA983885155C9AF05B5FF1D0EBFD9D020BAA9196D9C871236DBEE8A703BE458938D3C882719881BD49476386387DA3508780878271C0DA821BAA1E9719E437BEE6294D8E4E2483932D0257B44B8CCD8C55028B3B7D2BB3866216A7F52CAEBFA0FBAE120609F95213BC05AE24473C98C29F4A46D985336DF8305787A0374098DB279EF0E34E6DD79BDB106EEA24E4DEEAB6DF35C58AE73FEC926174E0942D242AF0D30825274FA1D510D1C0C41FFF59A4381CCE5C6B89AF30C41733EF42E76C9CD58DEA7E881706843BA04E3A170304C551B6C801CAF9B8DA52913D2DD4DC755E0BD7C723C4AA5B001D9855236401C1014507CCB84577749DB1AF29E318241D91C4B23BD80549CD1D6E0D793E966A8A7B755552F16D3A1146B0CC6D92C8C90E97D7EC8EEE7C365697F93AF257BE24691E41F2AD26BCF47D52A1B80F5BE1C658616537630088CB6E227B0EE6EB8DB2FEC0284E58202A73CF3AEC16BAEB59D2A6E0257F0ABDE5926D9A13D89A8B2F69695BA3682E87A77DE06FF54892F56581FB16991654F60EA22856D6FF9E0BE2C4837F0C1F6C54E840F67A75185F0DE9439AB1E37D4FB3E9757B0FBD17C89DF8568755567C390032DE93E9C93E6C89B2E66E9E9D96616919D9FB461F9F33"""), - TestUtils.hexDecode(""" -02dede66fc74f94ce000d6c4898fcf4464b834b848d2bb2d98d3a5862ec632dc9636201321c793ab26e4a42ae4f13debf105d087b112849946c76b54b801382b9727d65bc732a5620e8f4f158f0c1737b0e4ab8e7404383f76c848b36f58f5f9d70ba14a8ebf622bc848a9bc3e116fd7b2627c41ccaea47d493ebc6d3dd167f79fc6ededc36c809ac87e77ee1b006e96ccccafb88d965bc1cc15388e6410c68a74d72b6632487c284fbfc10135da29f29264cbb9ef620c2668066a2fa80fcf2132e93a29383e56c8bd89b3aaf8a905d4e60c6f8002132d38abc3d3c3b6fdc6cf508c8f6a7cfe9f78be8445f00a13414e41c27ba31efc46d0e028b778ca57b2326d624e3af6be0d4cb2a80e44b3f1b83bf572e8b7516b8e4715376e5da06bdb7d487d6a2d268afdf5654023ef4a13aaee221fdf7b9a668b2f4e1858da3c1ae3a7a7279163ca9c1407e8c0fb69f0ddf75cca64f4b0f277acf9c469dcce264b8f37f9918626dcb4252391526ccb4f068879809a2b115ca1d75d7a1ddbe5c8261531a98494ff634dff81515fe3ea4e289d75631ded8b8ada415f6438ada0738bdf9f89e986dee9c80d82ec13aabf10849dad939e81441fb063aa627c4e316461fff15e61c85821bdd55b2cd1545f810c1f280e7852604be73963b75e33eda2e2300196590b9b77cac44d059016c0b08a2f18f18ededd8dcb1474b3e088a6e84c12eb0470cef4b409214eb47de0e277de2665c661ae7766de5d05bc357a2db50ce51d9087a66b1d3715f5be97a9ac56ef866fc3bd3025738d4310e4761b57b3f901c5165df95385cf70f064a760b37341fe2c8466aca8258fe821308d8be08f4d569e27365dc4be8a2ee4e5e13f9d467d8b6ea272e407386e9f448c1758858d038c18f49dd7f60874cd4059b5950b8e969df6a2400a628759d6d7839488674bc128e947594521a998a7e9aac9d61ced0aa7629035bdcdde11a82ebdee6145af1f9c31ab104219beeb4f222e0f0e155e6b67160f09f6ab6943a589bc4ea4a1eb3231bea73f16da8998af58b8f71d3aab3e2fa736f3307180e6d777bc5ad02be4d7c718855177d7c1826bdf9f3848c1b9b65c6a25a93af48c728b6485ab765d36ebe3fc82104d043238867683169cf120dcdd016156283a7e6171167ed19996ac57e4691ca3f49b43b03aeba25fcb3d5d89cfde475eac580b58291084d8f7d554b463b3620a63bad5c1fdbbf98a5d8200f0e0ff1aefab7754e70e4d666e0b31ba193fbc70d4dfc601464a7642c56385abe64df8f377e2e7b7c451e903a13df6020d3cc7bd73fac7f95dccc9be71af4facc9edd60e9e5cc5c99bdee1339fdde03b3342a4c0635c71106dbcc4ca3ccaa8ae7e0b9ce740fd9a6fce8cd805937b3daf103c246d3bf61a10eea6af21bc42867e471991459ea895bd74d6899da56c22ba33294cce17b88b39691c493d7ca312776dffb953720f02fd814e6b9c96e4e4a9aa6e2d255735ada1d02ebdefdfcb74573c77b4b19f751f55e20a5229a22e326ac75858d7eb4c7fe9a4ed48dd49be353269223d3021365569da4c2cbc3dc6ac620056c5aa7382a363f93b894c0a4fb1af983d90d8127115837531e9ec7ade4a419051d503c1501afdab4d9b9b9a741810693e256e3f03415901ca0eb9eb74083d88d7a1db546c4436e3b19f3be3da87a6e4a7033d0cde55ebc2f7123b750475886244bb6444ea293fe498fb1e98d9ef7b31a86cf05cc660841f0b21a3ced89cffba8cc08112fb9c20a8abaf1e9eeb7fc7c678377ff2edd2e4c4d3140bfa4106f46a8b137c4d68985dbe4b8d67342f409f75a3027dc6a71acfdec2b723a4e1b96a12e42e49eeef5ca77a8961c77c39d5542d5be19511d6bd5364ae79cb254da944281ded04e1e06b7d4de33e40b1086de49543e56e5d7d4ad2e224f31337351707819f96d36db4d3a29018403556995a098cde94138f71cefad7d8dace8a6e08008b22aa5d257508cc4f6a9811f036e7715c67ac369b6d80c425c79a8ee97c094c93dc18771394a56dd527a676d660472b9fcac4fe783500676a9aa6b0322752a73ab982fb28e5eb4ae639033340b9ccc8ba036ef1164d293627c41e094bba0bd851480d2f91ed8ec8a1d4a229f4d08dc25b5b7dadbcdf22b2269cea9c7c6b886ba74bc156590e440a9a0e128a35ec8aec4eac360fd9bb61e9804dedfdbed1e17454394ddaf851c73327022da9456ba7c4edbfe7a0031458088f026830c3695c5d89a60810c2cb6543880b892d8d5c93214ef78d8e7538028419592df1f630144856ea1ef215ef6658c350a50e018cf0dba35fda2694e1efa93cca66931d9560d90bb434501f5f420b8bfa02a566126dc2bbc9f4e0fb929e2c42637de5e2e77e07659ee590fd3b8facbe7847b9400df4bcd858925c15cbf1a385fd395d50b9590c154928cd95798b735faa3acdb4a8874672041d585e45318ee942b3e36711dcc706bda76966cc0100f14014f9ea47ed9c924035e2138107f52dd26bc5d0312879505d7ddb3b468765086169e24a6e1919de2eb169acb18267fd0ab0c468da0ac6436acd2c4e08fb85f134e648a992a69cb871173675e87906f30e7cedca148c00ddae418e07e1aabb8f82f53127635e09cd898b348d4bc5c575cb6656d4bf33af7414bd26a84b5184b9be5e15c384902b1c66a6bf08b16172ed8084de06331119df75913d29ddf181de3bfb9de1242183ee797309ca14ebfd5f8ac368aa72ed7403fbddcac4077d669930d742240dbffc1a2b4a83b043d904285ebc0937c087c9025c0472a2b6e546b6629cddad4b9e60d64c01e0ed4d4bf8e580013e2b215d24893b3dd7629e71cd6c9f906205ac2a1572fece8a7d95adf21ae18f530a6bc18291f22e1b05349abf287d50f1f6724f01d0cb3fb7e0a576997c3cd9c013ddcae7071a7edf496605715568407f86ea78b20e66404676f2b34618060e180e4f9dbfd9a70a1f96acad53deca1db22d87342ad2eead7289c7e481d2068a74e62f9c9b90eb02aed47b57352b23009adc93787eaa74c7b8981525eb077fd502e6c476f6fade93b53c29cea27cb4a7594b55e4ca11b66f94ecd43187fc23d27bc72d0f48a23987fe95b06940a360e9026a022d2ee3a11eb72c8573eea76accc0fc2acfc61fd9e1655c77bd652a5dc40de7dd0182ff371d5a8d3047bd82a69a4b75452dd2f4409c5176b02488b9ce6e8b5c0173d96e1a83e5889ae16b4a07b09afd8f11b9b80f812c9ce794da70ce46cc3e31e24325f5358cc0c64deb9305941c0511ebbdc302c2e362123dc4bb4c9579c6ae2f692949e92a76f9aad182ab69549702421d94c5625904af24a42620f331b8ca6f8d6ce59306517ad93fd6d1fffbfbdd16f4f120540753a630c0f56b178b1672504d1cc0a20bef9d93c8777c036d881a42a72dfaeb14a1a0b60990a8c27f978c95ce44edd72e677d3be62dbd26b3c9bb1ccf1128f79aeb2a41f6ba6d021300f0ccc1ad36169bf63e36b6da9b3a9a6e54815d3445125a2d5078ec0eebd58df4487919fadd4977129aa61ac337f347b3adda82072d758925f4ce6a5125b9e4f87dfdc5cc4b3af5f9589a9cc4969afe7c6b99edd05462d1da3c40d785b8067c4c866a8579fbe4d94786e0fb0b717c6fb96e2e3ebd72b6901acf96c0fb174c272f3559898019a3d87ebd6d9ece260ec913300392b541a1efc0811c10af0671206345b46a588abc932f58be6149ae6591250a8740dde925cb9fa12150c9f8d191163ecb613418058769c54f883e9c0b533f6d8f568c6a907c227d16054af09c6c73676f5b9859beeb5a762ea323eb76853f4a3ecb113ebc42f9c99d89e5869777448a26c40407362a45730621c700e3710a65ef8a49d9c19a2692bbb37c1fb4573498126522468f738da44bbd4a719383582244a284645b318bf7de280d1b9b9829af334d24c49c50fad08a3c1c630a8e682ed700682998fe7b121bce47bbde010fbc9ab70494d5d0b300b846e8987efee9ce09cc1bfcd828f18ea2bc4f40440f89ed48cfb103a80e77e26967b7ec56740d18ee40bfc9fbc6ae8a0d7f46f3bc09b7dfcc590b55e3d8fec26e7f4dbd7806f550519ba3ad64c15b657fc726001b0644054aa24f9b1dad492dadbea8082b176c5fd819a8e73665751578e74ef32779127616a28ebca4be7270c195ac077fd71627faf95fd02f3b6dc45a9f47d3f666c318d752ae08c17d2385e810408d90fe0aaffea328466c5fa82958e840ea6b7ec4f2bc6980db0f3a86461f51cb55dc262ebad5f326533b6bbe0d9c4b283f564949f9cb05291ddd5371af7713a088fb9033bce4436d93190fa742dda242d725bb1fc261925efed8df4b6e3040b7e4989384a464752833f83a087ab09eb0d2be8320ffe552741a5a6b90ac91150fe3df65323ddbfee23f6237c623eb57a44f7dd67be498c97bce8a03dc2f695d0a41e270663a06c67819f4ba401a45886d78853efce02a00335cffa3b47c29b5341f43756fc5c180edb367aa43f104be106d233224623da7738147527e42a904f5a1fcf1d35261139752f9bc38dc992095ac84d03f889024bc8dc211a1b41979ddfe455f696b8199a2e5ecf61625293a6e8f9e36718e9097badaf37098ace700000000000000000000000000000000000000030711182024""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -02b250a84d15d015d65daf64921d441de7eaced5dae8d5ed5aaae0780710cc6f6478e91ececa60d2de17019195875bb3bcc202adda53a06e8b8faef1dbb67e391e8c8e7145908fbed14602f4cd5e8c5c5024cb3e65fcd88368454b7fbf8b08553c0abd7dea5834b8ac4da6968cf7d4e4a6771111de335b8a1ed45a18a20d7cd4e9eeaf18868950880600a531f49ab5a53deed6c37ea1c22fc0769d8a8ba5a3c49134a80a649b0435e457314c10b7cebe346a822a005b4adea250c449c4025db99c8cd8a3b44a3582e8fe2c1f37dc64503f90143a4f60df3a0e123917d68ea2bd0ed734718e38a306e64516e7a30eff69cb22956eb3fcfca07806ecd92d31ccb06d2db525118fc75973c04c3ded11f9425d2f89e3442e8a4393f469278cad14b61b6a7b15931d647a867f2753b69b22f3ec80dae692d7cc06bd82249da6e24570831ee4088b052687d8277385fdd1f88b4291db8736884928eb2a3fedc6b57e0a4c9db49962ba32d0b75b0c453e63a17a85932e18853bb860869a022dc48a96d6ceb1bb78d262ccafea8f05d61d4f9131efd3683e371c60781e36219ca5648cb69e65b11c2f2035f26827a123ba43e86de7f3f2d91f07f0bce7bb833634fe33d094b9c0ec790a8560e7475f9570fa638f104b67a7c0bfb8ca02df96596a4a7c41b5d192c44c9086e387f6a868b8600aac16fab9582c7db786d859348d66ed769ab476f69aed6513178d594e268d4a2edd29e684ff71aed82504281589da608904bcfc3e21ae7ebf53ae4acfbee19324cf10bd49803a2508cb0d80940840a9b8c0d7ccf651f134e03218b076d5ba213491163bcbf407e42dda28aed332d455395866e6d5e11c08f4b76b25844fe2a44c28b13299a0f924d6b541492977c6d779a06f8e7d19a145f70b42a55f4d200d6bc97e052ace5af0d2429d752046f25a8d51eb43c13faa172d4a9553d0ac05e6655c57be3f232329c97c97f7315016a80e6e1c79d12c269129fc89b9f859d298933d7b0128a69508c6ff454fbb56a502cb740acd4623b23382f3b3857d1bfb0776c3f1405271c551cca1b4083a8059d755f2a55c39c2ea836f8992a1f386800627f30fb3ab6998d3b644855a8ebe7c92f45accdb7ddbc2ab67932cc4e75b02c78fac8edb89d5e68cd9bce2187eae5f612e7e4e80ebb50fc63abacb76e0f317a299d72088253308f8c5c1b9772f064c90496aee1282a4e3a9de98ef74a2c3a4899d117376aa2f5ebac04eb83d57eb887ddb6419bb266c94578fec097ff2ec3f06230430b1fed1262992f0172ccabbce8979b5cd43c87c2cef2144270561c6823a9dbdbc408b81af10680f1c6939f7c8f2487418d7eb696f491957a4ba1a9a261eba8d234a958c7ea2766915a3d483019d83daf0b4e1e8059e81c3894c4280288179700b0eb984a401d80bc537e979d3a50543e6865eb5b73e4dc0ba55514f22c034cda20874124d95ef6df0eb7e37d7e425dc53d0b0b81d6a3b222b6c066af30e1fd6d04b732e4ea9be724bc115d49e0ec3db841db81d9e0405c5005b475a1ce6f84b8ae38019cf2c21fb9ba58a59e983b55aed4b758851dee4885127c5655a54e3a79eac74256c4928274147d61a4c6f1347f4e3f49fd25b154caf3db3cdf7f885bfdbeb24ffc02226569ce08127fb17701bd8ab0c792891d0433013bbd62a359852c5f90bafbab1ecfc0b74d6937320b9019a955c05d9e121eaf87d08c4f55068f3b2973a2f4d1cbbc74887654d6ef8ef201d2b0c90af205f15bb460c4a01808bdc27911342a476458504c01de66877b9acbd8c015e049e37fd1f90c0b4e50b54bd83db0f87011f5d56e85eb4cc75e9bfd9e92b739f833119590e409be30bc75adcacfd0e6f31555f86bfe4436b9230e519d0983da0138f31278e6b7ba165030855d433fef12032855ac24d7d8148a2ce54f3ed2996bfbaaeaab3595ec02bcfd0c77480e87252f2ba6874d713a61849d303794d940deb31c1306963111fcb6ae6e1db1715c1ad5b49b0ba4262abe8d7c8227ac428d51ab503d12caafbe0539711c956cb5a19adb5cef22bd1c52f8a297913403d8bde655af805e96d20f277fe873c463b0bb747342804a0e74657c6c14d53049f3e42eac9e945e50d771c7467774a755a2209a1182a7f7e5e131c61f792e4fd962e40d5cfcedb4add6eb476689c508ad8dfc5552d65c937e39018b151555d605075023598fc479dca05d227fdce3bff4e2583dc972d3cbeb3b2d6d2de7e6ec44c00ded46ca34b8358842d0415f7332bd032b933be3b758b7ef285354610c0abb9d05ad104d44fc8e057f6585c2a1844cccd3bc394b0e097ff09da8841ff7e3fe82aef8cb8af844e70a1cfba3d7b88cbe2a82a01f49c06d00a8a44ca2ddb0d8080faed34fd0da509e80361ab110170631d00ca8d5d8c85cf788f105aed5e2d90f870d47c07d08dc16db01440c671d1c7f880bba7a69a76c3bf64ead43c3b7f0477c5fa030f93286a2781b435778450b4e73572423671f4861419c8057a4d5672877970e9121fcfe6b51ec469a0f71b5c69718c54c3165041d177480d761152eb05e2c3cd49a063a25b05f5e75a597c840235fd599618d72f99f088086cbda1a2a655aa528df1d694afbb5e27f910449863c01cbec95a297c5f89ef2e67fd0064ee5fc2449098a43e2bf86c2943007ddf82708326d5fcbdd6e8a5821f9707b6a7a509e27306f8808f5c0bb85b8edad600f1bb4d58cb4b9cf6a74767f9ff52dc"""), - TestUtils.hexDecode(""" -320D1B2976A4A4673900C7B75B23EDBC25B9AE867FBB79B55B29B3780EAE8C159A3AFAA47CF1D9E452CAA8EDDA3304BBAC47EFDCF96CE92DB1981A5088F731E1EDA1EA5FDE9A031595A8F268E92B4D75793C6F408F79B78599D93E80066F8C4432911828A87EF71C877F55B1F18207F01820C0153B647205CA93DDD6B78B94EB59E3EAF01B66953951ABA4027F811877B0F60C9A5AE6281D82348E3EB749C82C81D53309F9B7E624BB1BFC6382F43A58D1951F7FB716C08DEDE4A8028B50544D0F26F7B9DAEA0CD075C3B11B7315022A37198F0C96D752798E0EF406875CE86C367079841F717261A2B6570A8F4F9BE1EA305E73BC8BBD88AB162B4D4BAE86CCCD406A0FF6ED5A968D4C985460FD8FBA5B3FB40E29B6ACA07F70717A0700AD3A0BB7081E09F7219F3F8829692C3DF91C90334DF9E89284D65F7406188C9A1EB7B5C491591A20EDA9399DA1AE8C0C158588FE1426B763FE9D11223FF7A05A3DE036B67541C2811AA459045CE73096F89E6BA672CA7A546D2B0554DB35C547AD9585D14485AA812BFBC88F7B248E03F2EC57043F4DEFC2B27A3B20C2EE7CE334D428EAEB228350A3ABF4628C2DCFA84BC7435818F91CD67F70F3C7D54E2C205E55BC4ACCDACB354470FD5C246F32A542106EEE0EDB38F01FF5C4B657C7C1A00718D2BFD311B8BAB6523351E93CCB44274B8F96EE343830148F5C8594818777C1E798EFB45AF1D2A75D22470B4D7F7C7A5938DF3F8288A0088719C4E36018D9993F9E69B8469E5F2ACF1977D441B82E5340E5AD5B21B66051513553BA1BA1C1D5F788C47CD3BC60079300F6E3D9F13EDAD4DF8521EDD022031A3D74A6A5F32AC6FC51C67F920233C5079A2B44BA7B8EC6DCF9AD4667BD26BD07567E078267A1BF44B15E68B71AD38226EDDF138D2A599944F70D47B26F775BB97D9966845AB3E6AEB96E1414D3BDE94160B6DF19E03BA1BD0361354E5078B3C5733B740314E2DCCCF8F4C9CB179DA62D5C982B223CCEF5F29D7B673680DFA2823A2BB279EA45D98CD91BE7D52E3E386B98B62DF3FAEDF025B55F49EE6FB5E8DFC9F70A4F093EE3898B25102CF3AA52E669D6EC69BF6C79457BBBB7CECF65B1E948DA808025A242841FEC6073326BE16C2D1953209F31BA4A772FF24BC30376EB994398D4177FFFBCF78C9A79B7F1746D077AD146514A2DE0AF9800255F3A11BA661765A7D8E8E7FE5FA46BCD1269E278555186D4BDDD03FEEB70BDFF7E5F616259ACE39969CABE8D4F8F23544918516C977F84C09D6A6749B1CE719676378E82F9B4E563D67AF7D911233F2527B5CC5D0733360CE15A173F10B91360A3CFB08EB44A09157559A0CE8B661AB4A97803C52F156627C642CD02CA5BBC7648833F2CD7E99D2A7AFB736E5AFC4FAE5DE19ACD2F5CE3E3FC887852758411E8C7FBCADB1578964445332113F963AF3E944286DC448471125E55A46D2DE35E9C0F6DD10A3BE4F1E4BDDE51A16F4239A1F6A535D3202055990606C0065C542297D490553204A6E3CA16A7FC9A1D77191E5C01C1507A332C659FD6B11FAE088BBA796F18886195A2B8F5B0064D85F56FB7256F0FE70E9C06ED18B7C8A75ED97A1DF482908D2E3E8D6BE8D0EC8020451C687D10F829257F3D09FC47C7EF008B89E2312792A25EEDC71E9835674CA50235E0A6C832E7BBAB458725EE7BF65D26A0501C91835625C330B0F8B4D46A0762F7773D2415A0DCA573B47EB8658F9EBFD26D9F6EAE9D7A7304BC690F8D2F60C33F8A7D19B52F9340BFCB2FFDC92A7F9ABF85E3352E46ED7591F354A9E19B70A3B247E3E4295E45B6A2CEB59B120B6758654BAAFED2120B226FA778FAE5350E756741093083E4E56A84B64739695C1C09EE39DEEF11D7E5BB7866C90FC9C96CEA071FF82F145592443BBCD6B7CE848839B641C4522016945F711E86152820275A6E16BDF296D34AB38CFF06A63756DAFF7BF230F024DA00C4128F025F091F4341620E0EA883042BE731E82D21DBA6EE737D90346B6189697CBF41F7C2BA7C9CBA20E14D26CA578FB05E92798D57C0060951BDDCA5D96322AF35D80013B48A79AB7684E1E1B040315A350DCF84389E54C054AC4C3428123E01C2FD66FBB2C5BE2D16B22BAB805AB59DF205B71764E4AC9BD4B2D872B8905DA230623C65DD235FEC253468E53928722D1F04C486B46E63FE63441F11B1E3617E9765D4F388D4A2B68B6C86C8E20FE0F3C48A561A0FF5070455C43A7FDAEB58ACFD4BF51A1C37B7751ED37BBC73B9C29DC4FAFD0A8F5FC98C7FF02B404AC08A0728FA82A5ADA4EDC195E679D88187F58004844065F281A67FF0A2BE0AF94D5C97ACFD43683AC721045FEF8C36DEBA2E3EFA248DA65837046B62BD6CCEA84CB1211C5893B0C5F0A5922A989CF7ED093D5D706657AA6E79EF3FAD0959DF594B9CFBE779"""), - TestUtils.hexDecode(""" -c344d3409be7db98ef0a349092d4bfa68e022cdf72abd10851fb824519086e7cb35ae13a93132867d90ce67d9c99315a3c548f7bed393d9eb71231bd9cfd951c53cf8a7555c2e8899d7914549a5565d8531685c7a02b82f3b95f38fcfe9c24118358f4dc4b0bad89c5e169e8f71e97e5f874bc8dea40c70e9fb2322131eced692b164c011d04844f0cf95a663a90e0409f2b36d8d936613343f6078751a082056d1c077fff3c3e0bbf5a9edac10d8ee0be319df29a998e5a52f06dfd12c47eaf72a457b18c73bce7931b74f28e2b3ca2037f0711b8a4755a860fd79bff06218b965a1e1368128e3db4401bf37185421d4b080e20a017f9695feb484b7a4ec6623cf5f82d99d1e0a3873d380cc5ba715021cc8b24f0839d10eb2b1679098330d772a081bcb20ba8613bad19841b411cb84e4f9bce9449b5d1b79922733e0acaaaf3c518d316c63a51ec49f4a5f30671df7b36e3996201fc625c91ec7cb621b54f98bce47381bc062be82eebbbd2196fc8fb1f26405a80a1cba591820c6b90f9374406c97020e0d8bbc4cf71d5379d54e3412f69d19b59237669e1751355c1721d097f07a218214428348ccbc0c954ea7029dc6aeb605ed6fa8334206e230c39ed5a836664a6c0b848de5c6a219a63ff24264ee44ee5d9f068a41cfe62cfbf885a2bb4c71f17863f5172b9b4203e9e9f21e0e744807277cabd3094d2727d78f930ba8779af85026e45b809b8b3ff259dd8511981e7955924bc29d448a5175c7742b7a1bd7db170c55a9831631267789adf7952fcba1391fc4eaacb7c3429f43a2b634553d8fe47ad9f39f81e54b0461061f6f67ab6b72a25e99801616737e8687c738b45a8ff6f05f6b5a30c8d87f6bb4e2d4aa82ecf9f7ff4d1a6d6b5ba61661e8a75d4dec3daa6ac96c0abf7ac09da08efe3eb73ec0de8ff231078bac1cf98ee9ac6aff210ce15f8cdabb143ec77860bb090463c0e6b63c0b12249633510404cbedad4eb85641630cd131a7897b46443008e79edbcfe471d37159a27a9622bdd6e34c1943e0b5ccf35d8885a9d584f6a54cfe7b1b45162360b573fc19055f6ac05df20662026072faa0f0fbdcf4f9b7d89d77fa0a3ca7ea0d857d0d9b94e95a406bc039799ed56e076114dd9f7c8c028c97e2bb813d8862da972b069d7c1e251487472c291baa0c0a9c9f349f29091d8a4332a56084e11296d1c72b7014045ee584056e9822b113136ca9fc27b1487f64e4fae57b31df3e6e2728fdeddb4437a8257af982cd08fff4c4e6e9aa82067182290da938b3b969e5ef0d15717f0c34130cc2d9bd29d9a4ea6707c9a45830c66a2598d8678581d9a389bfad0e34c3cf45c3596aa986380458c5cffc1dc06c5e143952a211288ef0d67c7375f0d9f59ef10a55623af7b6d2faae4802882d09cafc9da95e7e0254b147fdadd9b8b28498d625e9b0603c9e7e0a710d34134e6b4d2e31003ba30acb30df03a913851d5191adde83fb0278aec64262de99b7ccb1c6ad5358651f336083f59089beb924db5af90be237520b5354ba63393c2514f2f5c815b694258cbd56cb7caa5de34986f214c566305163782b9a67db2f1e51c0172f757e3c8d9804cefb63df98d4297555aa95781e8c1114d5c53b06491b2c4463790030d2d28d159c071c081286071d95cf5fc624b69eda6b2cee5d84ba30ee0b4357eaf5429c26fbcc455357de8730f0b50aca059334ac5af33c7169208be3b060abad80a41d5a720e262075442b1f514958120dfd51927363fb0b43767f3bf4ba7bd2669f79d9ae38c8b244c9a1334f802e7295c1a5b2d236edb5ef8eab028dd2bd8fec9f0ded1dced5a352f55f4b502f5aa12a3131bccbc88a2dfe990cf2cef02ae787db30e8bfe26079bed383e363576ee704e2b2b3b6dc0254ed4039bd0155fafa471919703f632bd8623350cefdcdad074337d5ea637a95f995141b21fef74b93be8fa18ada82dca3bb6ebbca0544d790ca07c42086bc4908a4dfded5d0c09e8c8d4382dd30fd6c586d5c379fdfb11f69faef1dbf46b0b03432c0b9967e6c7417b2488aa22682c5ee0fe6a08e90d6740af02f131c5acb53fed64329f8f108f53d762736519923ab734654f968783dfe8d13d715e9db219ab7441fcb739fc75913b20334155dafe6b85f28512d71a02e463e8f58162a2075d301d4215c61164b5143f096decc998b006051752431e1d1d7d109f92c986c40d2a8f17ce6fe1c32c33631974e47c73b5512697f5e3fcafcab2a4f8b462685fcd5c19decaea96d45a7c3d35eb6b81d52d3d300f4f94f2f831e3412b12429b71b46253c83d849250072c035003b8f4c0c7376e502183848ab14ed9f8b6ed1c87d554223fba1bc99d1d065cbb945de8968fe41c161c301b3cfb9c181ef3bbc120cbef645da02c295d6ed66925802868bc8ac6b437550637e5a16d429dfa4b124c1f1045174507f706d3c01f9343ec58bf79e5611109530e2543ddfaa2fc0641c69ec8f3947b4350bef318a55998fbc25686a5e115c35db12a12e77c8dd43863c2c024745410a0fcf1560f1a902bacc961d931f793238684944140150a99f2894748d03a83e030ca52fd83fe43bb9b7fe43a9451f3850f92df5e242a1e75c3a101efa727667ac45164c35fe7143b4ca2119d76980506e8981c4990c8f391a0c9416647554db2c46256f3e56963bd4f7ef309914dedbd893fc6855caccaee377d70cdd54c64ccc3e3d1c0e197684fc692e9d64be1b07af246bf6d2e4f38d2e8844e01efdac0b24dfbaf32f08492a99b38486a8db4661dac565fd847d83993cefa810c42cabd357b3b1d5669afb73274be28d637d8c2de41305c33ea3569f865834effe4ba3cced51fa00ea3dd7f442894bb2ef9a92378ea447fa6af9ab8b3fc01ac45c7221981471aa121d59e77a1d472906c437004ebbb168cca7f518145494516b1d3a1aaec164e5f73a96c244afe367943eca32c4e61bb5766122f1f19e9768c4eec5d76f3b10376191c5d42005a99eef0fe332cf5cfd4ba59f725bd50916348b5704943cd5d14bfa826630a9529744148d9ebac15a84cbf6490be826ea51fd42e505fe9e74a13ec9a1ad546c8c22e8d498ee7a0dd75387240c3d166fcce4d957fdaa53d0573ed995a229e2744bd8493d44d774910625310b4edb8e46ae665c40599c7b48058f104199ea6ce1070a37fcb383ce4e2af436185c4a3f20e186a25b8dbf4dfbad8304125e186eb76b6f6ceb7fdc51ed324272945e44b0bf11ce27b5b6b683fb4efb7e168ff13e46f1f0f4a136827d8d56cc6fed0a9fc8a2abc8f5c06d1dc0de33042c5b840c6d66a8f27331645a87fa6710f9f057685fe00247cb7f12b229a43f539f9c4a6727a8897c69d8ade9c2af6538c594699a9f428a998bc1e8d11adacba134649315ad51f73c1bdc11d8e5eaca86a138ad934b30b376d754bafb3fca13963eb800818592eca6807867d9bd23ec931a343776da195c8d43830028cf4328701faf124a19beaa44293e797c2bb89b2c9db45c7d3785a0cf5c9fc783d727da3a3f20f5366d9f39bf49bd1ef9811dcd74804716f82c0afe9a73c88138bb23babcf5b7acc87f5dbdc0ce1e39540a5e5979ced0aacc221362e2a18a4af86f34f9b2c03a21dd21f70ffd443be4bab058acac295aebc452b4fd32ea5750f4a2fe6260c30eea5bff0fa17f25c3dabe3b58fa72f75cbfc18a84e2ea3d568cf6e66e401ec82753652f44e9410bbc435721a10da1eec613e71f04023f3121df6b45316795f110c81ec9124b9a5568c08041eef364ee59b4eed261f3edd834741845ece57fc5ad1f50d183d03c0aadd61eddb2f13c46093082182b21d4bc5832081fee8c81c1d9a77f132e8e5e9f5a94650222dbe47f5d7f846b1e91d52f62609cf0420446b55ae4a96c2bafdab6a8793beedf7a7ee9f678a099996b6d6f8221427fc86e1a260d7426ebbfd7b9f3e0b9029907b00cf77409b24f73b7f21fd2030cdd4e36fc09322ff6176f49b6f3492076eb9de2d79f41316a202994871bf7ff96ab0cf94ea11ab959ebb4fbdef3813698b1c78e13f2422efa15198dba6af17ca9b2ad199f133076f9ffbe8496fd28e003575579d6f62c69a237c588ea8bbac99b32c43393b20112779db5f9989c04e9530af29a7cd959fa4eb1276c69d46a67ebe363d635aebe19452416e01db478ab32a32c6e95d43ed4693d51f4ded754c62f53524d4179dd05a102acb6e7057c63aba9c8664d9140f866a359f755ca2bb4b0e66b3794206bfb311535810a24a6256a8c0c79c4a87a8fd40bcb9bc23321fed6cef599deffa6994cad1bdb655eaf85d082cc1c626727918e63eb27521b6de4ef5857a2ea372f64409d4c6885d7eedc15c95aea623bf081991890b8d5673cc9ca26483d6b7bb88fa61b31a13f114923e7332eb2a52b9c42b7b341ac6495d1c4fe01f627350089daa8de8cb8b4c660ec9bb065ce689d965e14488e67976502337f1de27d825cb3e6f563312f1a3467e1d2b2628b5a3ebe401b6533f549263babe79b0ec66132bbde277a1b4b8d913b1c378e864d3c56820b6de08e3462882e72573e8ae08c64861669ab8e92b575c6e7fd5db3a698895d8dfef064b5fbfdef1f411373a788082a2bd0000000000000000000000000000000000000000060d141b1d23""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -2bd5cb469bc4c91a3b3064b58eac4e6e03a617650702c0d2d7a74874743bd42c097727845d5a69c2146cf89053741be3476ad6a7d574fa59f868e30f5d4d1f78157b0db9753ed7e6687383c367d9168806c52d5ee1cd548c65449576ca155cd2668aac7faa7a692f3660832c4e3d65ca6e31b1fd5f7a1ecdf76d4eee120d353e683b67760c52ddeb28c967c5a99cfea6a74a1bbbf468d8a6ec400253b81c6780292965478d5b1d90c37bb6a42cffc2d086d2bb03845e9f1f1d09b0bdd27a9c0495b9a86a4d0535d84c3c2748c7345090c2cb6d4fd1dd330bfe860d1f666567e0e164602073d427c293046ecc8d62d50fea16458e7cc18dfdcc76a01dfdf5a8dfef558c94e6200f65220f67d5831809b2c17911778ee60e724b9cb8cf7d54f3fc8717b2067c17926c69d7d05830ccb3d3d3ef910b622a95127e0b017eef9bb43823f977e904c7fcac76aa44b08ebae23f8898409db11fc2697225d06ea646fe78afe6c6c5861f361f15bc3008aa194250b3d2d14232535bc612afb523d4967370021ea8b6e4a8406b4e933c6f96c244eb363b38b65c35a3ae906051d2980f98483653c03a8e36490bd8d5bb80608eeca2ee9e8e570262ad2e0c77850eb8bdd1099de5aef34aacccdff2c152c3cbbcba38980f227d76d563b6ab1b8f62892e51d24dc2e648160f4cee0b095f9d9bd406ab0f1dc4ba9706611d9b5eac5fab8e246e2686b3ee96bfe4ddaeb26d0b1accde64707406572898cb41ecbf927794e422fffed966a0247a76dcf13d61c3fd256773ac41466befc8aad6f6c26d7a63d0f51efd63fe12274e0952c0047af384e7ce9bf7d7cfd329dbd9bce351290f9ec015cf784f49fc31648147bb46bc9bdd59418f998eb36636d82c5f6acd769ac965a04119aeddcb199f055ec3770c19329926830226d12a990057a2c60d4fccfd4fb20350b54ac2e7b3822cb6a81b0c2928a95c37ad33fc7760018c1a09c50b5e0ae0ac0fb0f89b3224b5c21adb473df9a1aaa9a338256b54cc5eaf2883bd282ff8c406aab2b67575fa1f6039d59bcdadcf4306f1e6b3f28e843205033101f7839b63b067fc1bb727ea98f9d2d30e874d2f825c1115a6b24623e0526246d9a4b8e8436231a9c815df3689596fead6c7bba5e739ae08b59be3c01241e73c1a7a2f9f0cf3feed564f1a2d5f045bc550707c52b367bded98e00d91190830024c28a3fa944edbbd4f292dddab123fadc3b14166e55c8eccfab9fcad135acb7bab9d00510d422232d5eef19ce46d742be4c2fe83cf6143028b8e0bb0aa4660564df0d717afb305638553170116ca5622e73fd7f92ec1a5a702ba0e26b0e1980c4eb38faa56ea64711e0e2a141e9e4062e6bc9bfcc387b100677a9deb0999fbc064a997b3a0c809b11456433ae9220ba1b0f4029fe4da9be24e66124e48f9edc05e9e86656fb7b1033cced41d50a0055be663e9bbb8a5d161b78226ecde3d7cb6e5b1995631cecac52be9c8986c0b22e3e8dcaf108d09ef484c579c6a207598aab00446b0bc847ca42e155b730570c365033498f0105023ca8859421aa3b43b37210eda50ac4d9ccc6aa69580fbec6d775aa2d31d6f97d3a079e0a164b5b5d48b5bbfd7ed8eceeee109e051f357f658bb41623120fc116bb202154def1bc1c11fa9956ac89ac065329d00dd0390e2611d244377a7b2aef7f00911fa3a464f68c88fe01e1dd5ed2743c11802af5a531f0956ca860f02009fb4dcb3034af02c905147038e3cfdbe401ba8998a91be1e119f9b1c674846bcb10c6c294ab4ba9e8732a01c1b8a0691753299c7ebc20e888e232cb56842aa9cb232dd585d52a1a46e7537a4fb271adf102b87e65a7694198ddbec6a697237a06091c81d33159a9b1b09af04fbbf368d6b44fe6ff7948977d339883821132959cf9f4c7b01eaa18c7bc0c38ef87e5c782e2f5de44316490e4c94621fb6a967241c49307d1356a7770eb5d0489e4631a159e4559516e0ff342bc093d2bc3bb4c4fd27ce3d21bbbc906c12c8060d11202de3ab3cbff4488676531bad3bde099adb4b547b8e916ea61565b6986325c7f2fd8649d79f42ed035104ceaea3afe21caeff7941a5ab5728c070ab717b675dd9ef985cfc0a9103d89ce52822aa532429bd612a0c13f65d24cfd27ede804411f81665fa13e08f9a1e39efa23821f2d21209bd02a05a41e6b5a9847becd791978fc3d90b78c57b5eb693548104f959822a78c097cbd1c12a09bc175ef97ae954c738588590517f6a7afda7732d2864845316d17121ce00e889843b76fc250b3c865e4509b1811cfdbeb619f21f6579ee26ea37e35198e59d416841876785cf967ca9d17ae1e31688035eca51859296ba364c8bb88f28580a75e195c00a036c8ccdb6f13beb393f4f5430479516c98efae15f2124a46a6b506830e50a8e37ee6e64a6722d659eea4a52d2d6def30d6387fe820ca189ce3c3ba7f45b0eec9fda6c18448cf33ec43906d6bcf98e20045c7b30967b6b28c988ec7e9aee979f0a310046a48641f982a7d9997c7f0bbe386f05458ba7dbf49647708ef232b3ac57fafd418bcef724ed3bbc9f540f2a186df0187b1e49bb0853acdf9dd18b95331ec1d5628a51c352a0f10b63ef512fdb150c63d6531b0811d9a4f071c76446b3aeba7fd2f0fc301e5f56fe5386ecf5c1759530a88e642b4b45ff7b67d7d3a234532890ccd8803a851adee2aeb35f6b4de938da6b8bc76668739a63da699a9b731bdd5a8b2f"""), - TestUtils.hexDecode(""" -C9ED9B897C34D7119115A0758332FE70D4A9E11FFB2D6A800AAE33F85FAC59E715AAD93BD79DC8D958079F3B5C2422F8FD1A1AF9406E8DA3297226440E30183051FC9AA52AFB8BEEA2228E88D193F231F2422977DDABE4AF4F0437628C6AFBE68F70CF4F56153A2691F7A4241EDCA760D4B3AE0A17A8A0214BF1BA65221DE64647AC6578F4C7E4A14C401F7DCC30A10A695A7F72B04393F4E9C4163AB68667B1757154BFE711BB54255F4DAA9D8AE6622C71EC8ACE5BB79C6B4C8AAF1B0A0099EBBD07B292CD7B55E44ECD68DFFF4173743145B71F536E7D23E78C63679FA2F3C72CAADEFD5A9471280CDD3DD8DB83F8AFF14FBEFDC8C5969B050D263EA462C28CA64362F7F165C3EF427FE5E90A83310DCB07C9612E9A0B8EA1D0631D84B4A7F1C7485B0C91C3B7BBB0EC98D353376B692BAAF24C5389D50250F3BBA82173DCDB52382176EC5CB8BD531DEA049C5B815D788491608FFA2AE8BF486849810AD89BF0352ED595E4EDBC0B81467D72944AB83C3CB2F90FCD10810EB65BDA18C43F9A9A5D98E714BE992B7DA02E9F7C389F1A22810DC0A473F8891C43932E0F6B5D3A21C3B611AF6C394AFC576C07572DC4A1E56B4576FE615E516F48544D099683EAA886CD41DA848567F70C2103C467D271919CC5935605C0EF05909635D431571E5A316E299E553EAAFE9C7CBF5063E2057D297F60B5DE1C17AF6B97192E840474CB7266A76D509A10FC7A71721D705A9DAAC5BAD8A52290C1D8DC7938663B24700F992FAB008CCB3801258245A0F5F329A4FE5553F4130DFB1D673338889B357FBF11681099FE9BFF18AEEBB31DAD290C1401D49CBBE38277AAC8A99C8BE4E6EDD8A0F3C901082A789A1037768AB7C3C704BF1C6E890D20B3DB6918C477350F4F25756BE1742DCB31705EA9DC975DE0C38C21D29B340C63438268F6CC399BD644EDCED36A7B50E8D65A507BEC51A31BD136525F4E7AFC1EF9E0E6325D032682EB4AFB7FB22F1716EC6F4C9852054429B5C5FAF3BC86213F6D800281913D5722F3A380307B59E1CC290EE66FB9699FFC627770B52619256C7B76D993FB4024D2DF0602F102A6A1257A200DE1F39DB54614FEC2B60F3728F59482D71C7E5BEC36F0D90D6FB0B4FA252E7FEC4F0FB9EF539257EFE87715ABEC75B2A5FCCBCFA5666F1C9BE2F0489E04E63ACBBB239EA8397FA2EC24C25C538BBBFEB74EB8E15FF93B0FEDB7F36FF67F7CB244CAA067EB2C005EDD2AC9E0765DD38E51E7C71AB72B056B230ECAA8985DCDB50439BA261A0DE57E68700C64655E1EB8608BCCC33480ECFFF1BB75D0AB69CEEA8F2E3E9515331A1EAAFB9BA32AF62798DF761267475DE343CFCF5A352C907A0314365B8CF6FD2E72F2142018C4BBCE4CF0A160266DE320EBBA359344A60D32CB135F5FF943173A3F9C7F4A68489E78621401425E5B8E6273309FA3313DCBF13D7C69B63C1EE34D3200BBB4CF57518A5E66D010984AAF34CA9B7DDC914A3AFB514FA1B9D3FCDF3324998D0D9058FEF10C30ED6B381C41DE363CB31C5107E7C00D4C0CCE485DBB4CD2092CD929E5717DB8CEE4790A48475E1DE9178E49B13C5173B6F301D5B7BFF1A9F8B3807A5FC84DCAFCCD8D585B77014EE285074E64448589A738F1323C7A865C3DD482499640A3F166F38E37C6F9ABA8263E4F3D1C2E7D7AFD16BB02B9B4BE8A055452071F278C32C3247DE2BF83A0633BABE7FA048BB18FDBA27022736615"""), - TestUtils.hexDecode(""" -6d9ffac759de540cb67a1d3ed0e50afaee62c1bdeae34e94e8c88d8fa0a86e22b911655d83e0197987aa1151adbb629f7d130a143a3c0f34ea817898a86d76f54ec5fbcf4d0ddc93ce671516be812b1eaa2fe2da29d0381d9d5cb8e702c038b8b8e51d3ae18d0837fe459be7cf6e4967233344749fea70a74f143fde0a0a9582366710648c4f1b26152ca0b56bb6bbb6011264960f9639ed7239881337eaaefd07908359dbbea6dca1834f03a753dc02ebf67371af2ae1a82183f654fe20ce6212eea1aa256b8c1366b4d13ed800e116365e8f3277eb522f2793812329e730f56f6af17cfde3273045aae0ec8188cb956a0058dce1c4d481ffb1e114405fab0a5e9a70af8d438a2a266d9a93332e621231c4ca1d2aa02e417a327a6feda50ac402263e797fea04579ff60b9f026bf7a97fc3378790e3dbc9e7b6cc12d1c01813367647bdd5f8b867c9e1b2d05c870b5935e5f19772fcde0d8116a9ca9d84cd340ed26adc1033a8615ddcd29f86659f3e742e7c08cbf197e4c2f680547099b364fc67b8140a22eff4119906322ea1badd4af4bd008bc46d335569052cf26520938e417c8a8a12c72cf0a451ae2f209532e214bfaffe20414b4243d9351093215ec3ea78a5689e4f89397c7d309abc54d55d3dbee907ebcc6a8ef921ad61c67c2094081d901ba8631745ca131a302fa813c7137c1f3fd66207ae753d0eafb1211ca4e0d247182b3155e12a42e1cce1c415f74677928f7db645889ea70928679c7fdc7e36e43231ec831a6a6b6241bf54466bf530553c268cf5d63b22d755fe9d341b0ac7ab830a303d3f74acbba37de4c109a63a6457e9f79955232e368e9b4aaf27c6c5d3984e7acbb9d19d4cce1b8d53a04d7e137811f10ce33ea05a0b25f0f5ad1499e39542a264ea0830cc2b20646c170495e71a428d35ce3b726ccbfa1499ea716df3a01186e776586d431b90978be9536e5587555aba18ac6f7aa3bd44867d85b6fe9727496d6e0c8e8e776cfe346c5546bd262d30492cb480040c42aaed646969120db4dcf7c3adc8a4e469680e1d5d1092594436655355631bf037a3cd4b9dada49c259e0c6998d466d6f3df582bf86cecb7f4c874f392806cb1dd3b08d3759792875a08d589cd8f8dd8bcb533accfe23001773d6b9ac4dd6686b4ec3ef8cf4335f70d86bd155e5e473666c3ab5b27f069616c6d87f3969a55a80e59825840feb3c82816ca0e7c544eae787ced30e7e5d0b911273909ac11c5f0407848a96fe139887569491fc82b02e70134a1325956e65f02cd97254d4f469455f5ddadb32d99b851020ffdebfec3c83fe99ac4143bc4de6e2341948494dbff83f13603bac25fc5801cd694eefa4439afc61ed048a811b355b75ca4f7f7cbe88debd671657bde2840e95032129f2f40fcdfd160a13c7c123fbc811a7759e86f914288b417a6051393fb564a8a2473c3cd5216b31848cae14dd935b79647aeb287a262a59d37da18b085a86745b2090a83b6796203baded78332e5a76ae6d8920473d268230c00a442af276d11c5179e0b776719f02f4d380861ef73ef946dd03cedc6b7e19c812cf6367d6fb847f0f00b0ae2d5296122bf26553bff501afe0d217628dd44a8a39b509fd5a50c2b991d70eaed000d85343135c8e1f9a4bc703559e08da575ce134e07a33e3f3214d75f959c85e28329aa2242d8dc69b12ea2c95be537b8d1de119a7ce7d7a672c7172bb7f9a5df91ed8e10adb5ca072a493f4199f1135ac519484678681bbc88135a766490f99c2b3d4c6951d3e5da5e169b908a60ea803227fb870510c1963196712d0283102d6883b9164d9c30f9853a799696d488ad8834b6903602d14565faf6be82e911ea41d2cdefafa2506b28f1ee5a77eaa115b91e1ab44b7123ec70114d0c4a13846bb046bfcbfea6097220fa91d1e0605017f3849f9e2be6507fa4b7bd4239ed56961e70bef8daec13fb486d458c7186b99adcc45ddddb818e4947c0e6c5eeada18f564bc664f51efac7a8f12a259956ffb2165f450d728ed5a3c9b4cd6dfeb2f90a7711620374a66510fb3c2b3fc316e15e52a5f91d3e38b3313b7f9b5a80b6b181e4c4fc036ea2574d219f179bc1afa98fc918e33a52cfbc95e20c09b4140367c978532e6be246c8cd1d2c5508721eb298db406a92e77d833bfa7c5865c997b402cd8c09df2c5668cb38b03eb0e86da9707853b20f1ab23e11b6d38421ec2d6882a9121b847f55923601914a11650f02f99895f9920e1df904c6f45715a4c0d7218933149297191f72eab16eafb816d5dc1f59c30a249b8545e6947ad81d5b8f562f42c016ad46f19f5ba10fbfd2a1c22974669c376f496519525bc7ffdd937da7845efd848aa2431344c7314d6eeaed5610ed1ff144794091ffdae46c31fa9e7116aed7dc93c4765b9b72e021b825107e248b988d11aad8a9d466b4b109ffb874f26d6d7f1a12dfcaba5093d60179d1cfd2b435cdac23f6b64cfddd536c55354aaf6a76d738bfc12ccb003a14d19b54e6ddba35dedfd5e4f7f8a18dbdb4d7a8b34acfa4ec462b9a9ac8fa962ae9bfe353ba9ee19d576a320e0f9e22347a84fcf58c0ad61429f9a5f22809b72e91574052534e96832a99db4fe9e22e20dc2ea8f5cc4cb70c844ca9a0334f92ee2703b58b2b09e77c71e27851824c78bf3f4d177237b212f73d6681c6bcc29f12116bae1a25666035313ea2af3e4e98af8f6cac0236c392c39516b610234304b4e4d1d02d8d8e349dd00db7b8acbcaa4c79aa99f711ba693c7e93c9a71342453add96a124e3d06e46c503425a311bc5249034ce01fcda3c5809de83a87d4eeca01b26f92d9ea61616fb5383918e87522bb636110aec1d2b43afdb4258a51f06ce0af14a8687276d67033d922026dd190346844df0974280d56c22fc76fca0132615d1d61bed3facb80f8ccf45ab82121ac3cdd34c425f0efc86e1546f35cf470bacc1976e8c8561b086c52dc71d9fca01223707341c9af7ea6791bb08c2d46a578ba479fd36a2ce79558387afe1375090a53aeb2183294e747043eff104374f6f247591860028a49ee51c5327007d08bda15dfe2de5109683f0c10b620e455d265411a460c3474c3c2c9de9e72356bdbd7309b6e6dd2fd9260131b595630932f46c372a3da2563f31fe5dbe9faac52abd5c842eb8eaade71500f235fe806fd906ae53a2b65a906dda24b3839a0492b206687931dedcf96c57f05c28bd3e1e97731523ee0bfb74cd9367676f142f73d861b070843e772fa18a80dd641f430236a96b294c68ec871f957e4f04546a0610b727b4bc9d46433434e43e9d6c0421997701c5464fd62d7f73768f92645b251151bbc11a9a968b863a2a25de9b1bf547cc6857bb65c3fdc38268b9a89d8a4e49f1c62190812148e2c2617a92ee7003a3de676129e1f6b92b81081f1be2d9715bb83c31fd3136c80a0b23b902a9a3e5f9383b1206d2d8638fb0a5e5c0e2df646235b6a40b5f4f2bc4a13041f44850bb8cb1ef1d525f2ced545246b830547136c8fcfe69c86d4846391d1b8d78a63f50a09ca62ba8c1578eb7ba182ed67975889ad92458caeddd358dbeedaa34e160051b2346ba269003fccc4c3f58d511bc74949b152ae37ef64d0ab0560b8c474d3a1f78b04de729c9f0c4ad7ad2812f037195c85f3d3130559a336610541de8dbce1c91ff95b4d73ca6e4f4023378a5e4e49c8a907cf89b3b71ebc5729b783764a8b9f998e5a299c877cad7bcfd34252ca87de197343c01249c205ec4057912afd681c5062897c79b272c9977af12ae543570f2d8c4977684a2689c627ea4f97a8dd9600a17b6bc10a71a9cae8b18737e3d4e070402d8925d8c81d49854806528d5b03fb90a4a01c03cde8213522cc3372e49fb12adede707ac55eeef0c72a1ce7793925ea6416728a2afd328d2241091049beea09b93158c0835f9e28d0fe34ad0e6cc4cd82651b3c9524e50b6e6e509fba04dcd311b679dc7c82d96490b2f3f7c48604860afd25d38786d7adee7dda54acdef35bf58c2fa5bb0c226b535a9f6230c9428175ddc939fbe2f2191adf27a496644d1004c05c06e4a2e8b82a1910665062c10e6fbcb6d4e49df3e6d17b02cb891f89070288c94ce4faff7709cf88994af70a256059e6bc4df8e2769f9d2871aaecd023d11b44c7ccb0b0f40f4bca202dfb1db1890c89c4121c3a221ca70592742c1c624f9c54ffa3ddcfdd40864836184cfb075417f28a6d5dd5ba9eb4fa2a5fed82c86900dc96aca2342d29dd7208270bd4d6ebeba516fa6d8809eef26e6e929853df5b7b22a66628d9a728170da4a4eda26af530fa05778698e85f02d979a76706b2daa3d154db0872ea5c8b06ca7235305b1d5c1021b0334dc8df6b267760e652a0e1a1fcbd0039d6f585879c7b53a2dd3f664e36fca174322e93989f78ec66ecb613b0a694f13fe2715a930b2ac5cc4ee65a120c3c309b97b8e1ff856857cd88c0ba77aa5557f4184002fb96b35f367bb62502fd6fedea2df3ddb6f4015b018fc00ee6a79ab78c25aacfef26b1d5b1fbcd372b296f320c3cbd02128827678f54ff94c2c5a677193999eb2c1d7f7080b1d4667828e292f373b47696f7b91aaccd4e9ebfb020a58acf20a39586173da2d737583d10000000000000b1221262c31""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -c80f02072f243218956d3770dfa0eee288f8b5372ccff67c93318ebecefcfbdf44eb324573f1e7cab8f0bf2c46e14121dfa84a543892c7c90dfd5a6e2d9e97ebbe6fcac50f96b1471833441ea67805670c91d070814d14ed96d43d8478aff217c5045047e832a55914de5c621ce927144a790873ad5bf955e6b84650b6dbd479fd99ff33fbd0b58a9d057cd6ca317cc9e47a830badf04377d34768ab32b7316f2fd1e40b3a413370c0d64b360f3f46f447e9d3bd66a5207c73415add021ad7a32c0229f1b12d70f4b4bc545e8f56610ed11db236a139ff2eab8d38c2c39f258a94d52c3c947f0a3cf7acc0be3b0bed7d63f046644f28ff966c4f40d499c9350d74a81f76248603fce5692a0db585ed18c2d0791baf6eae4e932e2476e56f7b59c73acb881279ed46adb0116820456d9f4cc2fcd5c0b6bed1f1d1f5a83af213dbd244a10c1e3965526261481c4512df81faaad7f730052ee184841140f0f2002671f4031412a31117fcdf55534435fe123dcd0374e331d2136bada30418330d67b747ee45ba7b47b917257db42023048219635d07694064b5bb4b47e4a3950c50d15ef318eb4fc532ff7a2a455dbacdf04a3389b2d11e403247c84a6cb66cf9d2441ef0c453aac1d69f45be2291d4870dd91345b516d0243c4a76956a6880df06f9b527b32b6b05b0acf884a58b4ab42b4d4f92bafaa3d2c2bf9fbf6fd4804f884ce38c6f4501318a3efa1b0f9f7dee7d573a86e3108e3ce93f69bd35888cd0f0f98d3eb11c7571cad0573db31a692f09189eb5020d52196aac39a621380679a246868554e9f6b85eac016c1fc0847784ab92ce22c3a033892c09a834f68f03275d7b4e5980fdb51098d3fbb951e7599600e36f760d202f7f76f9f61a6e04a974b08fe2e6c2fafde4ee15d97d7c0c6e049ee9f66a4fc4e11fc65f29c91e31fb63a667dfc3b6445b56e7cad1aa237c56b16b6cf6d82349fe3dfb9eeceb332f97cb6fead2c791c846275e389835db39abd041ec91726b93a81bf3c45b948ca8dab2f98773b33f9e1ee1bf8bb0971c3dd10f2eeafd84f391f3fcbc481a3f6b87efb5756ca9699aae68f6effaa27b5c78a43b5c64411c7923937e7e03b0c9a39c125d268106e2fd2fcc1cdcf6f37e02a0848b46f169d65a184213f7d65026c57ba242a093c6f651cb7bd47d4adc50cab9ed9e9aec5da84210c7671e0df9a620fa27c43e44f3e0f8a1e143eb6fc1c120c4da0e30bf9de21f0a973e796ec08fb4d01976d9996af6c8bfa33400978ad16810faa80723b4e3748734891ae6e590eb411dd291efc808cadc857f64cbcf7e5f66f1a0fe7a687e1c83228722f3d111dfe2f9b0d992ce32795d3ad43f3022cb635234d7dd36320bb6dbb5289a03dd9e7a68febe91e6076e19eb979601199bdcd0239bfc9cfa43958a05c7f3185564cc457a088d0b02ee953e7c665e2eb53d709cda597d0fbe25f7538611086a5f42e1b8756906eadc43ec6bdc3d813b5e3e08fa7f8d9ee200bc098a16b5e5c382f500b45232dbff31a632b5fbb846b65a5a2829b4692b192569206ddd0d8b972e5273166919915c7bc77d5225aa75132bc115da4399b05009c258539f514005603c34e83d1a7ec6b277354d7128f09c5c05250d4d4567a7299bcc30e2a4475ca3a476cb61e2f994bc481c30d24bb11139ba0aebaa4dc48a229f3e6abf570ac3794c1117eb9b1fc682ecba28224274f63baf26bf1fb25be6120871958e81ab6e27594e15bbb06bbdd5b05d727f9e31328c7e60d5a069cf22eac5d4d617f3be9ad78e78b10c37b4ff083085230e23f8a57c4eddf6930bdfcb9484759310d62c4ed02cca6ba7fc3f5ebb23b65dffef3c1d5d020570865f7d2e13dc090c8aea4f6f02f666abc01d2b17623fd5c9bada469ef4b70f74011e494eb040357acf588aa2cfbb3ebdc4d0c087d7692c4c39be0bda4894c834dfbc11083586a641133ddbdf87a1078a73b4187f75cafeeafeb674a64b83cedf3a2d65e9a494a6c01df470c5b46f3581c36462301c9ae910daf7a8309d95f39e630f8f53ac368f51c7fd77dec9cd73069b392cc5929269c0a2eb82bd29e8952a27e03ac427498b6310fa2e93517b1388d125330a9ec3431b95f1f724bc6711b3e9b7cc111ee39a485281adb05d422f0833d6cdd5a9ba3f8b29796a8706024ab87f8f46e459bd6e8db00346d356d8d9ab9b7ec821fc8d962c5373f146243036e3c859972985f574874094a3f76cd925375485113778c4b4905bf8a50268781b96acf0539baf9d2a05d75ea81142198feb5fe2743783c83a8c80b77eda68e353d18cbc07894c460bca8f1cf96eb73cf39a300c9ac13dae0995423f19ee40665d6277014b9266919455bc2a1a7f3589c426593ba3138cf7fa976fd768db68e86356b7606b1e713b3c41c065ce17dee516b673689b7520dc4206000c5c5f47d64559ead4134b74a6ece8eca619dcc36fc61c825e6416dbcf4821db0eb38496d0e2ad86786e3176cefc73909023c4b50e60f1860d3b9436c20c5d91f1471b95f82df96825deb20d84c8a3fd053c3e20b8567c1694c20ef4a66f5edc24c07f511f1732427943414f601c9b376629a2bd307983834e167bc6552ed069517680bb2d3cbda51986c5331ca35806bdf327a9c262e8a26770c84d227e1cf3cb785429960f145e2ff4232d5f80388f15916cdccf82a44b548605138c5312b087aeae0f2712cbd61d3557160b14d4abf04317fda74db11186f0"""), - TestUtils.hexDecode(""" -258FBC2A94EE48B415DDADDF470F14FF8DFC069CD949BB88812CD27B2BC3D9522E00F302C0B72533C9A612A251BCD292A291F3652695D318927CE1B922125B287FFF9B1AA2B79180622C32AC624E0463E5F48E86EB5952CA1A95BA51388760FC5374F0561FB8873018DEBF785FEDAE4CCD1A41820EAE9D7056BBD329E7A95F21A4919A109BD27D26779C3588C9A886EDBEA1FB97A8048DED858B299DDFFECD4D678820E5DB6CEEC8B1EA879C9C22FB7F59B227B4F7C6AAC577767D899B2F11FE39D1ABC527DFA0E656F25E53CA05630215C5CCF0FC071F124E48C57C5344BB103D51A1FF24114426A324BB16D8F80D3CF2D0CE573F4E50DBD1CFD66C05430A1109374CD84156D2E31C0C3F4DE2F1E225B5CAC05D56C4478929E356F7F46032E2719E07BB1EC207B32D241C87D87ABF28C7CBCD38267CB011F26A9B49090008389417C7A219A9F18203E6D907D63AF4C42C60F7FD99C7F9394021640F450A9A072BF2C1CC3EEC88BEC866FF1FB5F032567AE053A408342A56E3068EA168B9E902068EF808916EA58004FF31C31DDC3FCFC2CCC92E0DA09623FB523AE46C8CBEF92A1CFCF4C0F523430E60449E5825A81DEAFB2E26B3131F0383B8FEB4B1B4E1499E89E9C5FA2ACAF1F37C422CA41ADBF907EB984DD65D8314E2F71E8AE616C0518DE9B8331FB00983490483362802FBA242E4CB71056E3256BD097504AD13F577B36A2F9FBC1EDDD25D9DBC09B3401D58FBCC9DDC8E74BBBC897552FC826620060D3777455BF76EDFC059E5C02BBCCC0F05F86ACE1903AF2BB08A962BFE9E2C435EE8C580502351669AB7DF3D9F6B4720A0509BAEA97FEED3B8C769AC5D0997A097852C72DD6D5FA0A7144E08D667F21936F434953EC3C88B5BA2EDAFC4F87BE8BFB5A592847D15D5E5D972710A4A75A5772DA4D9F156563C17B1F0F242457A198658524B0D6A46DBCD26EB9400DF3C4C942FF53E1102411101B2FCCB58E3FBD16E725147960AD56C6CB6DB336857EF137C49D53D16E98CD7A0E856E2D6B391A95954ECEFF3B9956A6D0C279DD9E1FA5895D37EEA8C54255A6244002C7542789453B41463B084E7FB3361923C43EE1BA115CB254F47E55E6EB79C74DAB4C9CCFF486B8CF5830F23BA23C5CFEAC2DDF7D71EB5F54141C100E0AA9873D43F0AC1034C54193BC63A560A0C661047C508062A70B3E575CC185462A75230D91A3021330D95F3C807688B032AC15A9623A833DB718D04603ECE983F1D21A4513E80CC67FD34EFF8E377B775142344645872844BA46F5AE6971E68FD8ED640BFDE9F276E26B208A8F3D74ACB739C7EA6CB26165EE182F165EFF21905DCE3D02E432B1193CA108B6ED066CE95D549D9B12445E05E0583EBEF32F17EB121D80EC26C1F154C4DA2ECAC841BE1CC7224576EA43ADEEBA53C4D58785F36B6BC0F8AB23340B92CB87DEB0230869A52DC634F68A83BC1AB8A4102264CCDCA39A51C331F6DBE30C18C00A966E5692CA86399264399DBD3F02FF8706302462D62E4D16B5C2FFEEB02A7E8447C2CF1A3FBA5046C792FAE0B1079621D59C1D7AAD17CD6578964D1ADCF1256F2A4EB4D534C51313BAC17A9383B5BD02EDCCDFE59998D2FCA7F3EF52CE0B1842368EA66E0A83FEB581A7137004655957E91B25F5435BEDC0ACCF69238AA4CACE418F08ED0D961E13B2234187597FCC012769F798D969C13F6BB4042897B0D8C32E6CFFC06680B1E0A40F5F149B5974B0E7F0D45367E93B415F7F6DCF86C2131137DCD0DE30A3F1FBCD5F8214AB20BEC9738AEAAAC200900F4B2074688C8F3026140A354A22F83BC2ABA66407F87671C3E7EA4EC6F8272B6D16F3C66C76ADA231677A9B1CF496B3C241D2D1ED7DB703119CEB162EB097A0AF2729D0D6CA8DA57D83E1BEFB880EBEFE090F6E98D64296F7CA90EA1C2B26131676232BB394BCD1A06BA83004BEDDA287073154D3BE16C242DD65839C2E1125B3E66DC93A95C62F5DD31CAF9895646D5E2D183D40EA09843F5DB189B41AA4CD1B40C5792C2BCF9F44823EDD4246100457299E30EB2C66896F89F4FA250AB19CA06EF5B899CB96FC5E0369B773691E3447E68475A7552C10F96F44B3282D92AE49A246508A67EAEB9F4586074D6FE8A44D2D27C7B8FB4EF6BF701084B73641E41AA7275C1D6B517FBE3D60F64BEB9119F3FBE96A11AD45610E63CBDBD79929003BD1F2DE89DCA036973974FE5C5D5A8B5BF82DE0368DC60D75A138CD91E8A9233BBD439666ED1211EC2FE7D7BABB1247315DC480CC64CD8F7859BB9BFE8C668F112FA96EA48BD91088EA44F40D3E57314D3759F867BA52E52BE822400D9B0C2123F50601EC5F8E8B562C4B1F49F9779A99C926FABD8A74173195CE23173F4CC4098EED74C8E0FA74320772EBD1847AFA1B397F5A6F05A00179DEF2E6C3B092D9182CA3C4E382C4092396005D8BEDF6248C81D3AA0854F0AD43C1079CFA1E0A42650EC9D7B9077BEED377BF5FB2F3D2717BED04CDF2F7E7D1F45CCC6F71A780D2E5C3516E5F6211815FD691E036E4FA002079448AF0E005B67D2939CA88CBC57567F634BD0402EAB06805ADF8BE550B3E27452B372CF8C92A7055714A228986FDCF4045421321555BA06173CA0A761BEE635C541FC984C5BD3857DE696E9B21EBCFB87ECA437E9A7B54F4CBE2A601824EBEDFD5446556B64E1A88B0BD9CBA507C5419CB8CC4CACE48A0C9668FD2D045E9057B13BF0785F59B35338501B73B44CB749EC2EBEA97C9D29EECCA6AE1FB719F9A67E8E175D50B2705B6149E9D5D257B34487B547FD050FE5C998412AD0B4159C2225EECB67903FFE332CC3B86266C22FF7776334543C1E954AF5A89C4FE59C1F1AAB5097024E2AA7BC09831C9A5ADB713591106CD3304873BCF11A9138FB08B7485E123DD8F7C107E336659DAFDB866487E197589DE47D2DE8298EC3560EDE21A633F820BE6352CDE9AD51515D309C4BB4709F171CAFEB407ED1A02BC4AAB53588C2CD4C273BD527F8B4078925FCFF8954536E0B4366E474801F5B938A4B81F037764D5CBAF19F237CE37D00246C60DA652B76469BECABD51F873DC75E520A75B52BF585D664B4CB9A09F8EF3C03FCBDE6B9E595C1371C2CFC24C16EBC392C75D2BA04212947944BC0377DB718A7FAE0F6F9008AC7DD30B94C1FCC6BAF750217C0119736E4F3B7E744AD72F1F0694BC88F71E4BE51ED8669F0E814E12FD9F833286E2064708951DAB852774D4620A26100FB44A8A92B86E17507C036CE6F3ABCFAB91193CA4BC4D4198DEAD7CEFB71B01FE2506995F2ED3A02EBB0355E6B67A2294648B8D1C1445164D99B966588CC253D1EA1361163024372E2550E9D29AEB4234F5F9B20AECEC01862CC98365F1C57FA4D5E0C1F8BF189E169669F825DB43172D1F682DFC7729B2AC0C103ECE4ACD982D86C515A208519D23F62934AF981DA66B97DE2389F2F669EB92CA4A5C4C844FCB19903371AEAEFB32E210F2D1155576566C7B529A98A1CDBA36B450F3948F34F90A49F50E7412E6EA68BC3BB0B0A0AFE3BDDEDB718D5A150EAEA784859953FF1DD1B371C539243547FCDFF4ADB06C61CB49EA5783AD06BC8C1F3E32A95AD3CA6D69EC1D226BF9DE0562888839E6243CD150EF6953C158F9FEE5EDBF173997D08509EAD1ED4DC2AAA33E18DCA6F59269CE457C412B58C4483BC96AF5069D1C2E3F2F8DCC5FE2825DA21AB2280984C359DAE44C2367D6F002D64AB47F9B64B5656622517A5F7D5E1A78D4182B6BAA82E0490659CBF2724080A9ED39BDFCFB21BA362DC29C750C5034A04EA5A85799E01FF8B16ACD2EFB8328BEC686AFA20E591E7C7FC55BCA8BA1A3C388B785AB0F57208CEBBC5619AE3A0B799D1816B013BD67D440A7AECA7D0BA517846B68F70CB5D6ED46C36F663D6F242E8FD8C620C9383EE1BE9250D63467504B229378D2589B525348DFF852AF1676A18DE321DD46D7AAFD3DB1825F192FBD3F160E8CA400B201B1A61D0864257CA340F179F5F1967659AF4789846A4D086041441DCF4267681B83D4C8539086E276C21BDF677961015CE550E41C2C45D67A09AD8F56AC3ECF1058F366F2E35BAA9353A5CA40C7021DD09AC9FE0187C10EFAC7BBBF3B1A462C9C6C96699741AC16D3526BED3B30AE25B8E8A9ACD8CB2BB6C28AB89F0A3F0D0F40D10AFEFCCB067A37A2C93D3E8399A366B5FE4829870DA75B93249DBBE3C9AC9FAA70C4E414EBA720C323E6627759E7287472C3DB9CA9B1A5FF03E872374D6B893BA4887AB227E989D9D4D348B3965F7B96C5094F42D84432EB771BFE757105966C9A08D6C58DED7DC216B3D0ECAD2D0B025DF33CD3D813348B5E08AF95BBA08DB5BFE5D0A151C98A01ED27661CCF80F416A1AA260EBB56526AAA289F17FF5AE97CD0907D9143BCAC73F1F83A2A8DEEB3ED209EF0952D5E463D87145E0E4D8BFA1741E3FB737E14B5924F436D0183D98EF836DCA3F9623B50CC13EBB5F94EFBB76EF9BDF40CE6EAC9C49852D08E2A5A193D1DACFA04EAF3C545E0E25E37E94DF51FC1976BAD069CA530E19EED277141BE62239F47441B88F6555B0A998C1BAB53758A41CFD8CC4CDC54E1158DE15910408A6E79D33CC37F61917027E9D2F186466F704647B1CC1CEC06DC1AC37D1A668D44DD8B12621AC3CBD2039BF5A843A86FA492A847D6552E1570DBFE008F51652D65D03D8B613AD917B81CACDFD19DB7F4DC9A14E237CC6D7268FC5D3B228BD88ED36D8360488509C974E01433D78701CE07108C67D0489AE94076106B045DF7CC508466D35BCF156901E53AD2B5ADF8795751891A5839033A40EF3F5DFE0BBEBFB2C9D1C000691F902AE490D382EBC87FD40E76B30DAA963254674C7B6F304DA2C8BDBE8E1DCC87DE0486B4FE6B57A18D5A9E9E4BAE776D6147FF9C98372426EFD30C3B2479231E624A253A7B0BEE31E0FF739F862010AF03E227A12C3ED1F33EF1C0DC9D48A100FA24CE5C5D8B5F88F92BDB6A3A5328B0AFA983D57A1D3320A682B5CA94E75DCC69BDF2AED0C05887B791CE6F6F8885E4CC55C3FB050ABEFCD3AF2CA603172AC78B3AF2B047E506639498D0391A06DFD328B8E1BFAED8F76C6E4A93E733ED1097DAD8663F5BAEADBE1562D40C772D376786509323BF059FF17A5E6EF5A31BD668954766417E6633BBEC90B53ECA61BADD4037030A55A5EF4129D4958F6A8A5ECAA1AE7E220A87AE996AE8D9AE46B9C60FEDD98FF1E67807037970C92CFF9EA4B64F0BF8907198A6C038F9826CB968B1F301952E1F409DD6AA4EFFCAB157E792ED45830708ACD7A50BE8C08FCD12560344221104827BFA495604A57826A49F90B8B694B2BCACE4040627AA0989E3DB4FB7167F50E8A04982084FB3ECB0DDCCA5F24A7398620D19B37309A4DC0DF28909E16645F35A81EB3C5EF6BFD650571DAB03A7FC02FDCCA5FD09C9D2D3DCA888B8261433DE88D05DEE5D6165080A237D55ED718486AAAF1E2534CEC3A87048ADB40EB9F9DDACFB2C883EA6B20BE1EACBDD72432C7A6C97721FE1E0D9A5589C951F7D46F2C5F0FFA909FBE12E1CCF00161E741C4505681B0B018FFACD460528795CC3810BF7F94FF9B75884956798F21ABF36DEDDC1F95890894EFC15EAA6F19E9148C71EE9BF4CFD41EE3E5DF8A449FD95E5744793B9C223D26ACB44E691D7E5B68D49A19687F0237E7287841D3B0B4483E2A7C29CA81BDAFA5D96D9D2CB6FD9724B9903E8CDD03DA810EFBF94BC7179349E10566B5A314F81327F76C5A8346E222C408EA43FE29439132CDDE79D0D69C45C7217399205C2DA4D33DB521940C4EED74CA22645D5B6A549E8712D0B8CC50DC180067D13457ECE66D489F687DE218449D974620B3B5462FF3A7F00C439AEC73A53303AC51EB84BBEBD51AA48A5DFB8F93556BA540F5101CADB8BDB912D7BC87EC2AC67971AB99093C8616C4D1F3E7B06003E4FF22D99E6CAD7558EAF5C1410199EC97720E5C9278548E7EDE62BE9105A2B27A54D95673849CD5D60424ED97BB64798263F98A63DB58BD55965D3A4283797CD88C7CA67B1C4F90FC7237EA35AA24DB18A4420B827B3FF7FA5472C31499480EEF5A97BB967D1EC46E7B05A3D25212C75972D48A9269D67048132399E1BE0C02150A3D48717E4DEC2ED47458EB870A1EEE5381209B5D182DA2093AE46A4D99E3D4F12ADD71001BDB936FE8AA96797982F88EE67AA2E0F340E7AF498D5AE05C177F0BD2650A02ACD4CE23018F9E00DCEB9794C5C76418EFA65634E01ED5E9FF94FF86AA73641117BD554A9391874A75C7CD1E7759755B9D2A7F367621C0011F61B588D913C7AA0A0EEE3A2201426EDDCD56A020F54AB41CD899721D6E1F05F8774CD5FF6417CB68EE14C20D9234369C9CA59627B8796C37B4ECF1DE2F981ED0FBCD5737DF0B82637D599A61826909C978A2B68CEF01C5CF84B50BE77B49C1887544779BFEAE3F533286287E48F0ECC0D36C27F1209314726855E61E5EB5E9A5D7E3516E29DD369F94D72004742E246AD4699C64EE996BC7B2A079344ED32A528A9CAD6D5AC02970D0168A8B5BC713E28934F2880774418550AC2F534D06B61E627BCB8711AD9FC6F2A4D9301EBB74E1F3C73B05F28DCE5623BE1BFA871C14A947A947CFA806AAC43AE515D6CA65436BA6B66F62B0FDC8AA4A748DBB72D9AB087AA39561271A986229EC02BA3719CBB1798DD333248E4DDD0B6EEA4169D3B03C9F4DEF9616BDF97AE993F0FEDAD31834B6F78E23164B556A39AC1F209581F61AEADD8E504E81A808B1E97F79F987892A8F7FC35FED9B1A2E9D3E17BFC5AA64680DE98664FEA7B479567CBE307AF2A8516BE4CBF9EA030471428CF802FAFF85701AF96CA1D8F50F5A79AD63F20C5CBB954011BE4B1A7F627A8B5F5A0D022D27BA6FCB8D3587E8632A2FE5794C7E8FD09C9AFA3021B9F43BA82EF48A3B1F3E40F2FAE182DDF9558F7033773F5627906E159B794C4220219BF1A9878B175996A16F3CA1DDEDA56B16E63C504354E5E42FB90CE4D2C1AE7C93D8CE27480F3BCCC076CC253B574A7BFA6D3BFABEB3FA6A19F196C7E31A0D6E9477F828689FD951E0FB033DBEFED6C680F0FEDF2F43F48C0136C722601CC7C4B48B24121ECB6BF84D6B3DB240FBA1E014F7E3ABDFC1F9B98A16F4D39826BC1EAE44385FDFEBBD649BDDA129FC7EA3F50A5F481D3B7508EDEB04FDDB3006D6EE943930E3F0AB405D151F21E8AEE5BD87F225DA6E155158DE27290B2048D384BCC54F0EB905961AE4CE5E6E93543016F62445AFB5C39C3EA2F3367A0B8F0FBB83B37518C5DBE1CCA1DA9D0B54F34B15A1349A2F03563732DE14EA9BD238F481D9B262DF69D24A91534805ECF57A538D8F08B2FF11E96EE692DFEB106D3515A7C69386A781DB1D5434AC18713CCA12C92557D1E7DFBB15605AE3BA86267F3E6CBA42B6084478E460F092BA2649C8C94D66128FABA2D0EA7D9BCB20663B0DE6EED2623A061778DCB40373B8CA38B02B7A49F6940D6D11CEF549CE80212CE8D3A85CF2D774431343FA1FFDBC71C5334B1CEC4D4E0EB643E1AAD67D1A5B73FBB1BFE47EFD83CD17C798044A504FBBA5726429F41DDEA7B7265A76A48B0BAB4845704C771638977511092BF6C6DC9D574E6288C6A3B96BFD37FAB695F8DE20F28ECB27EDA70A07FB2ACDAD88DBDFB2DDF06E83ACFD3A136C5DF4811D34C242BF9206D579BA8DC6D20E8600B726C9F1B918EA573B9DB2F96444E17B6EDC15822B85D452CD99CBC847AA205EF79E574ED9625E33B6EDC793E5"""), - TestUtils.hexDecode(""" -d645f682a1b7aa2650f431a828463cdb131c1c317bc2d9a92477f9ce4a7190d287bd352213726174bb967d2538e6f796698924d4808a15377e3d05877a560d2cfbc13150acab39cc6ec464ae5fe51ef788aad862bdce80a3c3669186598ea3f01dfdf9479caf10033fa89d5bf164b454b1c909edc6a85793b2f3662ca4dabc42bf621b2c5f55b357d2b7c97b21a1748d6e6d0cb3c2e1d891b057f0c3bf482f04add99ecb92d32a099443987c25b1a5e26930082e9719fe2ca845343c3c0208d35cada03bf51f8952ef49c18c916c03417e217342ebf7234cf9270522b3f6bf7dbf5f7aff8b245f1833b8cb314f86b1e407f4e0b49f2f2917bde67c9ddb7fe39a64ad96811980b530df51645a89c365602dc6a6b53b67e56c74951d72e0cc2a7ca5ca0c1b32c3c9700fff54c317b3bd1474cb3cb402a85ba80def7b994f84018b9241ca20cc5ebe6cb24b26b4ee21904b658954fd9716004a009b762c5eb5afccfa8f6153d1cba1358653a88c0b87dc6478578929baee5bf33065aea3dc0bf333453ed0fda613d9a35e00eaef91ea96d87b676b66963d2affec30cbd7dbeed1f36dc93527db0a082d494afded3ac6df843e385a53d8a7a0dddc2a38cab1a92a649072768608fead5c538d8767a75f46bb73f7971a41401b8fd50312aadc6fc5f2096007d6002013ef9fd66be15822ca3b001540652636a8dbe65b2b6324885504ce3233f6fab6bdb5d05a10d85ca8b9934a5fe39d7c3a095530554d058f2f99f9c2775a0822ceccea548a35fcae73ee931ca01ccaadb226f91f0104743c423b220b9c76654c9baa1a1e60310673fe86e8c71eba544763f94b80dd075b3fcfd82956da9ffd4d4a0364e26cf4c4d7f0d2ba435a4e7b51b01e9cf55251a5f8fb4e32ed1fdfb6dffac187bfeab67b7bc06fbd1d623c68823d45d708ab29117ec17fb2df9ff17378ca7a021b504e678e4b7371f2aa05588d710f292e547f719f7d2e66ba39d382807ccd3cfa8ef2d33516053e6ebdb2a8584982efb880180c45480939af7b3d72e71d046fc78088c16aada249506b079daeb16056bcf49d495e5f5bc9b64125f66c809e02282e26a8b8c9656d19b75eddb4310daef82ff90bb199142ce3ea68dd6ef33cf4d0f2e7981f2d6d78beb9aa10ff7421804231b02b39b3e9c4be9363c49fce0b5a460f49094389ef2c28bfc45c805a563dc2202bd9da12485eff443013dc8090be20ba1430eb71516fb36926db06d59f5313d43294d09a5c242edc04ca7f1f69b3f87861fdd572385ad400f66ff9bf127e866957b5b7ef7e16f0cf93cd10d77b87894fd8c0f184f0a359cadbfb5fe6d91a06bdb000720f202f077cd4bf5c8b149565c43b4a07cdc5a3dae7599d26f3931d101d086b9546be593ea0bb85a1807eebaaa798e57d88d4b042aa3e3f621206e22f66335792b606f419d1dc63367d73dc462ebb177d3d9d4532ab6c39341b447af8a982d24300226fb367987aa37ed10223083e4db66a5a344628310d46174e0c8b466fbc0809905d416e1b742f3749ffe7ea56ec6c28b085d71d4e315b4e49d6ec945d23ecf5dcf503c59b839446abaa0ee57179a6567ab4d02fd1025b671aa5a464e1892e9e2b96248107fbe5fc4b792d1b6f62ecc6195be7acd19d76eabee8e8deea2ca2661a382f06e4ef90179a4fbe255f4a617bf6c1c3c564e05d1eac7cf110759364e7d3045b2330a52bdbc8ab2307e876df8b0011bd2361471c6cfd7fec98dd4161bd7f7517fa6bdd2d678dd4dedf71dfef7eef7d28d03131aa2db37f163d16818aac1e4daa94c6fc8ac8d76f03f981d98166431fb42081dc565049be93013f71832aea1c20dba0112222bd1acbd7e7c112ebfaa6e264655950a6fd78da09d55838d2f79a87a311eee67f023af189511c7e215cf8bf5b8f47ec397ff8ed22f5825814c86712c289977998dc8c7ac8eb60cce95ba56efe213043e7065d8c6e6c1c6b7c4b87f807e6375fd93e8133b9ca61735d2399bc2f0cd4e6d28c21c4172f26808a70ec7d5502449e335abfd7ec5e45fd298cdfc8699b2607745c30c89803cc741b1c74fc6698fa95c1397b59ce6a08a19d3572fa395af1f913af021cce85d40f53d511b2d6ca6860ffac07dae4de99cec54b0608ccefa3395e327d67aac3f8940c03c737f0066da5435ff060320aa68868b2fe309669a014e0ce7eebcb3e9f3d27684c0d14be48ef4d8de1f0f541c2dc22160aa238f736de0f31996fd1e554ddfd33892e998180e4a47fbe34f6e9f2004d009e83fc55e7c921a73390f6fd44a7f32122968e174fed54ad1117344325897482707ce6cb45121266c870f3f560c4315f046e3798073ee0ca7ef718176458c761825f7288b6663bf48b6efcc50e35a5ad124772fb64967056ab6a39658973471ecadd3d666e6f0377fad3b7390dc9ea67545fa030d1085244082ac60d0ba4d6f0ab44167571324e40ad664fc95c25dec94bfd59b32332ca5efda8288965284c7f88fb8045af9169eb63e98405e2aa3e949d4ebe07f3450ce6caa14e2b399e26a347d88b2fa8a301032c39bbbd945ef5d213cd4b3418c25cdd175a3ab8ffa41679cf6359ea3c28905309af59f0f92cb1db581e21da648f096171953fbf62d53da61da8eee1d24053270ef6911539a7ee93c6ff45a0b465ca879498e131d37d1a05be88fad8cc28a3026c7853b9a48bb8f1680889ebb3978b738ac7c3c54a0bbf1ddd79819a70e9d083775095e1daff66f72df70cf17e746c70f3d291a343d4530b6c9dbdc861816ad799b1a63f807fcf791fb1ca2e3160543abbd10e4fab61c18c3c4f150519d9690f7d22c10bcfed5c211a6af6f438737402b425c5ae274ca98716bf64b127ec0c7a6cf3598e9bac44149b93310ef5de9fd8381a961d5b9c166b7a687072a1aa27a8ecb2d9a023d353bdd29870650e0626931654ad80a995d6c5ce63ed42ec35444ee57444ef7edf45afe7255739b7ea731dd4c48a1497b5e6c135f4ddf4cae02577920f795809c1d00a391f15e7e376271c0cc0a09ef69efd28f6a44b6d2a9577ab7fd2198f81b92cf4094c7186e72fc3a379ec9e31b7bc12873a0008f40c14a81180f4caa16aee8ed827341c08fa4c98d3be393d524abfdf5546999acc4bb74e6d72b7db9c443bf8bc300fbb0d19ab0a716001cc87dd27bf2605930cfa437c08b0392e8526a26dac97e1e692baefc515eba1b82fec70c5eb4fc950386be3a5eb3379537100649cd192d611dc90e5787dccc69a364afa632abb31de145279e9d736ac1f6185f332b75875006f01eab3a48ad573d4e9b6849cba181d1aaeea5120fac5da72d81e7a36fd0847fdfc5f7f8f589b98511bc086a107d1ccc4797308be5b590ccfdab138078ca19679a5bde6962909491e1df2b048924a235819a7a28e3e3e97105a1a400c0997376ed9ff34b48d6076fc8d9668e6498171b82d7dab2418146610d80c2c7be50f614c6d5adf8511ce282d2175ca5101bb18dac9207813b9be0510a2195cc2c746d2bb99d3049f29374664d74497e0372994583c788765f3ac918db9a4d4d1f2c2482f50d013e7e93e0a5228cc03f4db0cfd14aacd90ed05b7ff5cca2b00f577e0ba47e7a0eda068f1aebbe688f167e3af3bcde28b3bcf0e89c63389564fd60be1c8919ac245db3cab86fef9d0bd4e365c1edb0472f4ba23b22c1918a399e3e08933031b2d0ada07b4c89abeff516f06b67e2b5c6bfe4fb6671ea4a45c375b9310f07278f0594e4943f4e45098e3c68c2c7f8b4eaec3b3d49a21c077469c84407b2ecf958c7aa3ccba4833a0b8c6f6cd8475c4d239608b9d25bcd9324326b4251b89579f2e902724f26943ae92b95487b215d719236f69eafc46070695e8d4a93053e275b93cf87723bdd589c15f722c093ca50c1d54121bcbcdff8c4e306cd4f11fcc681d6af09cc0de076a252bc8583b5afba1405798756432a729b177906ace7f3b8340f3526e7688fd49206e6853b4c72979469a30c584786f2b8c75cadea9eed04cfe68dfefbdd2ed5e1e2b3397ffab7c5d84e645a4049e50bdb9cb2453092354e0112cf00fd214e22681e4111a7d4563b84828d6bf6450facbdeca5137699c551f2b0c7a0bd5ce147dc71dc2bca5b0abbeeb109e6e951115c9c8448d455bf723b8e18e31b480e5b17c8de45d3f73ed313b9bd6a8f5156cabf25eea4737d4dfc8ffe042c6cf665bb346d89477d1faf60ace914eff5db92d82ab2da4e08de466f532d1f7c639d71e6c3dca9bff0c5a4948540cbecf4aa65c4dcd7caae9cc3ac56c04511518c1ebdd02aa8285b05393ce9fc2d2a3d8fcfcf79d4f1811d9073346d67f4f9af28d15706d577f8592c653c315a396e03f3dbe81c339c220aabd4f654239b14dae453dbd213da8819df690f38ab52a1f67319dce8ba5cd33e9bd8f5e61c0e0107e97b7bdc384269d410cbb77e19f2d89e38305c6e7dffb952e331bccdf884956c9c67ddf2d56c048b31ecaadea55e8efbbc94ee0a19980cd30edfc85d6b3ebfbeaa51ab1bb01008554717bbc6b17ce9b8b255707f95b7302d63b0189aa4e9eaa966429c1c1b9d2aaee73460a2335455f8e9df22a2c3861cd354f5163b1f1fc212f709c040516172a63acc5e6ee051f5a8a9195a3c0e3000000000000000000000000080d1418222b""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -8ee898ba956b2d9173be3179771f705dfaea460258d89ebb97518aee95f7560abe8e02119cec52c27d34c28ef28453699fd6ce193970443d211c471db1d15d60c59facdf1e49a57e03e2398a1e1375ba9f1250828cab80097369832edbaddc174c175033649f9dcaf8cb0e3bfcea913eb47a34946919f79809194df8daa2c4ae96c85bfbaef5d2519e3248b475b1e3f99cca049afc80599e671eca3ca8db36163dd4356d03929fffae072fafb039c2b091e89294083573550f5f7a5d8eed887e26379856a771f65d31a70a74db83ffe8814b7b52ae41bbce25aa4c33082177045d6d2acdaaef17bb73855f42001469c6b0717ea0a1dacab68372d25b575abcda54cc68db475132d20cd722f2e9eb7c2de6280ec574ece4c921952e79833f1338307d468df5cda8a70441b362cedfe524f2e9167070d475eaf2339821a1a1d576574b986d20e82d69e91cc84ce00cc82f4aa1c9907f6462119997701d9bca1788f1472c03bedc490d840301dba631eae8c1113274faf8923ab9ebf52cc80bce16b1db45d2ed8e4a14c4d63a74cd8d91a48b1663f8246312624c125e3abebf2d57229ded63f422e4bb0f126f9e47f5c301493d4c63b0ef611a7b141b74bc4971e2b16d8156dd759213ec7febbe076a8a534535353d01617b2d119f912d112e4f53a06b9f267b1b4d2feb6688195ff5d57065f54b2a18cbdd8f9d57a3588acb5822291cb8e01e2cca5d74547db3cb84cddc2fa2afb9008af15aba2409662989772108283c78b6a745b3f8e311998de25c880ee8a74f2fe99e45a7ab3db69e7849accfce7f8c5b726a888dd2bba623ab26145c933db5ccffcf7dad6fb7ad918f93fdef9f710fafa54a29b774d1ebf7f21c339c56616fa1c3865a0d57b45d0c4100efb16f8f62972cf5c9855bcc537270dc50c354c324462ac1c71d671e0bf37db744542e4ea766cd5d96c9e6349f64046d8c402036372d43705b33fbb3a261ee63700f79e1c18ccacab0d351c697ef40029c08a76c3a7c2bc185e03589a91d4851af6bdf83e3711aae0037452a2495d7a88d881504d4d251a24dfa389721c52afbfd0ecef34ea2458acf120bb122e614658fee8af89dac06797ea2d74ec3ccf3a1ab4ff120d5d69e0e6b08caf9ece5c58d0907419107d610ba0a61359dcf3fdb6209c6ace63e9442e67b7e8e78e94cb21143386eb5d5011ab83cc9d5c5bd03af2e1131e18433f0372a29c4f187049f7d58b18ddef1fad39c46c433268ae6d09ace463a5e49a130376a0dd89b38b3728161b14ade010f532172b71e887487e9ab4eb97f471f6aaf1e61b9e7c6742cc63d6b96443d67488746a69fa23cd89e977b891c2b57351ff75f2e0fd0316a561fbd37720cac1bb938ecc8fb5f5a96b97fffc1029dd1ffaeb87b20ac792e96294eccd88d2e8ec625e0fa8fec32b1592eac7f63c53320653dcf54ed35a05809ebabc6d382fd6eef515adc3e47319052278fd2f6f2aa22f6b85a71294e9d905228090a70314287802dbde42cd94e06747d09371e9860089f62c2ffcde6913a7b01880ef254ce9f02e6817ca231053d1578eeecb88c5afbd1cc23d5e8f10d983bb9b653f03c21fed44c3a327b967fec03ddcfb6fcd6ae38f2b0e1ad455c772b5628f2db1a9928a5be2e782871dc99c5e53d47a7adffff983ddc0768a52a4ffc3295f804bd06271f134c3d54b7539ec4431b34c7ff5dcbadb2cda2dc2934da8c153df98ccc225df28998467a782593225e7dcfa86f51c65777fb79d26473353a871d82341bf9685ecfb2a10a8525d7962247c399d19fdfcd24da464b04e3e312292bc7749f15fc3948b1b49c592f0b5ad01b0d01cc63c3274a16c1ca68b27ecc446a440895009251245a0989d2a643293ee17569c6f8551125279d3454472c8697914d22dcf5c2b0da92466fb66f08710957cd1d54928de436409760d481e9279fe250d3d4f2759db8fd7d7702e552cf5cb8aa30acfcd2af2c0546fb2aca0c687570dd398cbf0c1578b39c1b20e433f0b8a96d9ff715cf72b09b78f011f9c0c05ee2112074b7824179be2eb9099748fcd2d79919399e16c31adbd4decbb52bafaf895575e0c7bab7688f237cf0e0b88b714a3ac1b7742257d5ffce53f92c793f5c06b6193e55fd4dfaaf05559e2df4e12e5982c3679520db10dbb04f88a2a643d6ea0d96a0cae9b45c9d185d2a896083cb2c002d56f4559cf2aaf8cab564e7a5f14628b22cb8c0e2818f2e7da1ad694f9164228a773113fdb0c3734932d9c845fc694ec3c8b0237ece02ee1675e26ed57aa28d932caf8d31f9f6043b326211161266ddbd61a9c8d241ab049713977d1bf2d446f3c0860270a401095620db0f6faf43af3b1a6b1e33fd0d769501a27229e4195a138057befd232417282d9e65754d2311e5c547e5a85fbc34900edca8cf487ad2e3e7fea9ca7d88fdbebbc2fe736353df14221accd45de5ec983847d37821b8456c687eec93ce790e1a2cb6c84dfa2fd9aac2bd669d23c02ce78abcb1de43c4f3ea879b8b73123c00b48517b3de903922ebdf51fa632bfd4debb845113ed4ff66f9f20133a3f2a02c933a16ed747668313bf533bed5515b3058e86ee68f0d3f043e797e54aecdf7ccdf5d771613b000b7ac754a4ca6f2e2227d00dfb5231799698f12ba2975f842aff5f7252d49f05a6713487cebded694aa861bedd2fe11fd0fc4b4dd6a54fafcc6934aced6c75680042cb4137b669786219c197803f34b27ebc00c13"""), - TestUtils.hexDecode(""" -7C29C0B8E2A111F457E2384845E7698DE4BC9BAEF093F15EB03828664AD31C387B247A525623282460D60290FC479A928024CF62571A57F77B17DB0AC572CB59723490DF79E9B1B31EF2C9488B6D758C43EDD9162D8F6C0B03F43B08D646172A1F8DFD71D4DD805A3AFCF1C4265BEBB71FB251DC9DEAE670A664BDF943ECB00FB7EFA37624953F94CA760013FF1270C1EE7FF58756CE19C204220713724AD03B10F1D6961CDA361539A8AAB6ADEA92AD782F441428C0018D85C0505BAA793C752DADFE92BFE8F033931D47575C9F83547DB18DAEC0FEE90E83967E0D0DC93281000755303F0F5F05DE041211CF842404CD5E24DDFA3C7C83DE3EA21EEECE37A52E16DC80A350B3A18E88EB3C81C74D25B56CDB446F6198DC88F981F2B1ED8DC94194D81CAAD971A9A3933E9319047C5F31530C7C98793A0633875A14FA5635CD1B0441FE267E79C1E874BEA968CB63E20E7C48E7BAA9CE8393FF9A239B5A1D613DA65F7DE78BDB793AC72566FDCD06CDAAF56E18B773737A82298902F7B4890EDABB766E990ED87C94005A2E2450AC1D0192D72468F81DB414F88CBF07707A95F549B7A9EA0760821AD710D52787730EE8917272497E5891656176F991F254A5D582B5975F95AF740421A3C18A82158AF11DB15C154F17ABE1163F997C64A3BD989A573D12642B9AEE87C1612A39A8A4FAF25E35AFED3F2DBFC8FC8A2F9DFBC683CDFA3227107C50526149557CD773DDA16E36782A278A93CD7F4D8FB47DFC37DC3E389D164913316A885C3A800DAD0C57B1082BD4D804BB6A117C3B41E7D8AE9CC9622AE3CA8EAA9A0B502FE3F5A449BA8E768D2C98013F681C68A5F4AD3CBBB83F302457679BCD3F35C4D6176DD8D2B670E87EA291EDCCEEB9917F98CDDF5EE1689DBBC85BBAA30D191F1965EFF8FA9B0073D30B1E2456FAF880110BA9E75E4E29C6106874D32944F49DC7E7E7C56ECB9D287F2C2E87A779052F9B84FF97AAE007012A5EC497C4809F0193C69E5B29940510A354C866505424D4FF3853C94687636543115A73DC407C47927EDBCC4E0567EF4E451F0E464A1385D2A0D740C7327F6E92EC6091845356C2620EB163D9F774D7781BFBC6F6F652A4A2DEC73203DF5643E1B4C3C3DCDF0B4A0B160598EFB56499D2DB1F1E76612356AF3D708F9D61D968A6A0193D9146B2983972271A4C02E2136E6593DC47FDE4FAF2540A8F7744BC3230529AD1C9D2FF65B7671B5A5B16AABACDE8D45A940ABA4171E21090AC6AFF54CD8230F7BCAFFC42C028E6023E55DD02E4B7F976998AB5614A5681C615BF8E9E6959B038188F71C75F6DE44A6B0498F2A9254F3B0968AE7DBB49872D775CB0A5725206D648862734F202DF470770AAD184F822C56400F16F30F8BE40C463CA3EB5ECBB15D51CEBCCEAB43BFAD7DE7679894B90419B65912D67DCF2335212E82EFDB6267EEA331C1439BE2AF62E584C222C1052AD91C7F5DB6AA649F230248A14AA6A532401A28ADCF822089140FCD3B1CF2358DC26939850DB2721750F1537424F6BF2020A1B4684ED79402917D1028C1B59076867DA809D6C5D3F47277755384C20624388EF0AD68BBFB6A63005AD1B6E48ED654E8362B2AF7BF114F2D144A420712FC4EC71D408BE55EBCA8C2F185E7132196B1B76AA7BE44EB55DF7C82C768943D649631E4D87B408DCF8FE470164D9E8DD1F48CEE7F6BA93E239F889119A4DEA118D93F1474E516139036D640EC788AEE708637A619BD1693BAB6C9EE9EE0C495C0D0F8912C0F14199AA69B960F53E4FD8E2771DE4AAF72117A5B2388FEA0CA3BDCD594D1760905F26482459BDE80EEDE3FC89F592CA16B65B27E9A21F1789BD0327A26EE2224C61D80AE8FA6053480048D15019A80FCB5F3B3C6F64C168690E4384AC05E856BF341531045D2952F2CA8BAA0B8926CC41AF2D8BC5A1576292DD67114D521DD4AB535A77E5E9BEF8EA01DDC7C65446D11F90D6CADA94AA1AACFB1BC3551353D09252FE515A465C1879071F6FBB035DADA0BD25A022B026AAA5B5BD420237FF097099CA2402E68E4530F97A003E50CF693D1DFB551DC4695C760138E88B8D11F3075DBF8A6D9BCB9B1242648C0C9DABDD9D49CF132B0766302437C0CD81A0889585869DE92E6CB30C31265C84F58E9437CEBA891422967AA546EEF720A8FCC16EC7591AA0D47998275DF1AAA5ACAD1E1C5868CA430F4FEFA0277262C69311FEDBCC083114AAEC9F99FD98631137A117A9B48B32A6D88E76F96DC58D741395BFC102E147C456D3A78A0FA3D186485D65B4E6755B53D301BD13CC88E75277AF3CCF1EAC6E9C56FE1F10DE05A796A14381551705234F65DD6E717E9EC275E38690B73973C9CAB27DB909C5C13041723BB18EFECAD808667643E87620191008E4D10F471AD153D27F1FF00D8AC6A8C5E59197AECA5AB496D8D10BC79C49D16DC7948C6AF62703D36059587F6EE038820A84C0F287D79C713B066E1DA5B32BD89E5FEEC248B34AA5841E8666CBF09C47EFB17BC82170CCB557D41D40CC87F2E6C0246F0B272733854CE162538DF34559473BA5979AEBFC0D6A16EA7B399687E672145A1149E382954815B41E7E37CC415057D7536E65FA1A35B8EFAABC7B9B0000E08B593496B01E8F14FC950632C659C0A7F7D59787C7FE6E8FA7FA0211A945ABBA5044918CE8482C6EDB366368A9DDB2F2BB66C146BB50251CE61DDEDD8D6A4A60FEAF0F794B7B0DB91C52D7ED1A54AC85D7907BF3A5A96A60BDDD08F60148C0B3237DBD56628982375A67F025B0E3F9EE13DF254E1D6DDDBB057203CEB267200C7788D01342C064FDDE996183646FD3C1ABBA5D2155383CF391FF16C78660D0BBEB549483A4A4A971017A8659616FBB1C3A8A2E83230B610C0C74B8EB32667765F3C2F31F8C0D4BDA3D812DB64448684AEB482DFEC5C37EDE742091EF7EE6F22E31CBA2C9B9A6656888F446A1E9D52D9E6437D22594A830958CACC6F175D4CE8423178B71E7CC81BD6DC2A7F6580A8A3A1207C34D6A1646BC3D89953A63D22A30EB9FAC74103FA527843D3BDA656D1F22E729C3A004B923D08C9CB18CF406FAA89D0D63782C7264D5A8C8078EE6D259EE168A415E7BC83E4F17D9E674154DF08CCB21ADBF5B35AC28883F6943083AA97210C6DAE492C6CA4ACCBFADD99AED15110B10C9904469B4F06ED32546130B0EC4B281622A5EFC9C94B1F2280F251AFCAE857C4E17FF5CF472F038E02E5B7B3CF5CFD2F3969B9B8D5A27C8EC38DCA4284F0280C24F01DD97A618FDC5EB57C45D9E2A05B44E69FE2E47CB50F596030C70B62437F2B91A67FB84205D95CAE259AB1D5FF0454C5B4D87F439DCB7FC62B704ADC7A84502E1BD8E6F52109BF0F36824834D574E07B9375E693AD477A9D74E94BC4E883206DCF875AEF7FE84B9B7C1C9B1858E4BF6735235FAAE21FA566C866ED7C952B1BC19A911984EC25AEE310D8A342AE32F46255E0E00444CB0EE90C37152EDB6C741F5F394B5D47154825279465F0F8B19DDD85B8D9194A7AFAE5FE609A245AD68786C9AC044C008A1B3EFA3A8F4FA0FD49A65B6FF562F33DCB63754BE76244326FB6E416EE3267F93D7B2BDC4705EE7021D5D2EE66BA8D7B9DA7EE6C354E05470B31406DCFD2C32C94C22A72DE90E5A9DFBA99ECA95F73A014A3E9B15EFCBB67FDFA6D3CAFBE3ABBB28C4DEA6AA21F87693D68F0A60331786DE02BFA9E85A8D2AC8524EE184EE738BB3FEFEAD7E19030AE883707DF67ED12E8757B86E6E5FBA26715DBFAE2BE0F90453868931629FDE97712E08A280FF8888007AC27DF2C7113C30604C5DB17538F026F17C7F07D2A94AD5AB367F9CEA87BDBA712363D11FF5CF0590030BE9B342A7ADA48C08BC42F923DE939DE79616CD346B3511F41CE695B3F939C101F687DE7292CC96691EF3F3CB653F4A67D2EE09C791F993C726D574440EABFBB00E5E6328FA70D69FDD5F2EFFFD37C9902AA45EF4E9D06059B0D8E3686C74C94CF2F0032ECF740B31E3F297F15343A0093EE0B8D7F8EDA1118D329D05A1B992755181429D410771E37B56E28AE2ED8C4DDE8422FFE91ACE348E443640578687C57D79DFDF917F8E60E0A2F1C6223056C373F58C297F0FEE3060D31DCF6851856D1D05BB38B1FF426BADA10FD84B2E08AC149F91DDF4A5CB38B290DED4EA3B02EF7A3DF42BDC6B6205D281CE4A48A1C13FA8080B6B4100AA123097A4140415EC7CEC57790D6EB0B4200AD3DD9FB7FBD056A5E3E9D7B7EF47F44A63DC908B6DD8B020854618F7662391DFC35A88F4F5750D282F81DDC50D0132707174914293E3655BD2942C09F88627C0AFE4B921B766BEF41E246FD23482B5B14F117E8EE340C47C7C405BB3692C4C9E541148C2B38281EF0274835860E19C2D48953545247BD1F7A76CA43956C069A17CCFB4D0B0FD478556A209B5376BE9207AB174D2CEC96E09E1F8C0FA07D8920B2ABAC3490216DEBC67030E9285B3EF6767AB11E8CC935C4019B7E68FB9AF8864358E6927D350CC8B9A40662A0987C1C8877AA9903CC89A93E1979ACFA279FCCD2E171A467B76E1103C4EB166273ED7B4878908B67DB77C4FD4E49DB46109DA4BA78D69E03B48518F302647B8186F787F4CFCD87CC5A45B98F7558ECD0612378306C9D69FBE23B06005CD5AD84F73A563B1A3C7988CE0157D2D2703ECA8575D8BFF972CBED32A231395655DDB2188BFFB413624639D361B3388A9C9E13645C563A87C610F6FE79AD50765CFA8149E27F7083A316EBA050860A69BA56D002A78640D71794980C83573A5DE69A697C2CF2E17C90BAFAAD3D421C6E1D8A55B3FB4700B666AE3CC3EC114E9DB428F27CE427E4101ADB49B84CA7855458841DD1F4FE76D9074D940102FC47EA633744C2A664E22B5C5AA2721017F3FAAF4FB033FBB1D508EB98E1D643406ABD4D69C030A2349408C80993D9F75271F913D7417DA995443377E6F73A7DBA24E034A9C4820117D1F0BD69C93FF55CFFD2D36F8078209F5711FBD1587435517291498926E7354558945F721D00A73014C06B2C9BF04B7E695B9109D769BC2172CA7A70700A1D5AFF6F5FCBE699FAE81BC34B0495A82BED01B983444224B4B860360C07F8C3035FC4F0C4B7DD4D37ECAFD32E8C121C677ED263338359E25BC4173D191E869ACB4A5F6D20FD16FE50454CDD269DF8CBE5795482A2B40D52BCE5FDEBA62D9274C9C67127580795BC01752740E606D849AFCD6ABB8340613C61A764B6B92863779622E40EE7A8994034E7D303F07EFA11ACB70419A53897ADD558CFE157CAA3D47917CFE0287500B3D70FE42AFE36853188BC815CFCEC9F56030C83E85C60401912C14A75A082DE2E0400F6348EAABA59312C51A7E3B6A5B39D606306A304B4DD3472C5B89FC65DDA54650392A02CC6761336FD114D848BD889DA4BFE6D32931793A6515510CD802E3D9F2C6F8F2F9DD96ED039462C587395C7E6861FF48B7980D492C23E0635464C7D1969C12A43BF0FFA3089E6B367AA65D4678A571A0D47A75056B34E3F8819F8B6ECBDD6BE580D423D902D3C22D9D787E0F1B6202DFD392AE028292795FCA0177CBCB09AFF8B579A87A854432827CF797E494ADF9F96A56777AD6215F284EA91D35563F25355D12BD155C6C364B0C8423E1BBC809E736CE0BF03E0C0B728F04E6BC8F3F07A0D952AC9D9530C77547B687E193EE2D3565AC755DDFFE880AB0524624E17E019466B7D0E8FD6E94AC2BEBEFC617BCC5D529C83A90D36D57A93BAA0C2ADCF360377C9E9D58C456FE9F3D49CA37A8C3B5BC7C231842B57D320310943FFC0ED2F5F622988ACC7842F8410BEF0E0671673E7BA61AFCD2EA83CF066A169BBD97098F4B4F3C9FE73F5CD779F502C584849D1AAB52D7059D1D4432C27FC9284FBBEE43D07493A38B139152ACB71A171D454FCF936656ABDBDA03DEF3C7B27891088F940C200AD454308001FEB2DFA0FC38FA74F85A30DF4FFA64DB48E7D40C158F058B58174F18BA482AC445A6A63FB54CC6C7D4C8089794E8AB5B38C41C7FF4C6A8A5F294EDC3FFCE3C01F2C5C7FB569CA06567C8D3BD34F82046DB4EE7F7491D890DA1FDDC55B12D90A7853D8FB52E86AA1FBC669C7ED349A2CEEA9EF18F76C23E817AF58101BC5CCB0346A607D6C60BE5CCDE5DB9889E040223FE98B17D31D64E8C1456C01353887D75EE3B82D66CA0679B1C2366C44E52D73B09D48A39D1BA3FC87D73772DA601EF442208DB763F0BF888D28338709FCB008B83671442CD9F7ECAB2C1E26428391E559306904FDE5BA21E1757D94F84F18A5FD8A067C556834AB257B9D2E1290FE0ABD3BD622A2AD92BEB2C6BC61852D58384A20B7409E4F212F630BB280A46CF89DD702B2508752D6A4DA94BB769797B6E7FC318B0B3ED50D7F8C5D8579526D536E4D43F93C055479D53BF6159BCEAD8CE87504EDF7DB35E1D03EC7B4F13802AAE0207A2414802BECEA39664110A54C37415EBD7BFD5D73E871587967F24EA34B7D06CAD805EEDB95F1023B7BC3A74A59A6C9F3A4737FA1BB087012E0162CFF15A539E86AFEE30144F320FBAF088C6884489F84F16458755561C9CB0723CEB6ECB134083C3B82E93BBB57FCE8D51374D38746BECD09A059AD6623EDE82EBCACE009C0C27D5FFFCAF76C9E91BDF5EB895FA1E9C3C0AEC0BD73B1582C067A45CA5D15E2D45E7316CD4B176D9DC7241B05922A682DF919B2D2DE2F45942D3AE254FA55C5D90B8DA3C7DFE2DD8381AEDCC9558566E8DF302022FEFE51F23AF6A018AAEF3C93FD608B0903376E193CB1C13021808ACD538D3426F9B3399686B6FF4DFC0A4552DEFE49D042BA76136719D62884D8B93A349C22E0320B823740DDB3794AD53312DA5608DABACF69767D76327BEA7A644A304A132F2D2FA8E7C8F4AFAC30E389A995C0A2F912E98447CB400FEAE35B3BE089F46CD48EC8E38D4F2BB44F1734C67D5125D7266AEE3E9D1E91F800ACF8038D43B6E10750DADF6CF70DE75176A2E9C340BCD2F6D87F976AFBCDAF5E35DA9B268D3AE1F0F8172A342CAF9602593A5ACDE03DDB482E80B825A7E91E8B0EFC1C8D00309BD170D9F12BF5017780A54F440A58BE4A5257AB67190C62DAF9332F3594303B419D44A38C3A8032E38599B49872D241AA44905CC851DDD0750D04815ED88711353DC2264C0302DAAF2FFD34E9716FDF8A81F7CCB5757913B380A68F153F62E0BA8335F8525CC3A20145C2416581612B9C29C0B1B941946B2624731FA50420716162C64AACFBF94B43B10E59E0AF3836A05B9335B0C44370CDD2E45BA817631FAFA2E0ADC801772F6F71860CC2623E1A802B370823D02442108E5C142B68CCC9CDD0BC2EB9B861D763C715D516540F19E70FB474E120F06BC19A6629E8DAF67556AC60D17C252A44901839143BE5EC76B834FF11DE13762EB23843D3FCF1FF9CEB41CB02DAC74ED6219288575FA294157E532BD877D1B711AF3B98CB0B4BD7286F88C6C00B6AD9E40D66F38525156A4AF35F2FD42A5F25A201C66DA4AB5C4D1517BD6CC9FD9764AE2756379D73C8D81CD044174860FEE5DC42B4576008F13A3504674E0D224A9F1AA780C3003B7856692676A5E581418C65BA9F049CA20C3EFA566315DA220E837639A899ED54A07B5741097C47FB90A81A41700BB5C0D8C3317E27A0A6CFA77292BE9186396BCDE5C654C565754DAD120719E571A4A14207CFD205BB4A66C02CB68EB9E50DA7B1FFC324AD07D8A8A54729621776FC5DF15CA39F3DEB6B810A735CAE0E1A84C6842E80D1CF95FDF5A6FDCD613C54DA1CCAB4994EBB81C632D192CA9AFD7FA662A865C6F193B7029A9B6F21041E3D13D50E5A1DA47D3D3C4B101488D2308954C801DBAE5029E866E869167BE7DCE6476A64FB245247A84E46B5F0D9FA9F7BB10756FDEA659788C032AC654CBB83F23BEA1F285DE190BBB5EC4135E8FA1B134DB5D1FFDA08C06682C2DCC51E0D848F8CAEEAF51DED21830730F6BACC2A4BACF7BA62D14B009116EF2D157F64A7ECBC971D50349712DDB0871D007B2FBF83A832416CFABA2B9CECD37207EB9DB8A017AC266A5FC28DFE64B52D0CD7FD7498F718B32804CF98D2F17D22C2957782DD83F4FDEFC8A6AC5B6A562C939D2D0A0FA6078F7E6B4C95159BEF010C1DF8448158BA29E1FD1AA076972E64A9D534B1F27930BADA08EB87BDE6FB0A691D4379DF0001D84F2F833050E18869F2FA7C00A6481E4F87C75483310949653D6B91FEF1116F25E5EB0A10C8C8723E9C1C80F75C2875FB0C448B3E25E7B359304C08C310148683E1D8391C432A8413057A7AF45289B1363EB203779550FE1F074D3B4CDB77B90700E3710D6EB4BD1FCC209F2406CAA67B98E44AC91B876762D597D0F03A404394AE81BEF8F54A1A898B2F0F0CC3D3B6D84D759D1F1C5788BFDC7657794E384ECB2D5307CD92F3E135F35720A44743D93D111F38791B60E7A64F51ECD6801DE0ABC356409D00D7F785EEB88FF3FDC801C94CD7972EE402217DF018958A79DFEE835B2E7C591D2604B83E2C8B3CEED7BED4DC66B66EA13BDA4FBF5DC3158035A279F57ECBBCACEE3FF346386ABE41D0DBB32E15B02C49D3F216DB19474D295AE0A8DADD1DBA9AECFA9C92F0429352B558F69AFC7070DE8D47032956A9978AC2F388DBBD63AAD776BFAE969EB990E72B7D74A0D2002CD3CC664E77E52"""), - TestUtils.hexDecode(""" -98b2f93395be5e131e0c5fb8a0792062513dd8be0e820804d26f937064f5c0bb3525d053e16da6567186dda337dff3c6f30c8cf96891ddbe0e15b349c03c6d53ea00c6ad4f6bebecf17b32a6b57c9ec32ab4397ec8062d9e8cec7e747a8d9fac7fdb897c43003780ad783874c2fcfec8a0d86ec519c07531a8f0008fd88395e44adff523568e526d190c65ba17b2bd7a383bb3f5df73cc2b646b40c49d2b87486a368d43e6d616e45ed0d9b3e772c7261faa5e5e68ceff3b6abf9ab7677949facd2690d6c88f8ffa3e05544603fed81516a829bd3d9bc55e53f85f31e98b01086c31995834d4fa0eb82ed75d3d510e4210ea4dd3cb8f2a8b446ea8283fb5cae01f7e733d3c60356bfb1411f8be5a6d0b6c20558f77e7c101e99419f94711a98b121fb7f953e0c19f91b3897baa245a62c7f3336fddd02358fc3d2672e9147dd3c7ea8cc3b1813ef8045fa37786c83f387731bc9e3e706468fc99a88917499d8603589e5d8b6d028d2dc2ffa4f03d6359bff057763ba7c106b4ff4dda55d9f1b71ded84896d844e44c9f3b1d174f368f220d7fb6dbe0d844f5b10c29d26ec169dbe54967e00f70fef69096bc8354a8bef7fe0be76e5f95758580c93ac8d9a349ceb388df4cc173f4bc2d1fe054ee7c649d238a656194bf77d5afac4a6115ec54278d17e93f73f9a4658a8f9f9820a31222f327613a2b66ab471132565f9dfe0388e622f784c7e09c0218603a17f83f246fb36a40f3b1d4e2a1bd2a49f388d3c4a7a06de761825b8ba7c580ac8c5ec6f44d371b43af52a62c31968155140e3903d0cbbd19397f80192e356e94523f7d4ecd4b2c55f7b88892fe94c0589a01807eaa594ff962ebad271a1f1998c517dcc3b98c5fc4d73b6efe16c4c45fbfbd18f5eb489ed9e1212bd07bce3e486c1264a595496401be6a914b2238d5f39f5b17a60886228e5e9b2d841cba626b26640edc619a444cfd036c54dc610a2102de9dfee18e18cf32a74245501cca7e49d987ef34f7a9adcdd3567e357244c012a7170b0d375be8a445e5b8752301d7ea633485974c30232fce5e6e9ea1be14f466d3a8241943872a1a881cd4ef436f1ead2ad9227143be6792406bd7c07d925091b51e5395cfbd30b8208eb6103a45fea3dcdd7ec9f478d303132705f3126942d19626d5009ed347db6e75e6a5f4f5651f72265f14a01fd48dbce38b2ebf162d25c4c3b0665a5bb30da9321f2cf070e16fe7b12f7ad39ea6b92755c4ff0d988ac561d310f6e492694ddd4c35c48c13d62848205ff97a58a12602c5575a1f755eb14e50f409b90924030ee3b58964f58dd8c600fb999bbd5daee8addbc185c52d7151bad1aef8d83a3a6d80137cea0f9b731249fcfa996b421b046b7cdebccd240b871a8dbd5bc072e69968f482538fb67b40d13f8bbd2341428d5a5d6bf50c19f89d54d239a0adea5bd89c12e548b69a19ccf9f9402316363aa7959fe3ab63f350f3fca1350b892ca634bda0b6656a44ef5995acee1f355fae403b7e05900cc4d6688bce46227c941400870a3e13bdf468646c828a39a072cbdb495c773fecddde1f37b1643802f565ecacfa1ccccc2a2829a68d9594af2cd44503ddfe823c8117f0cfde7c77397d7da69b37bb765e2e7dba9ab70e3b802a009f511bf762820a8c491c6c19ec72965508a82d199b34f17867be0669b4c792434e6e4e4c1efa395f1c4bd83a1414a51d71688544d57c2d5167a1929856076f7310c768a1919392171a57821109ac3e9b1bf7cef03088d98bd2dad5b0290072d7e5db27ae08e4bffe11d359dd5b58468e8d86d787c9adc8717986408b2d67c9e0e53cfebae82cb27f0919c62e89a68ac8903e80a7a11b7bd56ae232081af3146927271d3c2f2f7247a3def6de720917b014d6f03eb6ef9dceb771cabbc645f2cac7acc3f8d6dd40f6fd2bbe69ffcc5a083eb3a10993bbf6edb5872e001ef31e2a0e86ad58f6829c0f1f560fa7ef734de2e84857e3ef86cbbd0c1ef2fbcf282116297b5de572d10968edffa402de0ef9c4273f793598d94aef6e294d4ace8cccf70acd9f86ae774d15e9a1714ac761af94b446e4f0cde48748cc5db05ab4fd3bac0a1c43bb8f73a7ef7285866ff80fb41dc837a0f9d3ecf93ed0b79bcf6e94177d34084c597abd2fc46fdb4acd11d543f8c0b512efbf63ada213b2d955569da12b88b2d6605fc99c76ebef188881c7dd195e6ba6d5e55f1ca19202ac94c360d76d0359c3cb1f801414d97535313ab2ced2db1ecbbc3cb68e81988bff134138cc393b8ace18e20ee4e0f04c2206df124e4cc496c2acc185489cca0aa1f9848382a55d991fe5b1228f913ff81b7c564bc779ab311e9dcae58e7009eaa806896b1f7cb6718cbc8f8b6c4a65738a87e2338c6ffee4cdcc5ac060e0021a5836c45732cd668d2760de9597f719d26bdfd2403f795b8e7d52e657ae968d027b0da9e5e76d2fba34f1de7425b780bfe96c05f817dd8f0cfe176870201da00deb460d12a84f8bbc43c713793530062dc78e92dbde7a9f53e08259333253a42f5f7b1a7f35fb89e69efb700f7c6c465e80cf47efb8b396ae3455af4fa48b45a1fa87a110975cce3e92bc2394a456eab040c2fd333f70d8165e2b6431677fa28edc67dcae5f0aac65f879ca9c690648689c94d6f657065aaeed5dfae5658f4922439437c65a2ae5bb0853478178b890561a69a24bd0419e2a089ceb0196b232c45c7373938c51591ba527df1f21490883e62e99b0c4b914bc5e7be903824fc12da0654bb03d3c15261691db25a6f6fd53e3d4e9d8ece3d331f42d2c99e9f1fd9af4d68a361922b897ea6ab23d8c896208bcfa6f2c3b06ce3c88fb86994befac763586c2f0c37f55edba60286a764e4cccc5ff915739c510a5d45ead80d14465af87377ea019da46245597bb6af0918654596365f20c63c074c8a896e5b6efa0d2ba7318fb5a42c6eb52806ab9c6dd8f3b160900cd4d71be8262217b9877739e8344ec1a90511a23f38c5b5c2f23552743b953168de2bbb3a993691d0d87aa20cc70eda60839a20eb3ddcbd6abad31d3ea359938e76191507f298dcd7110e0ce6216bf9ffe2f361c8246a9299a1fed48aff683ec8475fabf36126ab166601981dab806616f38bb1bb93c335fbfa3b250e31560bc8d0dc53957da03da2f80cdf04764f2e9fa8e7d2f7a89724c74471d2bf713d4a4adfcb4cb178a492e64c1711761f9eb9d0e65e04b64f9b94f918f4ba6835f68aa523d147414531b925d3d9e7d315e1fdc533ee0c498e9f66bf813a25ff95873de22448924b36e6172a87d7adfffb9abc2bf2272c270b83cddece1cf189ff52e209dfb78b8a952142cb72c969c4ad7cff67b1ee5e5bb40caf0dd45cd37673908c430d0d776dc2519dc4984170ee7ca6365936369df16c4a094b86c1b3ed3d3cce82b2e56a5681c204e0acdd4a712b5cff260f4c27ea6c32e23c227dd8e1f8e99a67df32e7a24e0aed3dc9630b4b3331cfd625072c0024e96e79c4cf2ee92ea18a5e9182028d39b937029a4700d93deacdd4933cc31e93cb234214d334e1dfb5c323c964d90387ea4bccccd0e4386e4d770ea889aa480f0c8f828cd2185c18a49ce112c70d140e18d9aa6ca9ca2bfdc12003a63f67eb31f0699586ea8fb50d44fe9da2d01f0be10d6da99783821c07e892aa6fc6b190d9639d9249492c154b12e45e2009adcfa97b86650649599a9ebe07bbf8dc8d452071bc4f0e8203f81671e3bbe599c76589764c0c1923b141df67e260f7ff14752d7a84154dedad28c0bef90c9aaebf5d2b248e2e20a4ae9373e692bbbbd20c408f0ce99cd7435a4610fc51f051b1d17509a34d4804529a877828c0c263b19f84cc0b8d24b9910f6ad8006bb84e1a4c8eeba6e165efd50e5a444bc342bb8ebfea30385fc0c69f53d04286ca24c0a0a402668503bc94237daa53d1b41242a13050232772ac1b2c6ce9f6bcbb53ef6b94ff5d0c8294bd5a4b077c5ad5144b44a63ec630d84fa559ea329d0dc27dc7b8ba68a96777250244066cf1b8971261826d29f18bb34fc37a6a39e4870878eac95503dc5799dc8923a15a7c063f2e4f362294c1bde18d3289e67cc883f56ae5f56fe9ccc1e5101d67a552be55e06d54df6e97b49b33ca50ff15dfa8b7436e5ea540aea188dff17c3c657544d600fa5a3e7b783adc2065f05ddd72e65a69c7619a0bdd93c731afa3336d3e408e9bf09650b66026a6d691447db90e08800d2aa08fe312b5ed3ca2dee411bd17d7239f143259d697216e2f74d7980dc8ba3ef2ca2c95af10f36d9b28b1bb464155ffb6807e15facbad8b3ab23403bb9ae6546b183fbab7d4fe2fc507931fcfabbf868c6e21d23b0e02952db97e610b8857d84c777863f820978e29efc1d9c5ced05bb8e75b1246aaf401ff1d0d777ca6eb8d74c25821fd9a5dde41eb13d766c30345965553af361395076029184d32187e82dd7aeb73cc648893801441476a6b7a2914ab77063878d53a539f7774abd4fc9d19d5af3b143dddad76ba439466d646752b7ddadc708ac9a0751d9eb72559ab30043f41bd91fee7947106bc185f0406a7adcc2327517988aed2eb5bdde90e2779b5e3f6042757749da9c811162a93999f000000000000000000000000000000000000000000040c0f151c22""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -ab36c995c472d4212dacc8ea95f1ee25ec693ed8457bc6a62ed291a979b6a6e100ce9fd5dd70be6f21f54ef6648cb4882ed6eb92916a7ed3a4230ea9e92f8a3d03d7587ee6bedf6721f6d053cdbb9a487e2fe5604e0dfd0cbbe7679ddb1a4a27eed08d07da3e3e0c99fd7b3a50830effbf4502422264648ebdfd319664aa8c044f0a66e1ccce5a4b16cb7b180040b981191c751e684df289ed95f0974f82601aaf29dcc4d76ab93a3db4db5b4776cbff98fad420253968639c02b63da7f4659e9174c6abaf1c8e83f6b266a6df25bf52e3acfec600361ab92fee2590327e8879477e85d6f58349eab0ba292792ce6769affb157c05e79df66a498c4d312c55c292b7d6cf25d5030eab40eef294c36dbede934d32ca45a6a9fccc5cab367521c60fd1d79a7513812c9fc9698480a7d7a2add5afe1e24fbd2256b760c91f0cff0db3817ae4952ea7df13528987bfb441777a85d9e36df043a3182a07c410f4b6bc23b28bb860c6f0ea769db2848fd7b21459e08f10141b4fa63e52d92ded8fb54983bbcf1d854b87f4bf025fb5a0a09df89bd3f725da9bfdd413d1dc131d1ea5d54f899301c2c68afbff488a54122eae136cc38ac30b105273a8a1f89e115ca8a57b52e8b9fb1f85e4d126aa968d3125918355716a8ebab72e51e79678251f64f5d3daa326dbe96bf5bbc2f3f78659da5317773e379aa31457f446d84319da92caaef07d82d4c2a5cb2c6a03f1865be0fc1808862b46d30ee13c855237651844fc45a13162aecd01c56231e01507deedd06d432ef7ecfbe123cec60359df65bd276040eac6d7a4375a38bb62abb4e5121670d94f74b31f798459bd195006f8ed8b9319b572e74dc82842dbd403c0a8a63f7f7a2b2f48f71d13f96f37b0dbac0829ae5b6380d64cd468278642120442a59784ddccf85464e783f3d99a2dd613fc301521c0cd9d38488debaf36e47c93df341a50e4f1a68a2e615f91969f196e3f969f36119397fe59eb9332c2097d8e7501dfca1d1ea7499ea5f602cbbabf826a8b16cdae05a700f50212d62d781fd393fa238c83294b7ce60e0059523d6337b473bfdb80f9fb655533d3743984ffe028676519cb5d2a4a1a38f139a0c6c896ed9ca988e82c16c5088e8d15c2243bebff9c20ff059cbc91e93b29345f783658071f4be8277ac27c6a9d394749ac3edc77c9f3a93964e3463f075cd0b91dd6b5045fd6767447104e78cac5c0675533ca1deac92359d1fe0334902fa6f6619a52df272dd458552f1cc6f27c7c0274f49a2a80416b3a99d5666516cfc630f9c28280b3b522a93ba98ff91f08e8c1988e4aa32b965c59d8c8a6466912d351648065169ab873678ed25157a8dde08c1a2181e84d1aaf4f98bd5f3f7ed46f68ede8410c543e5a814305fc0cdbf82e416392600d29dbe2cded9938c086befd7d0adcbad5da5b4004b962109928ca5728fcc4ffb28e4fb337329217e31e61b99391a37340b990e4fff46303576899a383d663aa17cb212f98ee01276c071e84e6448d93513bd1ae775d448496f48508752732df8589e5dd030e1eb521ab986c4a3dd0f58269c3a74acc144396a6a83b9700d58c760d8b1af6325cd3f11136e45902283146c031589cde05c53568e14eb06e9cbe3e1c2ca20ba15226e6eda3ad9d274d86bfc8d3deebd0fb6b30da0aad3142d45ce40d8c531b928a5f7eda470f2ef443f790c649645264b35f1f1af690cc80b591d02281ca979f87a1e09c1b2ac16100178be5dcaba6ea4cc4a45dcc77f4d4f6f7be8fecba275047fb572c5ca4cadc7e3016959a16cdbd241b4adde01100ea0e3c7994b90a16e590f2aeb9de243be0614520d41a70fbce0ffd3c85a18be640cbdfcb1379318791f1cb50bf51175592c88edd4816833083f2b7b5554d59a23e4cbe712d2d49cc1a9f2208756f050f8120cead2cd8fac0e1f65ec5ad6ec0e06494217acff5219860233a65dbd3e2b1e20916137c0cf4518090ee4897b5fc90921279ec30cea06d116ccd8159403f3d2197ddd95c7e21a9ed25404a658c64437d98d9525cbbb223d91578257f0e63ba8f78c217f985390206e01acd31dda5cb260367cb68233b85e4bb72d82932538f50efcaa67f97284833f04058576656e770840ccb72f2157be55a6107b8ca27b12a6cabaf45e70ed6bdf077022bed277e1259e12255504777b0cd961a9d0cec2b985977893c43b6c22e4bacc99180eafbf1e59fc1532aba2ff9bb0418c80fc9d33ebb18531049ce73541fd96bc1c92d94da2e7105e2e2471eeecf32b1c51c1e00a9d3701b73b57b9e406d700ee4ed9738e0067ee58f2ed871252599e01315a168d452f496e8efb0ea455537806780f83d976e7e9b839590568f1f799f4c1282f00cbb571d934de2a610df4ccab317648ac384d32a5959ecad1f65f31932152a8a66aaf7acc9dd597db79c85a76f38ace97807fc0c8c759d1e58b9d4a061f62cb8826417ec7c7dd06608568bfa5d8333ba6ced03e9f06044218f19222ef5f79823b5e015f965ee9a17d25c09095cbcdbf08344f4d0129c44fcd509c8a76355aaa09cd726fd085f74b321069e53d151662fffa8bca2274fd35d84694fbaead2430652a60129f9173dd7877f01e21c50965895ece33bf904523e10765174a69986669ebf95d1515c605f1e38c34f83ee28aac1e362cc052ac558e1d5c9c24f20e447b12d25c81f75c4cb2f55a6f1522c21ab8bfe5c18f76b460ab41d202c47a9cc02b05c7ffb07"""), - TestUtils.hexDecode(""" -F55B1A381D9258CAC6DD7B5A57899867FB659A56873F31F815716075DBDD56D6D0D1480AE1242A17485AD259BDA2533CBECE28A906271A3E65FB5D48AAA124993738FDAAC65736230FA07EA27D96F372B90A16FF778D0ECD7C0F62174839B8C7FC50F0B0150D47D5CE9F3715F5964DC712A681626821EA27E912B80D2D04C346B67439CB5E06193B6D7F2161B4F8E0341D8F1C0C7F6E3B351C4EB62E48B555EF00EC0DD5CA6A572FB201D1A4570676A04000C382F4C332C34A0436B535CB3C3F2378682A982034E01211CFB23285395204ECF985F478686817A5F6FF4B694082B3032990597A8C3A85B7FB5C2C49694103811F754DF0434D09C1A5245BBA980D6EFCFC9BC63DD42362477537C6712ABDC952BAE377AE7EAF9FF0CE2E9EEE82FBEFC1CE56063293BE659624CCA0E23DD7EF4412DDB587CF3C5302CE5AFB39BA8613151A04491901DC30706B46EBD1B26D4ACA67587595100AC51770080FC32ED0DC109D525088A2579D8873C6929554C30BDD1E2A0A9797B1676A8CEB719F64A336FDDC3F95BD4A68F472F00C4778745203E1A7736764CEB94F33109AF197C98D94BA3F07E857A5B251858ED850E7E578057E833A2CF95D7505C4973B709CEE834A40F32CF07AD1861CD46CC4DAD37DE66F8037DF1B14CD88E62F81B9DEC286BE4968ABCDCE54F83C5E9E4FFA8144A5877D75FDF75A38ECF60DC180E9B72F256BCEEE087F5AFA5C6D779117070ADB4A671839E8032E55AC52E806C82AC16FCE76A659D6CBABBEC066782C4C068AD4FCD5EC425885A5CBC5A4BAB43D1A60D499C497A2DC06B136A971BE8ECEF3FA6606252029FE5B33661883608702542F7EF44720466D91FA1CFEEB9D8CEBBE4E252CBC096D99551BB90A0534D723B02146FEA94D1C1926221092B97F1A143E6B4D5A8438239B2E2842633A6D90A18DD67D05B2CB560BA8A964E0A49BC1987FF47895D664F92E27F8C90059C5C38B02B42D7A179A09B70023BF7D664A94F7289B29FEF89356BB51959FBB82562F6827CA2A3892E934A9F271282C204BC3C6B34C57882EEB552DEDC0644B43FB28284FDFC82A1148447F2457E94EC0437CB5E0E3B6AB7F7E48F0F53C80D7695801DBC0E96F9C00A4A96AF8D60676DC4A6A6D97CEA344D7E911BE7CC9CEBBB23C562BCEC6992AB1148384278D94913DC4BAC4F73313BF83CFA2591420B18429D1F88D68443B960F61A1AB8E2713794225DF2D4EF88CAACABF6F095DA88C52C011AB3A07D7B71CF209BC84DEDD7FF2D8FF02A0727196D50CFF6520602D9FCBE57F890D19EB7845C6529EE5CD98AA2FDFCF37FD7472D1491FC5267F1D7E6E91EE891D880D5EC20FFC761344BAB59A327F829ECFBF8E550208976BDCFB75BCD996599B68CB29B27D9EF68BC975DAE08AA121F4D95805EB89F2E8B2BFDC61058740881E9B403C54745CF6D4AA1747EBBA56473D00FCFC62B5F5DBA4209E0E7473A0A311619437D2DF22F1D5BABAE064970850CD51D4A62A51E9B3D3121B766632B18F8B7CDEF40B249812A6274D4C69C9EEC096044026022B1FF055A05B6BF1C919230723A952589F540E77D7D24A413F542E7E0D3F7F55B8B335CF3693603210E979718E8CBDF76CCED68396DEB561EE27E9008D7BDB428BB293E1A1BF2675D8A4568D3339682854BCF9E8820A084C94D78E5D0938D66676ACAAF7B411B466B6588E9E2B4A387D84F23963E252EF36A948F25625DCCE664281D76BB6EC1B8E20DB3A7140B194872DB439D89F18E74E1861E3CF9FD442F1CACF4FBFD16532BECBD97CC9A007978D17922A68CE98369240A8D1E8AAE6679CA5DB79D83EAC1A571D0871D5AA28F6EA4A8EB60770E8CC43A78E6BEBBD4FC63CAE26F297F1E21BCE999A509BDCDD20AC938E38702215C398726ABA5A7AB3F26DA34DB3CBD58A7882FED91C33803FAE62E9E69FAFBD698962F2C7226A641AA7B6CED1DA8A400992333EF5DAAC77B55F94D51F74226AC03F7ED8F3D567BEB678D98694E9E0D483815D080A70FCE76255C82FE020DDF32D4BB7B1AE0EC1679B3DAEF2C20FCD7D8F74F6FC684FB678F02DE6B53D03FB656A9B9562666F49797EC658C0E8ED14480A0532DB85478FC2AD1E21F8883F2EF3FD97DFD757D883C1507C44F812639711256EF56BF6F8FC4A73EC3AEA3099F6C2BE6B2380FF3AB7007129D4829103AFE70851917E02EC5F2117DE110FD8F4EA25FED6FBC24BA063B7ECF7585519132884FC12DE1BBEF498B92D6E2062F1A4F7C97FEE96BA87ABFAE76C50729AA68C8F374102B3CFBD69139491836E4587D0085F92FFE2A94B6A87AFE29C84D289293D9CB4A733F90389C96198E2250F5BDC83F123FCC4E42844DF74FCB65986CBAB77B692CA210AC22B5B56E30BEE2BDE84663B22507E00E0D066D5B1F5245EDFAC6D860D0493C218A541A1FCA4B48F1A916921153933383284BA268C3AB003CD58FA979A08BC48A57C755688B0859AF7F21061F9F1B7DA44088ECA4D393E8DFCCA52823FAB812AF36212CD137741C14F0860CBC7ACCE1FDA39431C32AFABB84989CEC971D4A257BDD70EC71192148824C17AF8F18816CA94C457E1023E01012A245F28FF6582C9015153DD7662E4321B465B33B1D5DCA9B1CE2FF49EA3A811B5852AF5C42FCE7FF42BCECD31C798C3B8F685AB50B68654192357CEE577F5CF1F85A50F269C28A1F2ABEA382AF5CD089C146B9473C8965A945091ECD1C02BDF64F9C3FFD035D8238AF974E7111BA4AB10288F105659C9E2847544FEC0B29B6692FB53CEA0DD312B24C1ED3CAA1BCFD94E529F6C27BDDBB7C764DC0161FCE578361E02E0F5F3FDB095B6CD311190466177A5FBA62BD18595DC49C29E8EC7E1F2F3FFCDF17D477F4AF8CA3EAC53B7018A026BC942EED87704108027753DF67BD36221E9121B49CD40E8EA7FA2D6961604BE0095099A4413DC11E93B4A876834776D144269BBBF8A9875648702B589ED4CCBAFDD726DE8E8A58AA5D1A6E142A470EC342BC3E2E1B49C7203F283E99E81E38F1D8D2CD820AC98D8244A705BFD9B67E771A0366C7C6958DCB6921A81C0C9D5152DA37CAA8CE18D6B97404B399052051D7343B3739610329A37B8BAAD173018708400AE02B8DB2A2414CD7DAF038F94714031B1D83A5A15DBA53585B606A13814F04FC925C3454E251CEECEABECD8CFBD6FC04F504508C04E25724807004612E2796987D34D04318F82F7E1FBA83A4DEE3C86FD1884B17E77231629F5D5D11CFDE976E639C60B436DD9D302C380E3654E671ED81D44FC595FA34EDF90710A6384BB62DE0D89B50C14A44215DD1121C602A79A003955D860C88470EFD320E8AFEEB114E547E50CE967572DF5A5C4DED09222FF7821F91598A0A9C41A731D64429AE7D9BCE1B4E90120BBF94EED78098C9EE30C38628297C86DF59930E72CA561A61B6EAE517DB39F5A61FBB8C1838E3ADAAB46187F0B5D09962A39955343631B74BBD17BB2E338E5FC8C43BF8B2DF3A78BED744A481A1D789721928962AF2B9E2187E6B52A19274EF68F329C83F42A28B49C447FE284A25B71FC95D9322E752E28C7B4B656A743CF6C56CEEB758E742CFBC4B8D8DE5465D63D3D5D6EE993A4C47AA72BF82126ED6C7423D3475AE098CE6A7E6DD6F3EFD654BFD5DC4414B8F23F9E29CB0D5DDFAA689BABC7B5A925AB19817226DCD242EE46B588D7CB8E88183CD87C6D06FA1A40915A3F19E2368CDD97A16ACC2DF4CBBC0B30C6289D7004A8B48EFE4186BC4D844EA01BA78E4D1F0CDD2648D0363CA73A19032A537F68E0AC01CE6701426A03E071A109D42EE5BF358445907E1D05761B8F41AC8A9CBE2657754A8C4D83A3516EA465D5AD57367BC58DC712A5C055F68D1CEAA494D9A845474F610BAAAA4CFC96EB51D41493930534D58533E20575B980F4379A80393DBF797969405D6A514AC0A9171B79D6EBC5B66ADED19821BFB090BF76FBF50CA6AE07CAAAFF584A7013A71D54A2B60678F6F02DA726E7448A2379C28BCE7DF968154CCD22F1CDDBF25D91C616234539731B8DF4F55E21F37B29BC77DB4BA802D9BE419ADC292105EAE58CC81A636D479B550D33D057B7AAAF28F743F7B8C17E26AB2A846AE08E804E5D4BAC09D11C736DB32F9DC9CEAD0442AB7B6AAA70633692959A36D6DAFACAF2D7027E5BF9562A93A1B35AEE5313C1E2015E65AB805850DCA7A65FFCAF14200E1EF0DD8F8F05A11126EB02C13FDE38F496E5EBFB09E9E2B4920E619A67517FA4749ACD8B0857C7EC5A6E94630CE3EA0841C64D2EB895A9EB7CE5E757F2FB80BB4F0FA429E779BBE314A491B2D45F9A79655396E70CCEB319C3B405C33BDC91EC2169C3A75C4F5CD7AE5AFD6CAF6C9F81A9223484E7A12512B600794351693E1111401F74E1439C99D77E8932E069193DF7562C79EEA22C41DEA4EAF9E93456378CDDD6C8AA97D8D69C222614E203B6A1FA6377A7A0CAEFE709C90CB91939BCFE926B35970B13A06FFECD44DD8A360AEB5D0432A532E8A3C275E1DC4A07D6A3E100B04AEDEF14A52C09AA90438D65C8E6141490BD1ABCAFDD5925ACB040A91A8E11D242521C1F00EDC14D62E1C6FCE721921DF42164B4B34203660DEF02677A6B8C564075865B030936F472CEFFB3446714AE18BA14A6E45247C9AE1F2836E2341B61940A63FCCFAAD809C84906FA0CB1863625E59B96CC2161A4715606DB12FE3E79C90B64CB9D3A93B451E1C746F6B820B4FB3B3521ADE56DF9D50136635F29EA908FFDB32C6582715B06487B391A36A6A7B96505FD8ECE767C38CA4D0F9599FDCC1BE27C9C60D9190139C4F02461A5C42310CBFD5CF506720C9A13067F83AA1FF66CDCDFDF59B673B6C1FB0301DB118F3F49D1BAB49069A9FBC2D653D390DAFC3CC5CB35F0E50EF4CA808DC69F0134E3EEE697597FE7E5C2A2CDC5ED4E81F344879A0536BE0076D7A351A199530C77C0AF25D5C7D5629641FC8A3567BCB1456C1AE1D216C1E408C3AD6CBC1629E14DD834819F94EE0D255AB1C61BC7C324445F67CB7BA0E5AC424EB9C3D5FABC47081752F98B0011AD389581B8C20333C2878367795E31F99FD2C082B04126A3A61273C94E894BA7ABD8C6FD743FB76CC4FFFBEA78A1CFBBD266DB4432ACEA74350AC06F2EC832BD71FB09481A045F7A17F22F9AB65CAE6782A2928147BCA3B521E001D4BACE5FF499B1462709525D64E72201D5620B5537DF7A3E8DBCCC6EB822129B7768469D18C891A60B948DE2C12F4E4DB574C6C8BC586A1B57E727853FBCDBB4EB148DB234D8759B2AC8ADA2FAD225B5420C2B93D7FEAF051B7B768E64BC6EB83688B5E7E59059E1079DC66C5D8696CE758B42AE75123CA0FB72438DB97D39F1340B2891A19A4084BAA1A5149FAA785F09300B9DADA3C45F19568226151382ADB16617D5E59FFE8029F0513A7156F67D9859A13C2BEA574BE10E319F1B69740CDB176A962810B8AA6C368805EFA56E4AF69E908A205DC41CFC3FE69E4A6BB7B1F541DFE0A0EC1B29E3C199EF07538BC8AD7B0BD31B6A4DBAF70B83443A9C6C06268F597A6D1BC50171ABF56D18BB277F83203BB671DE404FBC4DFC66EE8DD4D92FB1AB2ED20FE8E9327CB15CB90908F37171D10E759BB8D1BE2C895604F87E2307AF7720AF99F0552FB15229B0FE7B45A3005E6CB0DC88A6D15AC7C364189A84A6615A344FABF4D0DD82EAFD42892C86EFEE6E9F7C248462E4C6CCA369CED819AE94B3DC856A3412A0DB90353E6C6D9DFE31913C3249195A3EDF9F84BE94AC6EB82969AF272AB8802BA0E8967EC342834B8A38163C90431844DB073DEB60B388710FF880EFB8283648CDCD75615D35451D8AE4711C1D7DB1AA59675061004EF8164AF3B4095F0E2FFC5433BA41ED72AC2C683D3959C9D265C302E0FEE7258B7C870F62D40961AE5AC43D3BEF8241B38A574F75EC7CD608781EFC16B7B9D36C3844B6FBF477CAFBA155B91061"""), - TestUtils.hexDecode(""" -5bd74b9ad4b08f18b54784c7c6952152a4f597cee14d967851ae2d781f249d926ebb4f4490487d1ab299a179928f69811f39a8a019bd808c500010aa684ac9954aaa005c9319d75d6049ecd99ad4a3dd535d881e8eaea118635cc5dea0ff3d4a7d8bd9d2bd00b78777f6528b94cf8de6ecba3829e8fdbaaafec7a16106457f0204192d88bcc76271fa31718e6ab4be525b04e547f9774fa47a8e4a88a4fd9b058412f92b27a2e191d32f015ee31cad4321c62ca55e572cbb7c2872615e5a2924d7945f1ef161e407f415b4f963d4cf6272d954923da0db3b04649906ef6e2da18592227b2b301a36298861e793b88e7fd1de2957d8a92c727b492cde702ef2b123e9968774604b71323cc4e7e58114c3ec7b59c94d9a17453795f426f706d98235c99ac4b4288d894e480efa3dfd19b14872fcfea1836ca639fc7242a55a0d01e1e21301f39dcc9aa94d2d83bfdefc26cad8614406c70bb96c149ea652f66f8d26ee0455c6cdc8e648fb20886334d512fd940fef6d0d52a14fd9c33e0be6077a10b4729a8f6200ff5a5669b3b533d366b81cb6fab41dbb9dde1581e4f3bddbbbd5f18cc00123c82e9f82412b5fc8970b69bf2e68fd5fdd17b7288949e1a7a6eab8986ba2e7e2f98b5bf2a561ddbd935802fb59a20262a77137c99274f4597d070c0c7ab5eb82aa445fcc882b1dd0a825a1f0a2c8181bb6c608a53704b9d587e555d756333bea70a5e73ccc5ec20260c8ba150a44232aba5ed55f49281b0e697527a59e4cb579d27183921dd55492cfc2abe640e1aff9147927ca2a1d1ac594c52502536d1942fea6b3e52793e2a410fd6ca7dbea45a5a696695100f53b9fe1f28bbc0014ea9fa3b134f2cf0c0a2b0a74525468bccc4677e3959d62f2cff8119e5895211316b448451fee29720a74d0e09bfec52913b0a26d1a60e404b2c2ccd036d73a2cd4dfef3d9a10549287d70bcb561a3d466c8933668f69d2e3f1a90951ae4def67d49fd09dc61342a15d1d576ab41b7f145d73a99faabd04b9afbf8491a28c5483674e9f95f3e4146ea0d9b1ca61359c604b0c821a9cce85e53b5e666cf1786100fa4c4f14dfc178b63581bf502b7909c68e4587892188934c0472412667e552bd32184a306148019d56236fe38b03799c2a8c748c0b969d9d6de27a0b842be7580ec8e186c76eadfdfe4222628448abca620a246214d2629b2be13cfa9e9fa3c26c24b03da758d5870c4f79f68c3be2bf16f97a7459795e1e30d0706f33c4f865348785abc4e6feaaeff79b1b45527357d31ccf575785390c35b2a4c87cca14fe7bbbe6ba82d96cb9bd6f47d9ad73ea3b061e030bc03a670bec41615f86360a01a37a3ccc307e31aa6c32fd558d362142fd5668e948441275f265697e4700d87853b4d1b8f50c1c9eb96d05b96992daf7e9d3dc5b78a62867ebd7b901fc37ff34b67af0ece5fe7050c94a43ca96af0463ddeaebee931bfa9e14226b2c7bd40cc99cb7b3791bd57fbab3d4961fbcfa4d9fac748d73b2de0c7eff554699cee1a72b197d6ad5343aa72d7d0bcfe6c3b458d24e7e75d00a90628100d635f032f24834a3dd0ca0f5fa0d040b98ac6e0ad4a3c09445d91d929ffcd5424800bbf06a747c7a05eb87cebe5d64a383cd77a7cf3dcc80300927443692c50c7aa0d12e1482f071ac1d9acd625f6e8c59068f1a08eb163a11685c7699493cb28b1fcef193aa1151ae7519474629485b7e6fadf01f369f05a1c37d157be7560b38a59643ac997b18a16dfd211e23c1c02f936c773b8b3440115beac0fee20269302ba0ca35d0838799ab67bfcb300e89909e2fa63d83b035d855bee14c47d847ec7f7ed15bf16130ab8fb33eff281407f376b3fa4f6894e1681e6eb025be02de783b22680e6ba9c4646b88d91e18a48f751fbe168096bbbd16a2f4b2a13085158d55c5283a069362f83c9247b0c65639aa21405f343a19dc877843bb72e39e6cda5b7ea3f198cf59c9607e1c5f09bf8962bba657f609f4e9d3ca99cc58f6283689c9ca4d0c4f659831abd54e1f154b26d4b7a103d9ca6b6112cf5bdf0e70103c8147fa7f5223665f75bd153d9e5aa982ac475413083d9baf3cc20584c792ace31ca3c3ce87cc16fde69df770f717bf9b0f10a097595ae2bbab69dce06d1973b01ff9922d8199735d6e16dbf4e7b94493b1106fc938ed093eca657e173b107cf995a251e5b6b7c97daf07bbc2ff89f5f52121522d175ae97cec1e98183f646defd2b15cfa13107cca9ddd0cd9912a23b139f84a2265e35b7053cfb7be23b79f28fddc9e3190b0355d0922543ebff420493a9ee7bc1c18d36e2e76437404301180bd3695d7d059601e204f46da1c5224966fe6c099f0ebf6a2f8c61ccfecf12f9dd4f1a197138e013654280a7c5bd26ab1743e40d8971c8b6e4908113b84537a410faa756251faff8fc8bf0fe8d325dbe0c1a6f7e099535e08bfe584b232a36401d9340ce323eae8e8eb4fb3fb57687037b7b98c6ac8fd7d919b71beb9273f4234028ac2f034685c81e630d57a83162aec955bff545d8d0a9c24d4a023988890301ffd37af5824f59384f596a4c242fa8378ba2b09908c74c8144ef1a6a4ef0b9a6738f8ec52e114b9aea248a8d2d3733f71649222c8737764fb440c9f2972390d3d4ad7467cf238f48a0a299c891210a60deeea020e4b8a56d2b5fa61aec1b341044fabd4abda13c6e85fd70170d18295538bc8da2908c103a799448441c50250455f5481f7a4f6eef5792f97cabeaa99936557b0ca845bea86234c1de788cf2abc1f32a80b13573dc2b21b110fdddefead44d94f01ec772078b1175b0297b0b6de6d6097e8aa3e5278944fc9e7a884d3267632917bf56bb53dc074ea14a8dd6e6c1a73d9959a5d2ae385f5dba4b8447eb451dc441832a69c1c0a3ed41b0997878c966510dd500d61666827435b7dd7ccbd125f157a419ac5b614ba6d65438b6c99e4d8e5e6776809edafe8fa6a76e11f5f400975df6e6769f2c2c1ffe3d40482be08581d5e79088fbff8da514abbbca7b3ccfdfaa1915c373361a971ab7f5c1c09e9499592dccd610f14ed84db0a2be1c94e5bcda339e14ffb27af1ba66c7130f45942c687ce96ed553ad7776dd532ccbb0faf1aa41b7765023d56c9068d56c3c405b8b2890c4fa6bd79466a4a146657d9248d8a348bdcf41e3388993e8ff2be2fc8b8dae8d15269fdcc040f7e72872539205992444a4d19552ddc5e51b778c5b5786f2d7b79036b73e738d7200aafe96850887c44c982b0347c7646dbcbeb4b6b55971004ade87ff20adef58d3aadb40d320d43585e7e55da08344dcd9fd8345a2c612f656ae178c914b5662d088c3437a6e5928d3410cf65dbe2ad31f1fc3781d6a5006ca8136233814be8d655b94152ac70df8cfc6f9e9101f5b53cd5fd37176341e1eaf25f2fb477d1d212333ea200a5e9da88b19db4163a44cd4c9d3ee1af413fc6ccde64a9cedf21c8b8f113d62a63df2233f9a195aa67803d632ca873fa11069b5998c1200dbbdb9647a98acfb4e3229185b8c220a6079c72bd4645b04f32ffc85214bffd8ef2cf27d8459eea21069c13bfe052ef92a070e63d05c9a9a82699676ea5cad84e508d7e811073e17bf943516fd4512d53c7b3fccedcab36921945a19d0ec3d9303bd479a446ea1a5d5e4adc5a97b92db843b54de9498592c4859011bd4df412a6151bcaaa703fcd97e702d96b0ab14d7fb0ee225f8097c174b517ea051f8f8b8af47a75a93fab99ebfa84f8ba8dcc9c9927e24f6c99b66f34f86c2fdc88755154f06d9b1ff731411f35377e14d2375480b688108212f75d74695008a61fcd452b6dd23c4d910c409d9edb69d294a5bb46fbda29d6b31b24613e751b3aa8605046cdb449ba86f27d226e91757a242ec2e9d241aedcabca88269dbda5fe8e5d8bf4a4cf1bb1585f1166d36a388a47241245d0001e35a790d6d201a92f34ea315933c67aa26b4b22ffa7d87482c7a63b7544ab511644b9e95152998af887bdbbdeb6f2218f8936d5fa50686216e30db9686ff1e924c850cfa31ac950bba1cc1124a892fa1c40f62a99eb452a344f65a1410f500ab650f9e91244ce5e962caa13832df55c4b41f53509d13d1765063380b942a5d4e718b9fbdfdf31259b879614b2bcd5c7a637c0868abec9be94a132be2c62111e5f22f420630ca64031ee7f43df2f8709e9b200f0f459d9f0b4bfc370f6faebb0345da46aa11c975670cd94ade1781d56a3ccf2c0729a8238e9cfdb1ee2e575c524661d089f894a1502bde21465f430561a72b835a39a70c60d64f371affb8ea30849956b767a5ad7648be643e0071cf9f08e880f6926ae2fe97b8fd9ba02dfc965b3ef7c102eb207555f6037c634496fe8de5cc8ae0184b6df1201e8ebbabfabc4dee1df3a15a46414e5627c7b99982acf3fcc7806d0e8b9e9356f21f15366d6327a3fe4d332eb8ebd410407b1b57220ed702dba8783c1d7088e66ff9bea1af5794c964cc95c415b26598d39f448a428c575de927e7eb129539a267c3e9d2c7b844e80b1c396810f8b703c2f6f141339bbbd34938cc12ed634425b7d80829a9cb7c8d1f3050f1351587a898c92bda2e1e366b5cbec034750b2b8c4dc00000000000000000000000000000000000000080c16191d24""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -48862a8bc5235f5337a82329e949240dade33fc7d17ace18be0227ec719ac4f71fad5a97f5d2cdf1c20dd6ef13760d4e0a1fc9535aaec433e7cf198e9b538d0a4a6482d60a005b195667769b820f677dd046b2b21af2c092abb4852bd66cad25888946d501cfc431187b25f773911ffb9e82785ab72df779f415cd506e52ef5b1828e20bb1ed742fc434ab38f3129dd3c50bfd1db5dccab13f2328740c5fd9f48da27f3f13df19e576fde636ab53f3c4ebb08681e288cf42b8bcdabeb3dc6c6c4e1a43e88e63d4e3797d7e8ad84835000206ba20f003fc90cd41e8b0230a1d80320d1a14d4a04788094aa376b2cfa10b72c66764fdc83223c39f8876407a05a5307f7748339547ef844012b48bc11799e72e67f993c601c6bf9bee389af261cbd8d07532a9d53888c543293e66e9149d8ea8862f69213c3421cfa0c2f121b5145cf9c4278b8dcf8facb6c5249837cf7c67b41c491a3345ba1dd03e6721b63ba12953055d5572dda5e34c0af2bccc6c4a0f98484108caa81d595ca4b23dd797dc814e4d724763cf782a531791873941f9873d7f6c0ba62080059cf0c3eeeaf7f04cb0d21ffb7608d279dedad1fade567e9f4725a98f041fdef9370cf1a1680feba08bb8205bb95cb9aaa16b7d2a818c3c3fcdd5bebc63099b4c4eafeca407e16678f3f15cad13c11275d786c033dd6fd280e263c83651e094bdcf87499323d179a383cdcf99fb8953228ca51382f81fe110c20265639636dbf562bd51d6398eca94e02daa1699a72c8d9ad005c4f4e21bcf4d1d4d935d25d02e0a672d419307cf720f65e11f0f1c45a0222c4583d94072381e8d5cafb06debbc117bb4fecdee6161e2a72589ed6da1b17f3f1d3ee85fba69993a9a7e389969de31ec514c1dcdb7ea4f2a5046ce463fa79ca665280cbff802b611ffe9ec0d63324626a83ad99535ac565ab42f17802d8e6f1f72edd03344d865270e374dac7e4701357ffdf256b185065521084319edcb56a55cdb91ba16c6ac647c8bdd9739de7ca426544ac9c0c59cba79897420531e1e1858f715cada8ae69d48d95cea603ef3569b98dcdf3497d784929aa0428a190908f796bba2e88b809c21385dad8bc18a05736efdfba2a81cadc11d06774c1a976d42b11367dda0a7daeaa1a271a54217a38acf3bedfa756eccfeef5ca121e4ed57eb006a103c471b5a104554e2f66d93f0c7343d78a6ec02dddccc2aee0d045cc9426fe6fac1e87ac8b2bbd6aaed7022d36719cb2d5324a1ae7d58ed779d3b33a4226b2156863a2fae4dc53725217751757a25e487be29a2507dc078aa0c45fd275ba4cb0874b74cc77eb516fab1bdc83cfca42c77c23dee74bae46afcee27d99f3035c67ec00bfc9d55f5317890bb744c15c5e2c871298a76413795d3af7bbcadfad9d1bb14a2aea340a08aa26c1c29f297bd31e40c5be7020fe29fe6f2dfdc86197389ac2b67d8b78ec6943b561dad1cec3324e7d7809ab3f6dca3e0c3568fec588e70f3ecec53112f6e7d3505eea1892a4fde381a2b672db39971d27a6400058a4b72bb7c51648ee3acd8fb1bf0b85f44fd20fa0e217ee9b9b92dca1e3b68e50d8d7415d08eb4d711c1dd7cdb3f43c87d60e8af1f2a6722fbb50c9d242674937573d0d9fee8a3f16aa781a1bf5df9cf8541a00ad026c2a0be05b3113576b6b84365f2cfcb110760ce7ff47d2e152436c8cf245c8a54da42062e072f9f90a83c73be236fa45d26129ec0791bd91fb5c389abf9315e27a0535b26e761e4441bcfc2b3b9a5dc0509affc072886852afdbd0869e18ca80960e8eb3cb77b2bd635a59ab0990a2c32e905288928f8063084c3ec9b53d31231cfbfe06bf15c6500d10ee110817f42253ee753c57cf5871929d9b512ee557cb4f9b8fda70fc43d1aaa7584842c6729cba6253c70faaf15f322434f39eacc0fe52079aabc00693b49d73223ea9341fecbbf5fd70b09bb2b5fc4e7c638f63d4eb4113447f8afa3766e3d39b0c507413c488dcdb53e5ee20118446684daa4e3f74e4b2297077f301151b06879e6ca608af5759c7b1297af86543755290c341442c61fef8c4b04a8579c9f321f4b8bc744c1f9d8ce90534a5bf92d780a222b1d452193cc6c25ecb816a3f4edd4a3a961ace14577dc824baadb5bbd363b3a426d8161c463538c5a6b15a9108024f4bf64e32e1cfe96e44063b27917501c87f10a7524694473554dbbba8f29a572846e54a16e6fd895a15b106ede3aa5ceae9755bad27a09b0fe67c41e8ce9006ffae11abd1b9b3e359b65f4b6181fc8d8c512fc22662ce71890335d9811180e329553dfa037a8fb0053e669d5d870b0d2a5100c4bb78fd297520bbad94d67471741bcf2e1c2ca4f6304e35663399f67840cdeeb9edb621c8ba854de5c52f306cc3d42e1c081e1debc8021f972549b8a9cfa033c7901da060e17f982f6cd2f195c87614d8bb787cd1b10ed6d31c5d4d561c1bbabaed7ff626a312470fae5ef2e51a05972b905b9c5bc284d7053d0585f1a91bd403769e8cf9bde215229259c43e02323155b13b5fb0d542aa625c0d6628579929f7040644e91ce4fcd47a895bf3dde0d0097bb42647807d7008caca01304f403ca8f49cf5c11d276d115d000fb2f220718649fb73dd06ae38fead76e80c20932444cba2a4aeccedccb7a29d57214d72780e38921a0d50879a014f52ca2604df524bc5fd650fef98cfaa1eba14d7380ca1f6c303c0aeae7cb9cf0cc2e3acedd6f151d"""), - TestUtils.hexDecode(""" -DA2755DCE32D07B6D2C2DAD6BBF7CF5D4C26FF0C9B6FB9E064B51829A1ED51A712E26DF8047B487FF0755CBBA8FFB60DAC3C45E238608F48205A582BADF82C2E7E83D672057B9A9209386D2AB8D93BBDE0C522CD1BCF2AE95573749E0D51B85EA01494E3BD97D3CE0A61B26249E4BB94F9667D6556CC4313669409D94AA4F3BB9AB70F736D34245E2A789A5FE2917D5F4CBE43010C5215AF880118E1F5FD47A4C195F3C74307523C688AB76B7CCB157F75FFD79149B5508E7E527ABF718CE8E2E4162BF810F35E234F8CB65DE0930202C1896DDDE02BBBEC8D03BAA12AA1C91EE798FF7ECED608E3DDB7BD04A1DD9139F4A5613AABCF7AE495F9CE18D73BDA0C91583B72CCF6A722C319AD5B1051E65C1B91DD05AE5A77220BCC7576F9CBFC8A12CD55883AADCAD1AA109522F286B00B70C8E3D4C6EDDAE7E1752097C85233583BA0E1C05C5624FF65A3F3894158982B633EC92C24382AF48EB2DF5EAD30759E99D67B8BB1144939F4080DF0E1689AC0D4CDC73DF1CC2FB72B92D5A69019087294D5F2DB196CF82B7BBAF953F0568663596F78B5A309738BB294F7AA3FC5F3ED5BFD4768CCF3304C836B476458E14B233C156C8407636FDB3EBECF49B97C96C31F51353B79C378C6F47F1913E5B14A82DEB126D688133F9139C12C45BA24CC9C7E2C16A26329D463ECF59746F5A99C6B03896E851815EF36F499654E2764BB8BC60EBC821C4D0B4C363EEB7849332A9F1053A975B092AA3AAE33F06F760BA1D76DE07A1F48ADBEADFF1E17C34F9D69E409DC5AC83C296C402E042FDBFB0B6B4E023B15B318337B6A1CE69F1CD3D93FDD0FEB7AE259A41383939253C317DB949E3BEB9C8F7A79D083BFB46C50AC00D382C846B78FAAA7399ECB902CE8B73A1E89374B1DA65B0723C67B24899342DF13C07A0BFE3565CBEA5892F8979E404BA84847AF30BFC04D8EC77B1C5B9400CB97622E6D3360836639670BDDF4E9CF9FE3D6B98A5FDA42422DAD6C829B9E33F53686E2663D232162D3A78A7202EEFBFA4917BB8E89375279C96C9054C2570DC3D90DCCF0E418B69E6443C1B2540BAEBE022ED9A9620C030377C67FF4C186A59459DE7DB1ADFE2923C01D9B8D3AC940486052DB67EB67A257BE7AEE0D3C77BBFFD0FC7C94540F11DD96C5100463C27D65D3BB6B7D867590D573D1C1BEDCC0E8D122FE4FB82F1404CCD061DD7C3D15287F39CBCD2448DEFE1FB4ABA858DCE13F74414E1A8C41B730A1DFB45B859545811C2A9DA01C342A1F3C8B916F60B5E4802BE672C2BE31531DD9E7014E681A8AB1240B5E3D5C0D26E7040D4CE05F9017A32E1C760F466A8D7A68FAAD421B2E2D886BF0007858129DA2F6B92C4CACBC1786291D7C95A3F6A12483B750FAAF1DA03059F89C761641C0AAB21A05E78E1131B8F45C60BB5E8681086717B918BD4FBCFCA1BB5DDD740BE289D8DB1C24FE083B3DCF0E496B1941ECB7D51182F9CB9986CF3F04F0CA4E01C63EC879FD4A3D5619EA1085B1431FFC019286ACDF3B4AAB03D6265A7B18F24CC2815269681BD37263B44DCCA5CF6FAC2ABB1DE317118219A73095D1BDA10B66B6B55421F049B71E759DBE6154F1DB98A7E3FC877FA90217A242B21F39490F2116A2BE8067168F26439C8D1928255B5A50CE1ACCC222087536BC37806FFABA03B7E787B04C2C67C1B0BEAA871F39D3DAC2221AF44CC7089E520BADCFD840E5EE24AC53FCFF1E7D6AC26694CBC15B80E48B10C054E8DEB00AE387CEC9972A28448A6BE3A01D5EEA837703D2FCD1EB2521D444F900846F59074D715AEAA2F46E956365B7E67C5528841145C442E6FD7B3D7171BE05BF8BAA415260F645E2FBC93C46B9F94D2997929349B88C2FB1AC6743B73DE66B30B44E5DB3E07E0FE9713D9D7575EE4E40327A58DCEFBA0EE95E22D06FDFB720993EB134073A80A4F06F8303C7758DD37CD7236E5D80AAE2E9569834846E7F6C75051302486B2564A1D8D987D1A3648192A63EEF4C2D25AD41FAA02C9F227CC9F655A72CF7207ABBC66F9C822EEBDC89833757013776C11C310A22C226ECD33E5B0772AE2DE8B8E9A876650D4A57B863BCC6197261D7D06903D414AF0922312B7DE6D9E64F99509CAAB8D808DFC5F046BA2CE55817512535EDC2477D8462A1817E45D33B9D7390A11E30C3860CBE2C4B519812ABA3AF7050227759DF3B6FCD6D3EE5C60C1042DFCDD7880888A147AC47A282EC51D0DF664451E37D7C40672A27B965CDB805CECD3EEAE38A0AF4C2349FF39947659686D30B9ECBDADD80C9B06293FC4BD5E7A0E1E9E883D7A4EB05102CC1FE45F1C9BE23043BB458E6B8B6C1C187761004EEF59E398B1124B98B0EC0F7B29394418B38D8A3003ACB85D96CFA0C3C63B2ACFDC2BF5540D029A261243E06393253B2C3FE253A220DC7AE4BDE0AB4B386DECA15FA2A05465740B072FBB0C8E81663E320AE931A2DC7A627C805AD80819B9D12EC271D9D16736156195302C93490B4F85E8B4F5199CAF233974079A7AD590374C4E5589D0FC26F70FF2CE51FFB3E6742AD5BD9840F62F745C42D6085E46182FF73FD079BD2625338105FB39110B660F8C55D0830587671CC802AFF63FA7FCFB3BDF6D65B362CA0B68B31FB802E7870C3905B04B41440F549583EC87218DF6A0BE0E209807AF053CA121D704DC0C90A499D1742658BB096C776514C89F6B2D3FC7FBC4A38C10DDBD3C08F64AB076C9BA4C7BF24EBDCE9C82B1BCB8E55C4135976C878B95B6ED108C2031F4E53DBB19205A7109C50289C743818B90ACACFDEF20EE33F5C9A7142B5640F4D875122E0E5"""), - TestUtils.hexDecode(""" -1fb3b6053f9518cc51b4a20cb33d02a7abcf1cad4ae7806efe9fbf8652e3755275a641f27879f163a1b265e886a1b21b129d48807bc4933df0cfee53f26305170c547145f3ff67fc6f317c5ffcd94f96fcc4453ac3fce38cbe41b6dc01c2146ea3d1e7a0bf001be3136362d75aa2785efafce667640dafb1b39d555a106b8cea129c5432867e0eaa493c43d21ab388aff1b6037621c1f134adab6093ee7e5760e9f33a0d8e8c63cd70c86438d3f94461a2d4bc9f41243e362bdfb4c809fb28157a6e5ab2f5c6e16a7336cdc4183ac4272920485fe34fe03057ae7b1440aaf99f28ba89ef1b0021cd863ba36e8deea60aa14cc7f2dab46dc401f12f5b61fb82a195781e337c195160fc474e52aecf4c6ff277908c481d51adac39219b29fa7ac703027354491b869e3ec404b4c35b214196822828079ec85ed0edefa0ed2a426ab9bf4c3784238390e8eec61cf7fa1c4a1ea1308e0815202f1109250fdcf69309ef634c4f0b134ad6d33ccb4a5e30c0472bd292c42de895de1c5989922bba6004283fd1376a0a263ebf74e414da5c058ed9788a862408de4de14b54d2adc7fb5e36f827f53b779e549698c8ae7fe4eccbca4b41b81e7239114720147851f0a72cd3183e33c6e82c557a5eecd4d07a824c6ea653168bdaac37a444fb63b29cbc35bdba265c5718421dc104206d224ef985992786180627df4b2f3ec5e6c200c2e0cbb6fad82db3f54d67f5fa7a9d1396c3b8376b3d83af731fbe8eed49bcd99e4fb693c87e259f20f61a6d67c8d87c967d65d03fe81e5d5f14021f8deb4d1a5d25902065e4ef707205a8159f02b4469be4c2094aa73580572a3568481f63e470bc86cfdf7b809c17801918f2a6f742892aaf696e2cbd2bc617f92efc482dc6bf8640a91582e988112cdb6161a41ab879e8c3c15e48bc2a7dd6b4fd25b5e7efd7388e6f3959bbafe518db3b73df504a6f6cbc6086ff160b3e7391845c9797a494000a23a9488008a595334b7b92db4b2f9a267869ee63b8d3b83bce7d57b9018bbc858943f0c7e8fe0c94cd0718672e4473692a2809423b2df248b2e61dea545b2f1db86b7246a345ec591083f4662b64664bc9200c3ae8ce7006cd795cc146aac8315129d62eb20e940aac6430165476742a19c17d906c3fd94a543b453a2f5d3c880ae6a1f64125efef20d7a0091e4bd66801fab9f7a396c84c4ed28526fc1b0042d4245d3f57731d56165e26e1ee72976cdc40b3574801255709cadd4361e7984527e6b9168a8f1b507b1a3f94d20b76bd4a0fd5ec81274207df86ef1b18c09e4f77d0670534a6ac9eaf076052d6d037ec469ab453404749c3c15cceef412a87301cd438c1e5c8d016a2c125a296c4deb4a12b4bf04d9593bd9d66814dff60549ec0a91acc5bb00a2f445c7989af4d3ba9d35868f7fd8a3687495f2580780f8a4c3e9f012f0cd07cfdd7e513c9a84bbf7dffdbe2934480ad3cb241a155248e9c30ba5f5d1574d73488beb96ae47913ef87530dbc9c941bcadc6a69b9acb06be7ceffd8cc7745a4fcf978c1fa126a22864e912e9c14fa73914ab1b9ff31988e6c859bf069bd1f912766680111d9996ce8565704046ceb64610f0c6162f74de87be26889ba868eaa8e3fd8c1c4eac20deba9467f4fe5427c06192a5ef0e84d2a063532131a366ba13b48a3735b7ac98d5d800f6ec7cb5b8bd604f7d3c72dc56e126ae14cb101afc3f5832fed4e94e5e7614e1232e970597997cfb3b9e6c5bba771552c38c9d6729ba0ffc2bd146754a3605c64718e9744e4f7c1ea184c477de17208f7baa9ba1913598889ac44b1d30f5b81aaa06a42c8f31c889737a8d15e6d473e0eb16fcb57a56f2fa9169a56a4d5b687b50e77bff964522f14530608fcb7f405cb5faf36ff235869b99b08765fbc6e21c91833a5c5e6e85aaac997fee4e800dab3c8fd5b35e1cd639931690f656f05b325ed80bccff2013c683b0419b5f43c3c14c245e40f537b55d20165a92e7b6bf8af9c81cb4b205f327b946c39a0ff087915b015c77930f221bb6c2c8d6500a521ea549f2d7fdb4108aed7a5aa6217450e238f1727535b3635f7e1b15b583743ffc9a2436e99c8f6e2a46bce90434f345090a76c422d778ebd3d9f4364af2c89d1353d64ec72d691d414f56c7a1747c7ea3ee8b284d3aa6612fcd30a08eb7eafc3dd42f221200fd0b394c99235ecebac79fe467c747b3ed5c09ebbbee5dc240287cceefe186f0a5b5f4fbddb0675f0159c750d715d0b01978cdd4e85ba77cae57024c6e6348155071016a96575e5f9b227c87e82db0a8470124b6572da0cbf2cab372d85708adadb04165b6cbe6950253e2c1034537ade941ab6633c1ee634371764ded5c131cd57eb9d3a794a2d26750d01498214ec9b78ba4c9400cbf7b910643a6ee5fb12fe1f2cb348d566e63dba6c1fddca6a0a6644eb7187a53d0b5d8bee99d31b92981fd81cad326a8c107abafb623a0d11e861177a58f1e3307fde29d63a3924bbeb0e946bf7f667599b92d98ab6af9d896e2ede95ca65cdc98b07456bdd037aafdc4c91bd387204ba7ea14dfe387430d290ada9a8296198e89b746f0264ef95c45ef3748bb9806f24a61565624fa84326594a572c701602c7317fdfa1990426ef70a5d3434e7b1ffd779e13b23bea25d63dbd7d9fcb713bca6c203d1b2f337a6e768ff8d5a1b1fed4d69f973f0e0a59f3c3527c30a1942054d3cfd04443d4611259b63c14f8eff56d17465e29a824afe408168acb215b5bb0252bb7c705280cc003311303373f30074bfa769676ec7a48df2d9f68fdb043b035fc1807fe7457e01e794a5130a857c56e92a8dc234f03c5c7fddf0f385f63b4ee438a2ed5a027af36eadab17dbd7eb9eb541e6ed5af00e1415622b083855f23d1c4639dc7c5b95c71673a2580e88092e446c29236900f685219aabdd06720f0e50dfca6bdf53c09ab3477833bb835304ffc65f1d6513acee999682bb70665806deb596566ac785afebd6ae7227ea882941257ebb10809923ae562cb34be2acde2b8b0de3f2a8b81c53d47a80a3b1d360c9cce2b484cc5dc62b948a6f990aec5d9c34b745943ba361e14de27232dadf5c72ad2f47e24d0872b2517843f3c43d1f348fdcb5fb589c4b304ddacd5451771ab0c53c03a33dcfd13e2720ddbca5fcd3f112eb81ad6bc1aa059e2261d7cfeab30fccb952a0254d92ab6c884ebe18c878adeee97721267393bfc85a5a4ebb7327c6f69a71a864e8fed0665b0ef302f16ca3d6ae033bbdb9443bc40c78eb7b3c5af66ba91ecd852e4682ae25575cd7d09adb3b74798d14bffca4f5bd837e80afbd77510ee78c32ee219f4156076dc6bc9ce87971e232aa4d034366a3e079e21cd17ce42c3f60f47225ec2407147bfe01eace5552956e6697a0a64eaa3b02ced7a39d1a1c2eefee96c2f8bd2c122ddb0960929e57247fa3a85fca43f63de635ad5d4fad02565aeb7f00db0c55c5552fcbbe5889b6495c59541a77a8dd20503cdf916b3bfc8f5e87b217134f2fc7a6cd13a736059348b3106bc431d929c09d4d6c0e39a93759953ed35f1df0ee90366e73cf0ddaa03bd39293e95929cefe9cfd06079b592b42c6e9f47ad6c4263233123092155047ee7c48e3e4e62f531d3810011a76f477a8650bbd7be790606775e1f932dba57e5d4bb2b2401a01a20b83b69ed97bf1ad8c765c93d8d4e1bdce3a524eebd6e54734d568711804d4da19fc69997129876d235fe53c78408e78081da0edb8d9c085c863c6603c06b8eec7733dd5713d79830b8debcf6d3e9183852502fc9bce62e85c20cc098cfce099d0a810df722d67932c2e3fbaef6efabbb67a83afd4cf9514598f316b72551abff34d1d13c93dc679bb58868148fbd33628d8279fee785dcc605073a000473e8ea9dd6646242ca2dc3c4863de1d0f8ad955682a9ba9fe52317c2e5d130892d5b6dbc41bd0ff3148308393d717ac0e96fc1f45e0539bb55eb50549e508da7db93d68f1711342a9d6ab64e178f55cd6eed8e8c28a497336fdee128df52ec475e46cefe3651ab9935ade5adf0b29ba5358d35d3b6516c8d3996aff1e2cd06363de48eab1bd00120a0d407b092870c2e76b276c70d4d7ac85366f60f2343241200253f92de66b037fae4fdeb1db275b7ae6ec196902ac69e9783fa6684584dc9067c7cd4a68405e0aeb2a4eddca1959cf788c0a516eb94f0824120ea24b9fa2354028afedbafff79917820d4d15b12def7f9efe49899c715c7b500f70980a8c799b93db838ca2859a06cdbdd5f84ced9987e1dbbf74ecf24d5f2484950dcd57347da8b8aece55d4afc7adcb0b232082157b0bbd455ca7ebcd0ebf257b184b3eb0d1ef736dc7d02681624622947c4f31f0dec5b430616a19b1300427495088898be15f27cbc4688ad4a93fa208ea20bed26e94984525db33a34b7631018e55d1b8ec54dc75c85e0c9a95c4f212092801e1578ea2e1a8a7850952a1bbd2642d7328a558c0fba8c167eb38d105d31be1cc497460fdc3973b7f004f1aa58fab493d29501e09568b3fdd7b1c8447cf154bf57356fca7c412c79417dc20e2d34485e6c757aacb1d7ec1c6d7bd97374b2c2d0132f6e749fa2b7eaf3ff2b385c6df71c232458babc000000000000000000000000000c10151f242a""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -4253129ba04cd46ebdd117f477bae35bdc6eede60df6a94a580b28abcf8bca385164de3e24f7792faf3d87c7eefe208adcca6f711f57d4860bd6df7f3950fdde40ca14784f71a397f300730072cb47d82ebe5c2360b09201e54b0e371efea2f1602ce195786dbcbd291a787e9fad05bcc548c4a8149d69b1b600f1111984774aff6083ba2dc1d1aee5d0d34483f9bf970229d87c858159225c3bb28b406f060dcd62f95770c78fba88f99e27093908cfee69b3d71a12f2d165bc8ed692209989f37c6bfc194a1ed596a38c4dfd284d734777864199cffd431d2479b24b3d77d6f33d92b684685e04dca571ca860f757c6cbadf7b1a96bcaaa2d349fdb057e066c613ea88c59c656ca5c10f521fa8bd770d982d7f042701146e16434dfd174a7ffa4efbe5845b6640763ae0b8df89e19beb0f3b21dde514da0693dfb0918ea8778ae0bb668b306a842b9c058aa8b3d3128fd468e4cd88e76e6f7cf737f85a36d52a1a8f3e185c455f57ad8fa5b1ca0e8ddc6548dbb6b217d1aed1e3fd82a335b8a41f2276c07bf9b08d2dd4e56ff71e22a66c7727f0a6a354c4c97826c9226b3de7931c252d11e098279f5a2b81117cfebc677ed05a2a81a0d74382ace17dc6a42e98df023115e03412b55a0e9edb4f1c7ea91841678c5c5cabaddd8fa57b5f1a5c1570ec341628d2f56268fe48ec9ad88f0cfe1a0b546bd10da7d81c39036c6a852841b8e060da573c61983502aa36e2874127f6f2c3461c7bf96119dbc5e1ebce6f33aa62eda8c7363aa842cc21cbbf2c1151d009226ed4f1b3afa65b06818805e41e7e2e63ef2a816f1d88f53f80963e9918136f84b1114bd2472c351816c4770722d797b6ed610526f8f27642d13bd31eeed3f8bd5cde13edc38c5d288e190fc7eeb5603ecccbf2e97ac9222cc7531dd1736cc6e93abfcc5386d1ba9f7143bfd369ca09f5b959e7700805597dae9eeb54194817c1b29d7f0519c39282b4ce257b191a1dc287ede4bde95f22c3f3b49c33a2f939c9dae34375ccb3d8995b3ad06af98d5b7370ffb863dc321c12d49bb94597ce00ba560ee60ad72cce2567c06f1d3fb5e277d252b6fdd2e291cf57438a015ea85b4977bb4766b3e439be35576718ed67a0ece1b590967082d6b813add2790d59ea20b088d30da760fc054f9d0d798c2c477d81a3d0bdc2197b74d41a9be185048c7497e8397b6881b5acf15090661651cd27f5ce524b326301221c06233f49396781dbc25f72caac8f26dcb17833647a4c704e4b1adf084bad42e041af26af4bfd75182fbafe5e6450a774548ef7f3ced7f4ce107f4c0e4044cf55f8f7d5e09974c79e36a85a6e7caf60b3693745ec9e09b047c7de351074ab58cbba84b0d93460086770d7f59d5e1b6291cb44a62e90ff7732b0d7d1e238ebbaa9dc8328012e1520e6a36ec864a769cbf39788db9a95a78e2d29f40b673cde57490ffbc36f973e7b13f0bbc977e43dd16716ca23fb865ba1b7c8b02d5323c166275472e90e6c72de1f08101084012706309c4aaa95c7b5c4165e7731782b508b085b825f2dfbb5017da0066a7b17fd22b7b71f9cfbb799589b633dd6de11f156d7aa0ce4278415b6a0f896e33e055f40e4c9f5fe63e72cc0d623100137a4cc43e90776d58ecd533fa1fadd505f416b65d528a209d29af23e268d420e67627f88fca6b019115cfc5d4731f793c9a7b7c8627e801d2644425e8cb2735361d4fb7866a460dc12cec76a4d82f1c2c0174b585b6a51f5aeae8e90c0d17c02f85ca2548ba685b1b04031fc82a12b55b00fad79e494f6285708502e3e387387e8ccbafe1907f33aebcf2662a4ee6097aff44a9117b3fb14403eeb36dd779782341527d59f5e7ae04f18a242c907927e27d32c46b5f0f6e2f097ae2f5f817dd66b6ed80c7d97aa3828de63df8975c4e83dd69d30fbca2164c61dea8d1c553c20afb3061ee242d33dc5c53fb0045c07d837ed97c77756b7fccb948dc89bb4221405f7d65388d62a52139b1b489afc181ee209ad37afb879488e14e286005dd4b3459722c5f2234cd5125b627ac46716d5f0e92712da986e95dc8d22fe9681645e9d7d2ed93fc223aebeeed8b1bbfdfde8c932a3052b6e45f49f85ee1561e455e96f6dafbb9fb89f2a64631e0757172172099a8b9e43965f014684b527576c72f6cb5b7d84df202830989d4ebc1160ff9e170f6b36d7136621611c725758b1e5713d99732014e6ae2b6b30c1ad4ed1d529fc3e4db71b16c03b0d12ef8f2fd2d5f9a2a3c369d4250472e5fc8d8987f9334a5b54adbef49ba79bc9e2249e2a2b726a354b596a957e17e03e4f3dd7562f6f7c3d8f8ed1f93b026d4f77e14cac27fdc6f5e567ddd8ac4ad88aba3b418bf03041ef47f4ee2e29ae4bcb0c4d0a40cec26a808d4e9a8fe90d4df0c2aecb9c713b55220306b4bf58b0373e7450388922f2ff2adda092a11127f6442a8e358914b9a9eb48196e3ffd9dbaa66c9730682b84c048a4023dd220b80d7cb185cf35e21369eed4e92d3c0ad70a33c409aa20402a2f0856f87e562befabc8ae292d720686c2ba269847ca0f1878e43056ad20807d1433e7e1e6c0f97bfcb6775505f581ff8dbeb4d11ba1a8343c517e472b631e6c325df855ba0a8b0a7b1cd21767375a34f60c61a72667e8bf2594c6f21eaead5efd2159a3a116a8dec925cafe3adbc050bde5a64292f18f0ae2a38a2206f33782b51407104a733f31b4922c531f6f6b57a626d97239e698"""), - TestUtils.hexDecode(""" -5870BB288AA6130708F7BBAD9FBDD6D41E249D620495ACFE90C61737B57DBA890213D4741718545CCD8B3FFFC2DB33C39AD631D5B5CC902DE4D340DF03E09248F67E89D28071AA50FA532E94C391D2D1A61B1847C6B1088BE555E5C2694EB0FC1F029095ACD9DEB21EF886BE577682CA96AA2EB3DCB24B871336AC5F23C8488011860B455B687BD4CEF5FA11381BC292B4098BB2CFC1822B48ECFD28AEADA71809BFDA190836D3215CFE755FDD9374115E5A0CCAE15240EBA0147C2F89D8D24454D7A5AC2D20ECC0D46C040FAD233FC51C870080F1FCEFAE6C073AF5F7A78D610E23831D5990985FDBFDC6D101ACF3DB0A74D71739E0"""), - TestUtils.hexDecode(""" -4211c0fbcd62764b125a8c5263404d7848a1812dad1056f3368817cab3cdc97f852487ff9d2bf404029ae58f9ddba2fcf1cf5006568c2f424aa647b4024ef30a1ac57d831cb0eeb85414d3b9069918d92e0fd933b640f0a6a777637245081aa0d27b2fbca9deb27ca1d1338189124269a14120101f0fc279ecedaab6b5006ca4c7c0baee72c5d44f4c330c56bb4a822ffd3e9c3f2602ada56da71ff40a712f115cbb4bcfc484b9e778bde49ed7df2d9f233ce065d1a9b3eca2c494fb8b7ff6b35d64ce62ca335c27a3c157c801ee1988dd9c7d0cb0b6d9c2295b17f88ca760496dbdc9f68910fa07e48986bab423f9059ed8d4ce90b8d1943d1231c8442dff36a63d28e667bfd075a66a7d729a2d852e89d8f580ae18d6652d8c06e02bcdd48970a658ff1293b6eef87108f9192e65001a21bb2e5dbe932a524cd0a44155e52ed18e1f09b9c5d46483774b49a6559fa78377442c9652b879597b0569cb791731007d556a6a26efcb57910692925f041d4d55a71c7a221f52cc578df50d0b5176a262250f55bfa3abefafef82d31d1af2facb5b6d46c554f67d27a143fe7ad83d4529183a02594b584baf860c1141d50ec50db36ab24adf208289635a7106c3b0bfcf48c6ab881b75f379779fed7f1dac26a4698d1ab9334f88ffcbf9a96eff8e85b34a6ae4d2228b7ba474bb2bf32706ae6d35409477269baf4a8effd70f98fe8aa791bc49b7fda540d80d31d699508d3f9a502f90ced18fd6512aa02a22d941acd43e3ff4fc802f05da84ce5c367f9497e165ed4c5de86fd284e0c181a2cbd1f16b66bd3221fd07e368b1e00193020162ab47e61d05f54be7354b497cf7b6e8d77b932eb0f8161cd015c089ae62d604b647193819b21171c1f493bf0fc7f67407045f56e022ed791c17606633967986c9d93219b7db49f3ba21ccfd1bedaf84315a770d978ab657ec5d4e3e39d8de6a163ed199b5d713d206c9eaaaca1ec4415b015aed58797e4e116b366081825dfa54c25759212f4485eec2cef8f455109e893b4732b437c301db78978831edc4154a1be9972d4facf9137e59e2b04b89fce1b6cecbbdba092518d1d78d7086e55125e22edbdf53dbc67f38eabbe9e76c69554fab97dbb290192f1a5c66384a062c974df996b618fa8478fbdd0e30f11549040643d583ad80480c1fd0106c1f2367cf2ab8eeb641917381815b064905ed6e900b7be712d3ccdb0b1004ad33bb6e8a34b94c228940afa09623c85e490c32023e157b451f02aa6017c1656ae1dbb4e795aba6198e6b6abf66874acd91ea4028e3a9e1b68321fb6e707a72443a0a4749ca460cfc0422c7c6b2d322ace8b51270514d0fbe36d6dee137a89d32e2d55610a60dec2266fd7218ca4d925f15a7c84edeaefe84cfe9a1d672b551f5f2e32308d0a456d59c26b7a1689ffb0a3e4817c5e385a0f4658868814272451015ace5bce4150306621cf53e232cedd3dae72eb1a240e625de8556f5cbee438cbd913b3cd744146228535ea23f310379ab18c24ceebb685d0f61e5c81a2c3c9b4f4a7a533a49c8ef32ad14f2e77e210eaf1eed44cd6c845aeb78c63d7c12c6e5f91b59489fdcf68c4c0948a858933604033209a9d5a2bfb68b101f604f6f10bd9703fb9768c2aebca6ed5b00e4974bb348da101f7f2653d55decfd624a7d79c13c05a7da0ea3211f7bdcf7bf1df8d21ab5f4130f67d5576a4c8a927b7c7890fcf42e1a431c0befa7b86a5c56b283ec96a2f27309ed629b8bbacd4eeef278d7775d1c5ec5bd331cf622298a343cd473b905abd0904803d72bd2463d9a88cc11d62068f0d7fba61781fbbdea6842bcc58385c4f3493ceaf5d105a2ec7764030961546d89a8aa5252c117611c8313ee2d7c96cfa76b1f3daa4e9c885b2d271781c654b52ae904f5ddb3d58335dd81e2e6202925268eff4a6676b80f9042c1e1971fe8a9d6b7c8d88ea282e1696c70619a1baa29584c0acd26967b4dd0252fdc8dfb645a255d32b6065951e7c3da633b92017bf381f1788cdc24b205dd6a7db1335440d62d81ae8afbf2640162cb92095270a8ccd65ddf5fb667fe2b5d33fb1bc5014a6af35cc4e4232fe052014cf4bf2ad9b46684704532f33a0f165473ed2850293f6bad8fa8cac3d74a995b02980fe5275aefa92374719e218185a5d62a6347f64f9e64ee8d06cd9d509294f18542d432ee24177a0af0d2374b5e29735abec655bc4aa1eccb6b8c6cd5d0602b8de15ecf20dfb64f5b0b57cd4bf2e88495da925e98f46799d344c070d95e7527ee7d2bc1e5da7e7e857b2c3c91489d188b4b43477082773c95479290b13779c25682dea8fbe6c8d7cab9b07342894eea86e708d1e1e7f3ed998df17cd752e947e5d2cf4b4c3fb9adc9049bdbed6badc20124a694dcff1deab7a33fc3f7c8a9c7fda5ef59ba4ed3f3ee925aab58cc74b789103500aface7eb0311a90c13b1740a54541e95ed0982c9409800f89c9519ebe0f1f8017d639ea1f9cf33a70633ebe2abcaad745ef5edbbd50442265b477a2eb61e89054d50c8956e6e2743c23a387d316cc5d0b02182989c1f01580b597e0a9f578d3a3aa6d5f0ac1534497c5e8312055e434c7719567be933cf6d213be58ac37527999a9260e7a0850cab48097fd68175d24c6f1b1ad8e104b3578e4fe746621a50bbac09fcc3a0951cc968d708bbeea3e7437bc269416d826e8ffa279b755abff5bfca14e90d791ae0357d45a301d166c19dee82f2c2e6035895b294f0ef30d003c60422f78178c5305996363dc281f8627ac75bcbd28c2a7e1ca918d438c88cfaa57766a372513615592861b9872ad6fc4639e885bf03e32820a49687e0df3598b45a2f81e33fed4e91b9bb458fb55ca35d99351b20dbde76038188f01935c261f07b4287aef1158a5e2db5fb136446cf1ac6bc8265f84a1314f41cf40e283ec5da03269307a31cbc5a3a80b723b63c0366febd211a0a448604bd7e56d4d5d9a7e6d8a1247f098f01bab54f27e598fbe6483744e3bee936adbe1fa4869ed81931cd1d7b4f9ee02ede169104f910cb6dc75e10358e1ddb3f2a661595eb44cb851c53c3f2835f5434ed0945a354483203564d3377e78e3959b93244e836ed4475f82fc829946037bfe7300742203d35d55cbb5c18eff04f30bb9ff99ff1b45858d5a46774088bf295ccb5e03792779dea64d4318f800e10029995e3bd7cae442a8d9ab8cde1a26c1de7aea6a9a70bc16597e54e93729fe27d938b205a0edae98eb80c95e6ac8770f5a2db81bf1fef6fe3063e4681751e9003db29209d1f84851a0afcf62eb0e6605fa69da74650cbc4fd7347743075d9cca143a8084c15d4372a1d325adff6f2b945ac8f7e9bba76b6869abbf9704ccfa718d6926562dfc899c2498b073184ea1c6824a245be772b9276f279e2dbdf62fb28d3295f364f18032361a5db82d16cfa57b21b4270af55130c029b573ccceaeb81293f29c1ba5c0cd6292307c9f0c88100ae57ac1892e422891039541287499d3afbc1d3c68e93a14d5a3b0efb6ff267039fa3aef140953b23cc1d7882023407e7c77dc0924f58529e18b41b2f89747d8f1fb6c166807193100ee0a26b57beb8da3c34fd134a28d5df3cda61683e0ca0f9d92266cf0675081dc18946586e5b9e070504d6125fd485094f3df2eff6d9197b3c7953303f62e276df391c8abf86aef1931d60488556e412ae00f7c201e8d64070aa72e291e804c209c8dc3fe968d06311d569d726fca4a094c7d4dd4b16014d4a1cebaa97131ef1ee66d734b9f85c9a6e70afedb26e7ee8d150d611b852b0bdb34513ee3db302395492b845affb16680f5bea4896b866fc13081eb86f509970b69df9d7c023c160456eb94d7eba2e9e2e076c10ad52b9c966ac387f808811138b9f7416bd0a9d21dfe8b706ce321f284342aa301f4d8361bf20bccd478386673d2afbab6288b8aff15eebfcab25406864842b7fd6bcf6c42fbd8b2cd526c5dca80e46a04be95cd7d63d936eb8f5430415b9b1232e4ad3dda1abb1b1c0286e4d89b9750fc67eeb22342a2aaaf83766ffd72efd993dec4a06dcfbe5dc3c067dca721d41b14f8a3536e69923d34bab47021bd1a16640da14fee5e587a833f2b415f4c454b80c700a4d9bcad4c94b6db9cd969d199f0a3f4fdb7225d445cefee5c67b1d6ac63e8e51d80cf32ae75247436bef80affa4b36096b19b1dff52a88f7a3f2e29dfdb9c5dd994f3bcbafd976f318fc59e3d1ab60e92a2c0ca7eebf68da24253b4bf1bc99c98ac429becba641fc2642074a07a9249ebe6508dc5d0d460f6c7bb873cc6a2ad7b91f03edcdc731507ad451ee3d9a4527721a5e76a55dc008f438014fd0797066a51910e958d5a0d92ee2245c853b4c9a7b2e7efb1e9e749b420b126f0a0240c516882686660b38c60007f45d7648eaa2d7b1c6b1bdba8aa5ca140e8c38b0cb6d54e3083e903f7c3f6ac97d95293506613b3a35f1c2a8d401f66d917906210c758563e4722d30b05d375c8ecc41d898574c3a20d218b581db4c85ddb2125e56c4918d021f96bac324ff9e9789c921cc5281c0f0c98a98fcf218232a8b99a2bc34a4b7c9d9031b1d408bbec6e3e633555e8fabcb0115324e000000000000000000000000000000000000000000000001080d161c20""") - ) - }; - - static KeyGenTestCase[] KeyGenTestCases87 = new KeyGenTestCase[] { - new KeyGenTestCase( - TestUtils.hexDecode(""" -796732acba3efdf731bf7c242aeeddf5eba5b131da90e36af23a3bce9c7aa93a""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -60d235ddc4f334bfd91d6b7df1a4fed84c88c2933806f13fe06ef15aed96c9e1""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -c14612e7a22ec88bb5e9dcf865776c37cd5b1c6d1b18798be80b9562ba4752e1""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -ed5bf4a40e4ce8d367598819be8ec4ed706df4d26819f69729c2acf274515c8e""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -78981182b43d78c40b828554c36d70b960a02c66490c15a4caa6a7d5f1e9ce34""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -917a2234587c5969cc1ed10d51b0dcf8b3017143ebf31687930f3e2c610a4850""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -df022c3c86b725c5f2b54196b7d68684b9fde93be78e38beaeef18195321f4e2""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -865f638c38f0852d2d712a708ffbd7d96f0df21071d8bfec74c2302ea4c5adba""") - ), - new KeyGenTestCase( - TestUtils.hexDecode(""" -741a60c9f1715c42a5a9e67b4e69e5f128372002a6c4f54ae5869500171e2541""") - ) - }; - - static SigGenTestCase[] SigGenTestCases87 = new SigGenTestCase[] { - new SigGenTestCase( - TestUtils.hexDecode(""" -f72a05ee9f7d9072a579e3743771e12eb5c748904b15ff67e6a82e1bb77cafc30e16139c1793315fa0b9f5947c2c5b423ef79dda9a5608d73fab61fdf5ade1b323042a98cecd925d9ab15eb79da754237d157db7937297373e8a8df9ff72bfbbc7aa2846a0afd39f61b35ee1e3b3bdd9aca2400d1b007a8d84264e688731d0714a068440100e923048082749e33491c4c04458124e5c4261098480039344043208012760a3a60098200513420952180280042264262288446a52348518374204162043a829a49220cc2626e3b430893430ca2481caa8610014090a842418b488e0886513278c812221002412a1b44913b9614a160c12322098242423370e1b028dc9a86462160d200202a0106a5a3812032108910230114801d9a0490bb148d8122e23464ca4c600581432d8002de3c04d410045e0c2641134448a1012c2464e20484a1ab0689a4265198840da284c4cc00523c58c24204293388614b56d0b170e4ba46820a66cc91600231802d4b2644806828c96485026244a428664402e8c92481214415a0660a18481d18245cc409010141082267018378d10406a2283450a256012314ecca88d53c80148100524a92ce1284e23412621a405613605ca4832d1845043c62498c041d804281bb2718c948c101345a18645a2084891a660e2964443183240b60420c710624662d8c451d34245243428c1c0299c82311a496d9cc811a142040c160a08412904c941634208c286294c988d630409c440291c39895bc0609c02714108291ab345dc843122342208280604364648220da34412dab41124b40d21c7011bc324ca8250d8146c80c08d60b20c83124ad13666cc46259a00880a07484aa8290b8204024862dc203021862154981003304409b96de42420c2962d88b46822c06c1841016118100b2449c14449984206e3206a60480652828513118888b2681ca549d0864ce4342a1b929161802dd9440000964d2310461885612119660934684a080098067122c32111b8889a146d244944cc1485c1828852288e6480410c870da0c010e2c86490c87158424c9442618a984420254e0c84898c28098a4805114089e03846e024040ac190dc388060221119018cca422489204da40085104350e218614338915b408de24411a32081e4122d53c43003b06d13458a1988218c1686511044e1c849a1260e1306481c46520900659aa630e4228eda209113036190888d531851c3b664028768009941a448269a4044d0944dc1a844e1c028c2980523b48d64186e88a4641a058563386dc9804c94862502271110333204a9604426665430459a98001c31401a330d19c98509036940005058062d0bc26114168d1ba111a2380992c2709c308910c830d19071d4926540388609148e00278c4c92890438051c038563920810266948b62492b28190b44014a0211433205334709a2051121389c33462d8986c1a42221bb188dc243049484d1ab1640481601b06500a936982c24823280c03c9504810661ba871082666a00692cc12840299100342029b266922a56cd2088803417009138862124d41140042342ee30200e010491cb025c3202121b990c4a80520802cd018280a39469202205144401a428d9a441040264260246153882c23316e14a241093549048424081652d1405299246aca10060a15660a31250a47521a052813b52908252d010802da04055c9681a4180983026561a22d10958d180146a4b081522080c026414b287100c53124466902015103b370824482243661c212065a1832d9427100088e0c279204076d0315804026111c175109192554006d4ca48514494d8b1689e2120a19016da0386211306e82c2240c932d44a86404028dc9464c02b50da318420049458b220c09c02814c30918a56420b58480984d4ac60411c0700820494a488ddb3611c9002c642081da48504b047120180ea3068219346e949065d9c42d03a9899cb64ddbc831d1342694206619860091b66001014e5948705c288523220c1b81200488240cc34023c740c22045d24250c33681220646c1c4685a306193a6685aa22dcac6210909264906290a992c4c42714c224584b004dc0072a228690841419a3020e4042a888071993244643662cb106409398dc2927058884123352c41180ca31804dc08246132201a1064c2848c12372c611201641604e2388a1c3950d3c8019dac3259917e5cd5cedc8d8305d2f2e16c706b20a3165c635370df6083a64be12031114dd323be97ac280053b276dc5f65045a54c13712955917ed389f5b46e884e256af84a5e957183d0cc38a6c089fd764521a78a244e930eed89a632702849993a7f00c501e383bc265558313637a7b234ec6f3d1543071d61350603efcf9004015f5048415cad1f297a9c9d1b15f7542721222b50c30c26b87db16aad438a2b34ba750d58f48213e351a472e48e54996b421952d00ec579ec39bc0b855389c837f2963bbef650a986cb0f32ce660d539da55193389014130cd102f4cfe130f537721585bc2327cc7daa3cade515981571060c46c015cfe52c9008628228486f880702f97ade1a5e6320eeabf4e1ac3f72776863c8e8a3e89368385173a509c2d7cdb9d07777cb60fc42d0210570c2e8f59a8e043e3343f2086917dd317f62750d310a51744842752bd1a60400a2c3389a874b88a66d2ece5a9b9c864c9d3d4ad5fd79e95955ae3e48bfda369e8fed4e38764a38193481bb5c79a054085ff2b762b241783dfd2d9072d0352a726c32ec38233831585e021a0c97fd1114b7182cc6babc319984bc5a999450e595e03a88a24453c9d926a025b80b53a4a47c58ba9bf5e5fa69151391294bb5004d6e5bd1c730a4b07f0402a15dd600ee13163a5a63902efd52861520197986b7ba28f988a420e6c81fb0afd647873d724683ffae1d6c9e65d001fc1e22f68bd96eaafce4c2041b13b02e0b3d3ac6885cb44e2c254d9ab56ee42189d7dde62cac7c74ae5b6175f430735de71a047ed245ec77195163737d5bf2cf880d1e42d6ffebc751708ddd43a60bfaad314e69208f140ef140a2435d3b64d3e9e3339b64c303564f92384fb9d132072aa2b53239f2022e211b7b023c503faa1f886f4e0f21f814811b0020c2a31b857dad723ffec88da75a4705c08f7c3a28f1ce7680e9ff66d47cec632abfc98fa1c7bdb9e5709e1022ea50d54c7b57e25d13c5990fdce177a198fe7e401e7b51cb73408f358d91b7ca3afb2bef8af7378bf07ac21bcd4668b99591a433981d0d8412d758873de0f12a6de4a37ce12cfb7e5ff8e32dab15a8ad9830e188390d0d8ab109b662c8b61372873d80f2a24f7bc12021c73384d2c38c4c28d8055a85a5df24e6167c0c6ea24ccb4d349c35355b3e924423ca06307f78656b7c0279cd5a25000e7c501711e5fea3ccfa049f59bd9702e6b5c9675416d16aab1e58a878e21242447828c29327bfef77594d4c52c36d33b83f66d81c53632268d2db050ae37a86784ef62ab14939aeb3a8567ce95293dbc155afce0664630b9aa76a272e8db240c736444975b5031c9f7676c7fcf2af3066197d87af0e1efd8c6068ed8bbb387cb359d7e05b38b3d04a4ae7d944d58e8db3b100ded132ea1dc3e3241c5dea374cfe691a050a7de51eb807158319a6893f1d141fdb3094450817c8af9ee50e44e65934d5a1fd039a7dcbc0274bbe98142fe6f50b69cbc2f5c105c0150ae1cf0df64bd7cf73c2714130166c35ad1b5bad3431354305ffbd354bab3e77274bc933c110bc96cddcda6986f0993dc63cfecaf177b8343ff937fce2978adc74b36c8ea698eca417b91548155df19163748121b31f1f075562b2aca99c89459641da7106831ca0a3aec9603597b1a7bec843fd7dc50f644ed6e5fbce214c0c7863bb47a45fa73c884db1d440d3da5c1a7599a73dedb6a093dfe8ae0c8a702d1f37a6cea458a40e8dccb8b4f667022ed84bf613b3f10ad57bce248d2569b11054a43fa9e0152f9bdf331ee7f0b051b3fa90f3f411b719de22c3ba7b2e78481100494a4aaed9d321885b395a63d9db18bc7412ad9704cbcca305b3b04da6b47cb3b8382a7c2de112c46f2d0b870ab38cab5bfdf23413af1b964bd68868a34ed8129d522e0255660a6b717d450c2ffcbf467177e00e5c55acb1ec853832d00af31e8d36b58df62bcfe7f95831fcd9cfb7f51cf7f1a12b84d5cc6ce6d818e7201fb15c2217738d2de405301f0ee1f3f8934d13dcb34852afaa7e0af86a5d31a85c6bb02431be3e0b05fed5209d3f1c51c618d8d261a20043f353d30cfcae57e8662f7d6ad92278cb988f85363cfb6fa2e0f9efccb6c154d0385f2e40e57e82c814ba4903971df4e27995f4a788c36329a715b0b2ff58ef48ee65925c557bb4ac45e2b3d0e1b0a23f9120d731f73c8da7c52fcdcfbe02edc0afdad6f3e7af6b2ce0a29c2ab8ccf775ba2135230ee0a55f9b39e9f392fc66039434c47292bfd4cbe857dc12418442996b90155373167a5b84a9fda96229610bec43d32f403b816e873cb39989e2ee3a885c0fac0bd977546383270acd725904d08623b984c9e46707b9c5a934c624b3b7c817a37cffc9cf093ec52b2b00d33a96d6bb9132673a39a5684c6efe1d1d11f9ebb7dc17c36d40fabb33e396276343c8a2a94fd4c6c8b2415ca91e9be9bd89b31902fa260ae9495d3562316bef4735a830ba7d20fa6e22aeb80b09fa07c9d6419e6dc3c23623427dda2bdfdd5269758399012fd6ce62a57b819c5dbc227ed99a06046fb7137ec13950ddcd577f4b528b34fe3b18ac114d5da5bf7871e13e24a5e38cbf2ec211fbb9698ae59577f66746f3dec2f04b48c68cd0803f0a9bed8d3a54da72d787d5419c8f2bc7ff40be74147ac1b2a471d5fc5d9a135508f203bdd28948a6b2b06ba41a33f598d208e5d857c23342db274ee63cb7813a3c863c8e1bad529f5aca98ea4e9b602497ba913b98e9d1c21510b02e388d958032e5cbf1ab0475b3c3bdacb02142eef236ad34ef9d011122173910767a691f55642fae6b762e1242341aaefa38ea2744ee67bffa470c7b32d87175b5c57ddc1a16aeddc915ac1835c6f0040470f6d3ca4f2611a61f4cbb55570f91406d0f3e0abebcd8abff8b344e582b8d17fa651c89f82181f75d3c88e30563413915255430a29f885c4e51f054da4f304e2ddfbd7f41782f1093e8268fa40d02e970abda862beb0051ea3ec3068f1e3958696ba329c62670a582670834047bd433bb2485c434172f4192b598f04cca6d36f7bd83247bbeec937f1f6e1cfd05f5af2c5f0bed0467a5c3697ee7772051492f8e7345691247d0a151791062062184427801423b398b098043ac0db62fbbdbb76be4c13992d33aa0b8525ba037b76c7f2ee0c76144fd033003ea6720f29ba9ef500c8d78acc27ede081e88766a4f368d87c14d900b45b65046e3652be033c1c83f6ef86c9e003279a798fe58382209a0005661ce13e53afdff6370d6b6c782061016e77f3d3f705b25aca287d5b634b0928d39949bf68bf35e7a1917c26fbfa38f73300a6e849b3fd8f908d37dfab5664ec3d379d6a4eb0ef4554b0f0bc5ffbe85dbf7447c9c5164471dc580494831e3212472d3d2f84189854c98762e8d3ae016425a3418319a8f186dbb781c89feb8ff09fa8f173bcb60b2b352bc2aad3d1c7086ae269ef37e92108285a815b1c1e3517a5426c5d94c2888c10cbdd815c9a7c1f83b4d8b0774377a1e7c799e8c652fb35389f283ebe142a1a2dbe6574ae029194936ff61db61887d4103cb1e2bd21f2a0de551e6f9e1e423a0ef516ede1abe694a97f82decf666708aa8672a3f9b063bf4fe5606a76b3743b16c1381e3e5f4208b9c4f8bba582bf60b3b5d3fa1a90648db008204ea56a9863365c4e478cb9f1155357be84d1faab4db013e49aa46bf050e3f0de60b94de01704c26268b9342a3a33b8ace7fcf9bf80c23fb912fa36765a41bbdaf51d6ead90097176c586f65be9857fc6b07b721fbdf788129aa979124692b9b1b7851fe236a4098d45679d3cce0e4c7aa723259ebf101f3202088f4afcadb686475444bf0c7d38bf7fcf909ccc6c01d12e2cc53823bf9adda6c8138abe27dc835ca7588d9093b1697fe156a6efbecbce0c3115fd1cdb985621f4836cf27835239b24cebfc3b26b0e0b9f9346360e2428c8d7210933c94abc05ac01e7196dd3de6588a3189d7b2fb7efed84d6c53428522a4763f110429d5995ab83de1443560d942becf1d2d741db6fb6d37ad521f8f1426ba8e3dea7d14e3750cfa17f10e8d2a04c01a34185c9113587288349a8c6a70a62539a7f3851e03f74186a3354f83f358500318749e1c34f35bee080d25879a44eab7f28765345e10493bf266607a977e2090d366d07eaa0fc887d4b6c574e9f215748e746ce9c52c46421aac960b014591760f4717eef1b2359342fda9b810a821698afe5270aeaabb9eaa621706497dbf6cd4cb5b4b6b32f870f05b1dec64c67077c8db2f80c1adc1bd5faa31f932fd4c993118733e7a9f544b2985deeddd39670a7d1562d95e6a4746a6c255b8f74772c8ac313726b649bdcb7f7e8b83b558f7352c8524837768f10de5c39dee63f348c25964b1902daa8ded48e03a1a07acb72f0738d42595a4cdfc0c10120ce027175a3f86ee51a3880dd1f470b24d129fbc2921ea1073472ef9d0ecdb634121bce9dcea720a115871606fec35e970fc0ccb626a8ed2962a7f4a7eccd3c93e73ab8aa3d75a3bb0a66d1f7d947f5ce23fc505bf135fa4e6986319299fd6d93ddd12f6f84e191eb04d8df4da1198cc98414640a6d70b6fb2d65fa37d2c7d61c175578bcf194c73143755f0e69375387aef20c27e58d9b870e7b6d6279e55be1a0eadb6de09bf35a79b7"""), - TestUtils.hexDecode(""" -67D7F4FE3CC57FC8BE9A3D06BCA0FE4A39F39E3A6158D3E4ADA9CCBABEB542CA67CAC48167928336993C569AB5AE55BF95C8291AE1A1AB2B595C90C0FB19041435F3B411609412630D80DB0C832D413D69C8D3C3CA78BD1BDC24167AF590B67449DAC7F6ECBF87698BF3929FBC874F6FD68551B28E4EEEFDE9A0D0E7FE9E569F1F9893D39C17C3BA7A6211B875A7BCAD0C14194C30D60CDDAD640EAF7A02CC9DAC074779345B83F0D282899B2B9B61F8504BEACA3C02A76611C82F2007953D04FD3C54D7A00DF8F6DE554FD83D1EA5DC841645B706C9D900DEE7862D526245215AC6B9D178E60F9602F1931503864D97F582834DB797CAB60DCDBDAFA3FAE8726B525E8BB69B5E0763FC4ED17FE7CD9C9629273AD5B073B9516F6CD7EE729351C213FDD122E3C11DBC58FD2A501B267AA4AB21364BAA856823816E77B81B6061279FEDA6617247B86073E55B19973BC0E725F34ED4BAF0AFB95E436A9B2290A2B316C18CDC0D9F98F9F6F13C5A3FC767EC0A9A49BE1378E92BC9B3010B41AE52AF409AE0FE27CB816EB2614DA41C796D5F4FAC4A743FE34EF7C0B3A78E0E4A5B439659D4AC27B698550E89A1626FAADF71420F559DF2E808144707B5C02090F754C3BD4EFCEBAF6FA4493C5D48F895FE7674C81F069E1F00E455BF5C965BE2926BD19AF76E20533A6115F4BCF2CC5DD3A49E10A2B3FCC9EEBB2B6E4F25118599062F2AA6CC3A9D86167B1BD08DDB2C53A5E46E1BF4E8C1967866320BA66AB67CE581981F2003B812BA058B75924254EE3715BADB8E6B1B9E4F4AA9844D578CA2F0AD12E1C964685FBFFC87108711E022EA7F63330CA72AF86262838863780F4115138672643E6D9B48C782B8637E01D3D20CFD5C98A1B57720762037FFB12742B4EA8E89E4B32EE7DBFCD5C11E4A6E839A83398ABBC32BA39C6A25922649971D88A102D1019B560C96B820C44551E14509468196CEAFE3B7BC8F253ABFC59FFBC01A13008F77C91B19083A9E7BE733C1A5E558C64557389CA19249CAB77014D0569BAC7812862A610DC6EE074C844A055ADCAAD496F6976C932587BAD9D7E2080F8623C5ED8D9D4FB9EFBDDCC4CCC1284D22A2997824577A619905B0D6E451CAA3B2D30DAD9728FC7623F9ED71F80599D65D9F2AA285BAE393D05C15891472B2DD2ED5CA669785EC4D441F3308EB4BBDAE8FC449962EF9787C39A533847540965601D8BCB6B4299AA636589BFE371D3904E18BC9AAC9B3B6EB8B7E8F322C22A6E01E6B26244F9E39586F124AE4E504FBC9D860A61B20B4C127FD0C55EE810AB9803D810233E6126488A6E95F8ADBB3F8E06D113DE6A3E361209E0D36B326E042CE9D2698DEE469DA15464AFF82D5603434C07CCFC4D956A7D55FE79CC127AAD2A56B34EB10E8B85C3CD5163C4BB8C1083BCE5E5EF986AE028837809641A6AF2B8295B743DD9B03931E755673DBDEDE56F6294270532D685DAF1187137CD7D29248F21B290EB8317E3EB28B62E45E140F4AFC6D1438F81E9EBFC6FC0F1A4146AAD83AD1F0EE2952643E7B6872CB2823AB21A155C281ABCD19E20A52611C6FFAA724578A070935B1A0BFEFBF061101A81227187E14E96B016242DA269FC91253FD827A73743A4BC49FB63E2D830D0FF409AA1C73706D7C2297CBC552CED567DFED72CD15060A522F9B88EC910B03CD2794A9FC07A8FFC5CB97817DC769E64D8C474A305035A49D05B1C572363913A315932E391B62AF291DC203B9A40F04F40EBF26A4AE186056CEC45EB7D21D88CF50258DCB5EF40CB2ECF949B18C72626469978FBE0964C8A25E8C2D27149C2266748F2B06746E8C9E7E2F0977BBBFE3FBEC7353F583FD5F7C2B0139EA928AE1F67004706F6D4ED7BD8D13BC68E0F4A49877C0B2F692936BE5FF99544B2B19B23A97EA6B5F585ABC9E69E689EFE25E15804C650444C479E0DC63C9CA2AEC41A316039EC7F675F1FD7C0476707370CFAEC9C3418CCF30B5D85FE0E15056D6C015DA59F9BE9028D9C2D93434F99DD8C1BDB41FA1EB021BFD0FC12EF0D038CA32B0FE1449342D83CD6BAE43A8CC4077074FB1191A8887BF29238D27415D93880682017470A42872D6CFA729AA2B3F8B37038C83583E4C33256FB871A704527594596FE858777A93D3095767BCAD2FE295352C93D227E1766A59ECEB38FB7C2E3664D6DA0DD4C063975FAB3AB4B68D125AF16D233389D96A337DBC18DA11F37F430C1E49BF8AD30258601CAC9215F32771C6FC2B7BC03B55AE9664E0D719C3B40C3E4FA7DEFED8571CE8E46FDE8701975D94319DC5FFBE93B4FC4898E2EFEB3CCFFB3494AC50BBA364C22A3953F052F62E46D0C35692AF40D2FBF899A23C1A4721375F307E2FDE2E588830753F908FAD96EBD5FC360D742E2CB2C38A7E142C95376ACAE29DE8E1034207D1CBC1DBF2968677AECED152B1EC1AFC195F3320352953F2503227152444BAA74EE8F98F2B4512F7ABB43D7F87889CF1F8C12D9BAB91EFCA5AED21058E322CEB4E59DB4DDE13BE46FBDFB225F4AEDF7137B548503008002A36D7A3E98C0ED65ED9322D66FAD4A741125EA4ABBB26A2FDD7AD136590061E7BC0D5228555D1A59F8A6E4B97ABB61F4B1AD9564E84C000585DF8BB31AE61CD25C9D91D1A1FC21A69AD286CBC7E00F592DFC1C65E2BE755DDF041486F3B52C8F72ACA97A149FE0CE1378236D99EF099A668F6847659F7EF617B66192CA452ECE3010AAC18A65D8964381F561B48D044096DECC22736C902D7E23EFFD26245018D9D7EA9E2F907932A1EBB405BCFD29F7A397C71A5E08962ABEDA5203988A81F787B25EDE84A7D85DE92A2B19974EF7D0378877B82BD7CB28B67F45F7EE625CCD054B44B4CD51802B4FE2E219315CA9F4C24065F5578732DC671C3004D31830DB435C763143CA209D7DDF3F5EA42244E68429102F4D90297B7C987EEDFF0DFA7F31964B76432E1DE27FA38570F2BF64D5FA3F12DD9772618ED2B95F51AC90410350320E19084F1596F6B791AF1EFC24DBFA2B7E30015AB14FAF43B568C5149A1152A47D278B5F01786F242858C210D28812147646A1A3A7CD69996809B784BB2F0053CFE18446F060622FE3B9181AE9175D6CFD8033AA752296016E7BBF639842DD4073AB282FF50F94B9E116C63DDED805277D4FD7987F740EF8118946851A5336A9F6F6E2FE3ECABCC518B31E741AA79AB500D9C6DEFCC437569966EAB1D4BD6CFF8AD0E5698D15F1342ED46CB6DA986F0C4B2B427752C18ADC5070043FFEEBA98569E90C79A3D5E0434119A077A097D69DA6E9AD7E32C6E8875A893F6D69424DCF4C0D4EA12605E5E8A9853E4B58E5659FED6D724CBAF582A89A228F99BE89D88F55095D0627B40B29365863C57F82B9EA22FDE731D1A2D8A9037665213F2C410D4AADCE12CF888DD4AF53FF839E962F0F53BEC60F97133D131C2C8EB588AA7D25EC025B9E821DA8E8FD8E550EC5E4D5923BFDDBAC522D1FA64C503078618B52F452B57874285AFD3F6B182CA6C979734C94F040EBAEDFEB547683E98F4D13F12A252E8839317A827CD97A7C3D81962A25DF7D8C62B57812EAFEA9EEAAD7D6A9E755AE4CF3AF42CA2152F663C1BADA0E653EB165F6FB56D86212378C0B9BD5733D4C37178FFB58E7357487B98DEA35127AB58A804B13E61E6D3E385C96884EA91C744DF6CD44B3EFBEFC79ED19C406AA6ECE144A44F1E78B33046C33EB17E3BF61A17D849493D08F0FCF8232AF2922D96213647A47A05A9A08D28AADD3B3BF412F29063C9D78CDD3385BFA9F8BF06DCDA23FF79A5912D867EE1B0D526718EAFA6F0E231CE6C51959BDCD8D201838A50634F1C6BEBE2E4F5235FD01A6D27B90C58C12D8210692BF68FEA5B8A8651E64EFC1DFCE07EE670D473F29AFA63E080F7675F23E7D2866E5F2F9A525BB657E8BE5933FBED1E206C7BA9FF097EC95B91E14612E16F0F4082F70A1B01EB6219D47C716455F4C1C60948CF3228557E787A3186B4758AD35922AF28BDB328693BAED15487F7448D1796BB9DB5C931EFABB4BE436B2710EA280368A8E20C5782A7FE986417003236BE9CADC560B3D7C2CA92341536CF67D412E855B92D0229C45B1C518D8BFC82DFC9F413D3FB23D37EBD96AA0CD0B39EF88B23609AE0FC2BD16FA9E934329558759F05C8D4C8F3F8728335B659D3986E44508322E47121E592C9DBC6F49656B473EF7DA53FF8EF7BAE07D1BBC68EF4AC369D7F8BE60948F34444C0C443A100443EFC444E7FCF0BC4DB6A2C2C64662A538D1F68F4DB95B0B83DFD744ABCCBE5DA343621F0E182CB9E915B2097C186F1B98E7D8F297C347B60EC26D04B6D9C1FFC01EDB2551FB8D11D49E52956F69CDE0E49E2E7DCC8E7C8E78C41A9B2A01483BAB11733A0943A9B765A5811451C07A195D87060F157D114358E478FBA2F2B755A2A455E9831B77EA9D33FAEDC1C562E1CFBD8DE156FAEFF10AF655713E36FB508342D9B4A239D6DB786CF9F57E1C39AE65A7329E434AA88C68F82359E6F057873968F9FB63D898F24BC13C0F7748F92E404C6185CE24C98D4E4D8D4B3C129CB46C614E773A89EAD73CF0C30CD7E6C9F6435F7C83A4C3F877E034755EAFC5F30ECE03F6413F4C7DCCD01649B6ACA9C1C3AC3D112F216AB852A27DB3B846CAED86B76FB699AA7623548EADFE6D16AAF5A3ECCC298D5CAA7E84ADA0B75290FC6ACE736051924DAE8FC5BA6DC9AFEF65F369D054A4A18950E71901F4483A4BDDB2584DEDC31A04C5F8916DA2DE33B37078E5DAF3304344A8AC368A6668464FFD7898A18D10685BDE6D0097F95A3587717F6A3A8827B46653D56E461EF861D6908AB7D865B532DAB37E02A7A6A72A06F25572D83ED6DAA540FE56BFFB2BC9D104A74F135127ECE457991152DD0564BA955971E8C9767DDFAE190052A98A63C4C0DFBD1B51BF60643E4C5EBCA678CE5150F03A6EF09AB0B1C2A0D2C19C2B30A645C7DB9B56B5AACFB862837A38407070DA9C7DDA20B99CAC7B03D10C8F28D6B1C686FD26F9A8FDCEDA6B188D472BC593AD51EA62DCF73D32EED5444484853AD0EFCAA60DD42DD2C50F5AD15DEC7B71BF585581B9F9C68C7C94C154CC7E0D19ABC90508C8EB2DE93F0BE4295973C1F443A1B2419E20F3D5F883912BBD5CDEB938A4452FE0BF2361A9E3B2ADDFBF000DB07EA19B2735CDF0E8E5C7EC5CC7CCE1A9C3E869718272E54CD9875C21DCCBB06FEDE38A4E787D111DC6A253A4604B314FE47A9B6F6FEBA3F8F013A456DBB78B497C4CA7F90CC6145F47C96D266BE5507DEE27E968052CAC85EC87049CDC68D723D8CF89B0C91F67CDE2908C0C71808004A070CFA2EB6408F5FD6108749406FFD3D5DEB6FBEA00FEADDAC4CC0E22A9F6F50B9893CC4CAD028FBB73C1B7BD4292AEAEBEB668859BAD444D0C5FEDE3C469CF28C5C726B59E828C473C8787453BAA3AB2BFC29C691FCAC2CF496ADF3949CC42FB16F3677D456E614B1F88406E6C9DA7DB9937B00764D61C3D347C140FDDABDF8CE5E3E2D385C3FA6FD9F13F3BF8073B5D6AACD5294938DEF9C6ED414FDE4B3C5EC43865A7FB02787E50F94033CFE32A85BBE24B09FAA3B55B8BDDE60E325B691A350F2F128CF74FB5B6DFCD0E946AC7BCFB839B3765616DF35AF29F3AC82F4E2DF7D4AE87A016094719A07B5897105E2B08AE3D807960FED396CF38863E69662238541EE295C06B290404985444F4B28388DD942E51867216C734580B3F1D5BB204B05D4993D6F8ACDC8F16FB77B607FEDA67939A2B6AE285ADB2C98E7D37A81AF0101A5CE39CEB2C67CF99441C1FD980C2C542E7284BD21F1D30E68EF3606C65D3230B5146DAB41D4ECBD5FD89FFC68441BCFED9AD8B4E0B616127A7AA39E84DBD1343E2A41B4DB1AEE0627657438034E890C8EBAE19791705BF6C948C630DB1423D310A34BF151AA8ACF3269253BADDF5B40AB7EB3A7AFE2D7891B925F65EA206F4CA121175E8F348B4162917A68FA768928AEB0504A60C4F42802DA25DCECEC60ACD21FB236080AF1FCC9146BA30AD964416F4B524ACC416B5357206980305555CE3485425EB8F87401FB1D8CCC184C486B5B563242BA9531147D6A2E7C0BEC1A56E083F05344BF97A18D0CE0FE56E8BE869C746D4AAB365225D8871D4F99020DDB1CE2B5D7D2E5DFC8A0DE780CBA0A9B9ABAC87F19C73639965AC2382488387F06199A08F283794E1B8D3580E5CCADE811ABA6881908277624D5395021016DFE21C345B9A21B474043E187403E5B0ECFABE43991865A424BD33D233AC4BD30A3CE73DCF49B58CC4A3D2CE25C54FAB3480FFE0D51A43B71FDB7E1126E66856D263DDC3BF1A31DCDB935DECCF858FA2CE5AC89BF32E36D8009657F11691201290A243B5680E060D2CE30F1BF2444D67DC94A24708F8F9261945D1B5275ECFEAAF40311CED5C3770A1C194EC44501DD25B7F5FE67BCF62D1BF31119F8EA7DEC1CF536C1026A8E72C7B2E167BCAA8673AE5506CF6208F3E1B6057B5D488B29EB84D6F94AB8AF322B8657075B9EAD3297505AA521D601C21540EE71349614CACE0E7F14EF42D6CD5377DDD0241E34CF273A1171135A376B98C53B218503A908577C268F6DD46CA9C26DFF5942998851627474DE9E6B46F49DEDE85CEB993A52D01F6AAD6F96439C18B0DD5A4FD559812227BBC0567A28C1299626B171855AA0C74E2F9B1AAA781D34CA58C72C708AC49F5AE1453902A1FFBB8458E8B4786771780ACAD999F8DB036CF4C3F77AE345817EDA2AD8F7D2AA9228C994F6AEE512F7C2D2AB72F2099EC932D818E495CAC8507B06CDC6702944237DBCE338C20EDC84D958C14233C1884BA09A023BF5284F0B0157048B6AEB508415DF337A553F6435140D0CE5D5CAA77F9137B2C1AD5A02B13738772743F192E53E970DDB401983535CB096F7D98644797F487CFCD18F1B22BA7494D892C1E5AA05E66B1A4326C70E348350C97DBC26CB110AE8289C97CCAAB150020827B7D7AC7913B4FF515583677018949D39CD73BC7DBB90696D5EBDBAE6BD6FC78E3826C8218996F079A387A17456875952B268211891404E80F8360F042EA3D9F7F7BEF772E64FA1EE8B4EBE0A1162A46EC1E9899766BF4D3099AF712A847CC86291B3D6FBF51B3B3CFF87D7DE71E73069619480F6056AAACDB9ED8E228BA075622C2FF242CB050342DF8F02118D071D27D1FDCBFADFF49184F5A100F95E1BCB019864E58E0F02672C8F5FEB97EFA06FBAE6EC3D57A10EC712BE0144323292A2CB27F1B1FCC104140F556D09A6074F853AD4328B00E6F2F24A61A7932311BC999805F2E774DB44ED72ED244A945928B9512556EFCB2BA7BE0E668C41AE7601339F0162CEC0A1AA91C3FEB6A8A40158D7A3560924455B9AFBD4B3881F6C08EC2895C84CEC30CB0F5B499B4A66267C719785F94A9B9F96FCEBEE939AD0FCF42D0E65DC241698DED0EDF1A9BB4147898E6E83851499175105BADFE4CB00B9000404DC92EFB4EBF41D9A9262EDA550DBD0B99353D001F90AA05591100BB678634FDE4E0B1C174222C253870DA3B8A797CAEA9B446309DE5210F9A932D6AD48A4A7361A943C1BC66BFDF75CAF5409034A8768BD535B20996A728A26E28340191E03DB17A7032FFF883EF664FD7351DD37DC2D72F0CC4B80BEDD1DC33BA3046162F5D0003140DF78FA588A9FDBDF778836C6CAE7E5A20FEF030C57867B295712DED14474FB87A301C31214FFBB4F8D166498ED93B6E233A669CB88D441A38A0E5846EF68F5DB20245980CA184878BA8BE1992A0638B058CD3A3A501CACFC818D2B5D7876DB6EB08E9F26430FB06EE0B9E834D1C331B66CD0BCCAD7A66ABF4A9D8F7A872932A3C0B25C5BBCA480159711E0BADCF69A1107B286AB199B210CE95BCBC4244780C074C42B6BD43869F27BD666F9B2541B1561B4C207E9A667EB1E31942697FCEBFD0B920EF80CFBC5CABA6F528187403D7E8262C110458B5382BC376799032362CE57ED39F0D29D7822C408923C29242385CA9749FACA43EB4483E095851E89D24CAC7BA5AAC60815CB5C8C5331CFD66352BC8623D5700F49FD98FFF9E869D5AE173961138D76E00CED6DBA09144083437CC8FF5ACDA10BAEC0081C8BD2F5838666A093B412532C521753C4E11ED0521923D1EE6BEF3B4FABED7467B9C8F75FB24FD8D96759A6146B34EF951C4DF92228C2E58231A8D25E3F08ED5A27BF6041AD7011DB41F815FEA503973D4E7B5798489B261A0AA4D0C32A19D17C584B1702713D1174E542BE4EDCEF27016BFC78118445A63FC1D17FBEE5F71DFF46F1EDCD050239C68DDBDEEFDAE7EB8963B5BB4819186D45191C05AA049E50C4319936C8788AB72744912AF28BBF5CC77C835C35BB4F987DBA6657BC2A7E58B7CE69AF37AF680DC0EA7797B29528AC70D92F295C561E2EE0D0E530854AA19EDC43C01A383035F6A5DFB354E9306962EAECA25EC85B9B78E8A1DF6CA50EEC733F60C81BF812981337F784F8CE07D0C03D8B3E72BEE1FFA55FB92DD0446CEE29D8825CBAF1A6ED295E613FC700FA31167224D99338C4F59B1BB9C1E63CF77476BF84F2001D42E4161F7737B47C1A5F219F6AC8B8E3ADAECA827AFCD6BC0CA09615BCE15F1BD0803BDCBD41E68F781517907EF3DD8E8A33A1E30ED09D7EC1D3605DC72C9232EF9F92475743164E92D953177B98906DFE5E414E134EBB63C79220D4907869CB2D93280F60DBECCC81B532CA336510E2A7F1D631F7BFC517AFF223430F9804C4A4877D8B7A385ED48F390ED9666A56EBD62F6C943D0E52AB1EA247BFB07C05908E99358A51E6111486133F4A6BE3BAF6B2D4C01529925ED911CE728B4CE4E8CF8379BD216108BF964496269BE76379912E94A4984B890A4BBB9692107D56AAADAF27ADE475E98A566C0C9E33DD1970A3DFF0E2F79197F6315E320BEB5E2CA3E3C904B557075981118B363042BA687DC682F13D213974B1647FB43DF7FA168C9D4F599C5BDFF2941C111C6C43FC75E69C290601EBC9F23D665F944A9B75932DF7792CB8A005A7CC83DD071376DB11F9C950B38B270E06C907FAA102AC76722325934755F53F3650B42D0FF293FA37086241C00E99B9C03FCE21F8D7555CFA93D09A0EAEE3733A8A5E4C45E74DD5EBFFD2F75EA60942BE34412BC82FC9959CFA155DC87FFA0AFFC1E7CA5057EE016B9751C16DF25610F1981A08B8E3352254AFA433E9B86D3CC13FE9B5B7FBDAD83CFA0FFE511E44412DFF1636BCBB49E9769FC52B302AFC7A96A3DFB233831007CFD6C302CCABC119DAD45EE63303DFA1F11C39C702AAAE00FCDCA913371F158BE5493A9B5C3B06AF66C8D5DE2BF9563FB617D1490FF6510971203DD25B27E1AFB289DF894396B8C26548BD53B320203AAF053B19CFC815C5D37E3115FD6CF8231B88FE4C330545F131A01124BB2487A3363B3E534BFD38B1D5138F8887EA63776D78783AC45675ED598617077AEAD86206B9FF61E3669C93C3C3A3A8F39E7848A88C0F94878E5D359C22BAE891FC7478BC8227FF320B047D0DFFC8218C1110136FA803EF6395E52DB8326CE8E3AA928CE42FBA04B1E7F1AC7B73296CBC1567090B9E92238859A87686D8E623B780F0376B8537F41B1BB102CC8C480C0B6C069F562468D4E1FE111B24D51F63E9BD38C47F35D8C2B5BE2E737274229974CC4CA63BD0E1F0446F6C4448EDB2498F2376EE26BDD8581242703715AD434E425908D61EAF865FAC5E82578EEB0525F54320B6C264F37DA36B55C2308D4FC6C7FB2F4D12A88CAFD93953193B7CC46804A0C464740B4972A71B7EAB5F6098FF78BDD452540AC5BAA894C10CD69A992217B422C88CC7849B4D8357D86234449B452AB4D49EDB1D2769512CF8A797F5FFF4E1E0A3FBDE292D91722D71322F0BD48C68A3CC998D03F7581EA7B5F5150E7AF58A076D09D103E9F64E61A2D375461007210DB511EA89FC4EEA75FFC71F7BF31400E7783F12F69A1EB5B7228952E2CD1D6FD57109237BDC024780006C229EAD71EBF4B543647FDD9216D98DC78B43CFEAE12166CDEDDE09B52BDCBFF089B1F7427EAECC21CCAF3FD5A35EE72C3107DF0670891E1AE12C1FB81581F3A45480F1FE06BECE6A494074FF3C47F90C961E371E8014707AB0FD004D19166140AF7B1C9D6B7E4B6826601AE104CE18E17939CF77C2A31F711D5C7D5126F4CB642178CE542973466696FAC1A0858ED62E4F2741E47B83B97DCF4610B1E4E262E700A06FDBFC6709BB1D4AFA7C20EFB72E0D623389DCCB049054CBBB322E63B09176E2903DBCE49083B01EB07F140D498B793E149573D8CA91DD2BBF8DEABAD9CECA0F896A7B306C22F8A761A65CE2BC1358A6ED07327AA0FF4C0B6E2906882A12C50D61D021A1316646461013D8169C4B54C61614CC9EDB2CE0AB0BAC96B36908BA3ABDF92D11D96EBBB9A60DA780AA58B804DC6F91E54D82068FE2FB10EC1FED54B794836F54503135A7F91921E2BBC2A61C99B6A0BDC04FBD2D4E7E430F16B5D3C7F06243517452BB7D2D51340BAF550D260A26A2F3B5451AD7D4E3A70CAF63F92E25D137C9E9B1433CAA5502DA269211F58AF2720FE3F899282C2C02B78E66D3302C5B9DC04B98197D3685EC4E6D4603D79B357282932689C2928361022E79C197A470212A69AC2BFC7505366CBB2BAB8D2E31314FFD77A04E85076D76948E836CF2A87918D43208CD856FFA33740FCAFFF9F690B2E6B33F1D89F65C71"""), - TestUtils.hexDecode(""" -a7a908a5bd14b14de2439fdbaba72b5ee9bd54df9c52b17b2e3561949f4739205c112010edf1acd95513c740e1a23beab2269f5db9b432bbbee5db53bddc1fd355d8ee23f018cdf3108404b0d1ddd3b815dfa8b1c724bfc8f9e0c0e610a8b1260ae33ed202e1e270cb27755f10404dd66d3d32c530aed7963b5ae36aa4c1d0ef442b149b71a0756c9e016b7ff63fb4ed25c59edb578d01a0dcf04935a4b5609f4018a32d18f9a59f0edc0d2e90bd7e0ae75b5402652dfa30cc0938c7e35b3666093157f1c2f6ad80024539443557db996783056c63730cfa60c46c86b79ce446e2e66d2b279c192cb4773409fb8cb918e363220c0c1ed95e9a7524d0c0ac53c172eb3fe311b14d16c2460d0e583aa3ce251057b5ca59fee59f72627fb3b1c8e74a8920f10ee9f96a080d6f0a143fdf029c71f20451757b2519fe0c10e006134a2ef8d51cff472dfa63f934e13fa2d9f9705092712bca99be482313668f52a5e996a59511ab9bed2a7a4ec0ec1f17a3df944d4222b32e7c4826cdeb3abdbf325f7f9c76f5b7de28b1d5208ce9e19e853b90c9c7e2a26cd1590152fb61ae4fe56238b5e52fdaa6a17afbe5078d4af5403b620acc4942d01a432849fb5a6bc19bac30efed04e629d3caa74fb0d7c2873a3609c0b6f8c41d88d394bce13f3a144f0fb3d60a5ed31225badb206848c13c156a2b7be5d9df517d5d71ea3b578f90cc85fa72c3057442c95571dd20c9c9b1424566a408f6e135d74728b4b1aa1918aa38dd2108346a3189f54c9ee83684b1630a29a69d6280e47099ef989c3907b95fa9c1119152d97f9d9181fe2bb89759987a7dc16556223bb0738d1a10ad7959270bb737fc7601f2552a322181e1730228c4f0889cf196bb570002cc439ddb83bbea27f5ad9db5e62ef69290368544e271dad0e880a032a188cf4ae1b290f6576ea5c20ff9ac3b3950566fb8081768a4bd804c22539684572105505d2d2507308e5e50d05ddf24655089c2cfa4185265737894310f66d29551e842e9df5dc36d2e1a894d10504099511c68a0a81900c70fc6c2b32e84587d6e4654c97ada0ac1b7493a8efb756a4aa0278b773cd302f0746a6a18e3b1aea24ffcb32a57844955bab9abb85076ebbc568b4c5ecc898f9a1d9e65c6852c64a1995733420e0ba5a61329b191e750e212a68ee37717ca8961593f146e0093d1b70f07cca6b6f2805f48e66c1b3d6405ae5f6a95fe27d427482fcc5bbbc2c5e0e0449c73eadbdc261ee9636bfdea73a13c0a9ad432b4b7037432c799cff8051a331b261028739bfcb17544732bea4c2c3ec1d42685d007740bf49d8f8caa8bc31c7e59f9ca033f27eeb57f03af68b8ca30a27f78c06dd3a7f821f58579353c325982273415975b03cd8649c9632374f25bf010aa1c0bb82eabba168c3e2ed17213734718cff337eafe9e48b6ab79655e98a38bb1f74519aa07ad10529370ea2581f99c59a824a5ee0747fb6bce34396514a6a3dc4755e913304a28f4bf4019a42acda382a7a7211a30b2878264c4266043cbdbe2c711fd0da53106b0b5b16e78bcd1a075b253c98cb0aa9b980af82425751a7192e42f5057d5e5e71a2d0dcc9404035e63a905133c7724ffa110c942c54e8970dcbcf99fe1987931a5fc14e83b731aad5f2ec0a29f6872e43f18a94f5f9f11e2b7508ebe29a803fe159aabe2cdc242a6ffe976044feedd0b5826c129dec3c05764451feb8b99953a635e7250e74772da18755e819be7db6560b5ebe2de9eac9fdd490a6aaeff8bf568a38f70bd0ca443d336ae6776212e0d99593f4123d91dff7ef68222d497d1799ebe6decd2f7acc6c363e43dfdf9f72b88c25e9bf740cd1207421b476ec3b68843cdd285e292986409aa4ef04ce4b6479c95e52ccc8b5b0247afb94f43af536ad9ee79b58b636afa64a2be3fb22fd128f1f1f05b949921bb050892ed61cbcdf66b11ec042eaac3765d7aa524c0cb022d386032ed7449262529d2a6eb8c5a7a539deb3d1db814f0284e9dee64661f8cf3906a9802efb7fb5c4033502eeccdafd77a6d0f6ecbbbd39aa21f14afc3ec5def48b48afcf5ec99acefeb3007a90a54da935eb5d4aaa68502b1c469acb166646a3af67fdbb51d1338085d2798174db7ce74f2ea9c61a50a6fbb718dbf62ac33dcb7fa80aa982924f4310adbc07b2b672438c837d1c58eb8b9093229cab0d6047091b4152a75beffe7b17e44989dbef1c68feacf11a47d9dcbb230b9b180f9a7d10036ccad63454f3da00537078db225cb746466f1d56df35fd9380620e37f4692aa0b9b5bb1784a4cb80a53a25bd9cbd7ffd2d3177ac7023ebd1127adc732ef7d4963f70b130af5c33a824c3b7ed6d2e1bbced1959560cb753917781af33478ffb947488c8372d227e5efc9f5db11bb010c278cb40ead48ae49b2df5f927363a9e78bc125072929ef80efee18c7592271393b6f29cd1e339e512b1214fc5757b1ddf0bd1b9742a0a11ce469a78866b24035d8499c42be66110a624c928641e59078bd1cf6771c7446bd1977578c165695c4d6aa4ba9383ecd2c41677c3c5cf9af096f4c8c9f5f244e5395ef1db825d2593554c7c741ff0e0540f0ec897a1d8cd88d2f86a1aa21e5473b1fd21a8065d49d682d4dce206f4b511f4d466a56be1bd99d1335b17f4170a08899c2015e687f1caf70140770dddc885cac8c29dffa7d5df823b3b8d64e96008f5aed8d52ed710375e34a7743a98f714dbfaf70e78b177156634c0ae931f5082d2c6b7e8d7b1f025802ad9f74c711e218955938b14fec5d0983bd2f44d9288edb72bd1eb41839297ba5915e518a1e57e28a4ef8eadbc6ac4e14b4f61ff5834b1fc6f21a8065f7e84cd99e1d86cc9fb8582fd40eb4f1f1f4e05161cba9e54c823e77f882cdabd8ec501be12e855e0f492fe572311a01e2aa73c9c0c0ef43df7256ce9a41502e15d7fc76a3786dfc2812ba4451ee9a4d159d1052e0fcac791df2027258c5f0ef51d23498d0ef333c59eaba21765783f7fe51db331be068ec4e3e779eb5cd47e036a5bfb6634dae1e4fc719636a3e4944b64af890b1ec70f89b73b33b626d5b3f4c33e45ffae3472929818e1de7eae0f0135937f4e065b2b1dd045ba8372820a294d4a4c9d44af6e321ff565c69ffe8babd43d095509163bbf8a503ec55588ac3c58074a96f3e32499a6845387f9f8b4520cdd3ad129165501d28b68339c1b0b43dd1dac6d02fa89b3c381373a94c1a59ef4839a671b7fcd08c61cb12b6c66edb631988fdead1a818f843f070a66ec46523f8879d43c98e3a4884c8683f9eb73a4d186fb43a343165202bbe8e1735749b64c9ee36f062f2f8129e227ef8d38a7f35677b01f68162d9c5310aec1a8f8ab1365546ae313c90be351030641004c735c2ffb07d7edfdd7434ba984790cc7c3c843c23531593caf985d63c4eef255962825a44a2c9a5c73d1878b6e149fa754a46b77239539851b2adaa293dc29cac659a0d0840bc545401984682144d7b651b125dcbc3ac272edd7e8805e086e7e33e2367beeee06458dd2dd80deb7e36ae6f9d10f84459a9b828aca738136f2dfdec4dddb3dc6c0ca72e2bf19b5b87ed28ff661de8ae64d7dcbfb71f17f362897e12e94f3197e58b2d62eb849a169524ab78962b25288f87321a753241b123b2aee98e60e2ad7341d8e1796a160932c51ab8c6a0c97b188ab05dab278cb64f025a42ff8e40a424858f7e56b27d0eb08746def560c8dfd11bc359b8afb1a3b922bd34dd1f4588572d26401074e4ef4f37500d39456e458b6a9f30b94003fd110987ecec56629a013245b48be1f8df1b2ad80b3097552841186ee787be2e8ebd555253f59e12c255db9967f8f506746b8fa49203e4b2bb48d04bc117338c40a6badaad1bf8f100b8420aff9231d20bdb2e78ce173b12a87c83f0b594ee7225d4d0b975a60ad615f8a21f3a4abf819bad041fd01c740233cbed5e690e6061998af1f0fa406862025feddd62ee72ef314eb3b12d40227d92de05a960cfe96707f9c9fe8d51728fc8258531ad38cb8206d978283436f6b7aea2282cf63b27b639c78abdaa21be576a55388febd14807625391dbb8689896d08ca7d41d28d6cd342426dbcec96d6d44e78739818a757a94f615cfed9134e38c4d34569242c51b8992aa6419c24b4a80c9593ff77d8bc840e6bc7328b69a95354606602f0f8f13d480166c4c69fb5c74fe5874ec7d98a9170f47096fab89d9ada1285aa2ffcc968ba5dab962248471b2de8ac7126988362b845127bee0edadac224e552b0bd83f0a0d9439bf24de27d54243f8106b5e95716d835a7813fe504f195b6f2d28e12dc041f50e31858cc79ed3a143d9c7f4fc8badcfc3a8b756150168ec302ede64999450b0359b368e3acf00bbc9608aea9c5714dda27888d63f60830cfa1ce2b224b854136a204dbed8e034cb5c77f9b86ea2d342bf3a0b37a2fe3978e4a9c7d881655014bb23d8617ff04f6bdf39c01da6a324ac58805396ad35733e42629ef4ceaf840fc83ccdb66e96c6e148256059e3b9eb1e8de429c77f8fff51bc994fe35900059b044c1ef5b336031f3b67d3bd471db0b7c8138b36ece1f56101e9298d7f222fa9f48b9f195f1dd87a869bf8cd0810e424b82cf6841e686f91fa3c443c7e7e547f7b920b774207212de69e7e4ac8d79b45d076b82d8d8d78c9c55aa6f57a7fbfa48e03005bb65fce5548f3fe6ba2af580f5881ff739a098f7c5841e4f1351c5afb3258c39bb39f96e751c043c98b46f218b44aeb90947d291cf6042aecf045cb51fcd687769eb88f07099d3718de8a836f7af203028a5560544f170099475f374f8cd296e4daaf3963d3ac620966584659600233838d0c5c62796df7085b19d42982315cde7335f73178cecd12708124004b937fe29ee2b72fc91b94e2a6a433b2a35449bbe0bae6b866e1a10b4021357e7dabc76c6b9eebf238473e953abcedffb63b4dcf4f73dc21a2beae5036cfec91e22dba6470d2ce404a7b22883b8735567dca179df3d908a725e2e5af4201b6be97f11e9dd58ec44256e2fc223156a07040bb3008aa633a70c76879a4311918a748c98c9f2e485ad45b90b9a59defbfe2741b96904f1619ae66a70180a1c3b550cb2fab06f80d4fd2ec44cfc09ed26da85163f7c51e8357ea149774b77c41a11dca2b70ea2a6f82375f61a4e1815cd019220a8ce7a24b6f94eb3aabab0241c8c585c1d35422268a3c9bb9ef43d3a3490bb231fab37a466723ee47366d71f6131f52dcdb19768a911ae8d9b11e31c946e0a663171d53ec51688603bdea9d2830bc87ebe860c8f7bc1ee1d18980f95ded0b462764d840b70d4dba5e022110993cbf58888ae3bd6dff8f4b2e1acf367df31d03375e45379e33defb73b2a605f402d364d8b9f7e48223c979239ed5b2b9707555a698bffb93200ba565b38453c9452186300ecebb1294db3a092b3ea1ff78ee1bc1f85a51f50d1fca7ca0d634a027ea705ec6cbc10ce51fa13afa4e7e756eed9d19e9c0b8a9daa9f00b11d2248ef3dd74bd01ae7a93ea2ad16fd0f0a8321a67d39b07eb49418f475513075082fd9e0fddb7d225d064d354c2b3f57343220211cfce889e69149b5db154054dde2736df5efc993e743ac1445e676d6401b5039834fe10c49011e3f03bcae6cfc3eb2ecb8f8055d6a17de626ce8caf8d8061f7addb6fc9c229a2b3152bb17e6c40ce3ff89acee7fb5ec800fd18ad698306e2c25146f22aaa62aef8e054ae7730d2dc0477c51b0efe2148ffd7daea402118658bbe0cf265e29a046258d3b3977b0305d30bb496e24e0ed6d997b235c310f36f4cc884abf0fe62b6fd3f164914e6d78c6d4abc9d130a442163b4f2b3234286ab7b361ad062c6d6d4a2908e3033ae5db787717a6a4abbd5975faa48ad91738d0b29f50ae36d0712fcb86ed1820d9bea175e295c0e9213be5226414718842d3539d7eedd89d6459eb50cc34a058b8b453d38890d76893be1de65d6d2cc8d23156e2a414073aebea846bc157a92feee6f6a256fcf4346ea061041774103be4161229c079c5a529e3f375256f9731a60d7c106aea032927baf6b3991c2bfb69433a3f21bdb0271132eb43e027b404cd9a882798995351facc5acea7b2b006b649fd1cdf6628fdca1e4fbbc71006743ac2767501b2116567b911deedf5936175edc26a65a6fcb29dabbc3f8db466a21a08fc34267c557e6371f23b7ab7f698565d9161b0a658cdd82278c7c0f9728f5a63d821260d2b33428f728bfdc32e3f3d3050d2b87e19dfc9603363b2718c039751746396eed60cb7fcf3f7b965503d6ebab7e04faab921a143c37b8fd68260f3f4e6e0ee396876c2df262e5f55d145e410294d1da139ecf80c792e12f121862b6edf6cc5a9de9403a0d141a1d4eb8ca2e8aabb6babc44cad5fd4d647ea147d00e122633575f94b2d0f10a1e34570b0c2232505e7a898bb4bbcf0000000000000000000000000000000000000000000000000000070d111517212531""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -a12619d8176840867fd76c85b14a43f92b39487e19dc0bc5078a6ad5bb20ca92ace50ce68a6bb9ba3da7e58c2a40ad87729bf63ac51a2d4a58b9481279ed7d7a4e6fa5cb2f0e044555d05a83176c203f85d02157a149565b329a18d0963ffc378d02874aa78fb009073a6bb453d992a240eb7ef84149d000acfc8fe56af5be9390062e082991432664122412a2822114b6810bb581cab4650049894c824892824c8228020a3472909271cc28208a462a0833129828301c83401ab2849a48322097055a3628a028488c285194824d624282480206042281428624e49265822440e1084a5b42015c183163228192b4295ab82983b63101816d490004d4480e8184858cc805e4c089c9a05122348ac4b26801a9480a2902cb9829db108623230250488e439461d4204a9028699b960588286c94200c089484d3a864018604540811c8a449a12001e1c46d002106d1248d0c36848200819038210220128926280341495ca66c20b9880a1224dca6911827059892514c16919a06000a090d13128254140892406c11a76452c27054164408440051449289020020017209178d0ba801602869240865ca8464ca44652022218b082859c210219120c1b24c594441832660c30611e4326c53c40d50340dd31405634852e08409c218514aa021110366d022715b80050815708aa401e4302114b68541b004e1002e0103200402601a252858a22c8430685bc27001096511050699482ee03424880440daa42163062d944011d8328922a9310235210a484a54c02481c8681bb825e2448624c821e0384e1b150c8a168681c80402922981046d62444d8c08600c0904d0b245c092480aa930201810421028cc886992c870da00081423601812481b3322892652409884548285524089a136292326402028681001309018429910405a484d114692240860d1861108122d53b211c2c24c24c42019214da3c4500c2410e1262241a450413492214665d94091d22840d9c84d580426dc8650caa68412282a01a71188464a84a46021c38d0c390a8b081222846c1cc48444228642120accb26493328adaa41001154a94108e891406a412458c9680a0082260b208813882e24011244011000464482612113064622872e0068493004523012218b40408318d584280e31844418891c2228208098d1ab7852244804346261342861b36094c046c62040219362911026d24c6094834521a878513208a141065d34211e2486e884860003305db340492201008a12864446501936c50880c1b324c0cb4809b3086810224d48221d0b2844c020813478e0b874051342d238969db148124a4884380701c104924002913174223a5404326111c3382894465e410304c3829242610433690a1c8900cb4241933855b9490140364198949090269c2c04004978d22100e0cb8881c003193240c11022ae4a225e1002a62200dcb0821c9064d80104018a70c5024224182708382285aa4448c044a09160d48a42942442a04092a03174213059158b85040006a112724011726a1464dc9c605c0807012430ca4106400a245e2804008282cd4b20c58208688922824472893b829243520891812d3880ce24288e1888891462d82925050962d12448809954062c648081006132270211549d8806520431111c48c82b8085248210417451a94458cb86589882c9bc6488c206cd346828c0490522885a2460c1b08258018818c1262d9108e41a80523b7719ca40c1202425816724c4610038068144308082431500411193861a4306e14026ec49445a3a489e1125221141013b8800287311aa6701a398423a56de2142619032ac3266953281153066a90b66462028444b290ca04860a312e9cb2300a492080162d5122908c180204274220084cd3141151262d1807840b3608448824c3840d1ba2088c822008a2891ab62414c81064908012c6492093284b02615cb82d4094109a3060dc220064c86c8ab45123348da3022d00c830a3126a044668e1240619b9642328680bb105922809db302450180a209188801062a3b8116298319a266263288a11892d41289283844918c82410c1111114220bc88904859191286a143148a4828c51c480c4042659365001862422870c5a969119308d00a665e13830ca384910a00c0c923153c685d2c410499465a3866441801013262e6316000c49811c160211b92cd0c0497cda1a2038e94cc9434a919eb67de0c9982db1508cbb8471e4c0a2409980bdd2c41d4ada62f2f6a8a783ad512eeeab3b46f501b0a0f9a5c6e3572d1ec107bc431a95f7321bd2bcabbd951b2a544666141d24e2c200fcf2eac7ac8170e137971121862e74a9929db36472e42e1d928ae6ac4c15cf130b5fc7ca39c87dae2327f58bf048591416996bceab419a1dbf6d64bb53fdfc4c9ba426a6b1c20a21005fe2a80ee053814a44ae6f9c5a2af37785f5360f7f9e89e0d4d9df1a3a6d37a5b32017a7ea1196a6891c46ab6050b8e3af590d98eb670607ca1f3d8069200bdf40cbf61981ea4ef96392d56e2669e65784f57fca0e0dece5897fadd854482bc47d4407925a98750fd0a5a94a891b6cf66508e70e8971ae4b8382a7bc93613726eb26fe38931e4c5f384fdae6014d680451d723cf65aeef4a64609aa7d1df828ae3d8bd422e20e2b5cd44ea45d27a0c7223d72f1f93189a5eb39d9e3b622987cd57be3231ec5d6e9c6d73b54db0a9430c203bc6424c9783941bcd85ad59089dda8f71b1e0f620cfb7a24c0e16dc68681e6fc7060e28d216e5211de4c405b321ac0f7053a3eadc7bce05b34afbdfddbd30fa79abb5524a2600e83c935d70e0e31d31f30d14ddaba909fd868414412fa11696cbfe7338dee676f146e5032764e830897a022ca3a1d5e0fd78f360789d50a8f885ffd6ef62e1ef686f3020c9592d675280f9f99b4aad173e57a8ef11ad450c367e220dbc1f76f1a549954cf319cc859b8fe69b90aa0f63033e93a454ab569c570dc99fab2a5b42ad091904c31affb3569103545dd02e14621ffa97dfa373dcba17d970dec2fa02d99638348202b06b82fa65e75c2bab28a85ef546e760921acdc7421925aabe2f5af75bf7c361f326e3521d95763fa507607c43b2056f16e0375f3d742367ce49b841178a6f99c32fe99db478d78fd4607c3cf02823a6fef86fe2f77017b028f3518ce40eac99a80e0556b4de6e79c26c1bb5369f6ae01bd86e485ef4e45dcbb795af382d151db6b030c4d1e7fd35e3f7a757ad89a7577e65626da96a8a778763a4c764291b88436b7f731e62194f59cdbb60089b8f09c938e1b0055d489cd35567dc7748fe2e4dca6fd24005841daa87cd2a9403a869c93316f7acc22ad87ba0b8bcef3c0e270fe14dadcf6f95306fc2caa8086046ea8f1c6c11f304eff5a60a3a3c3390c9cc91616f78d72ecd5d9cfd2cd63a745433c3d96f3b3492df5e301f3b9576a8ea6f807e19ab3b75ba9759e6d325300a76ef7a8df818f43a2949c40f2c71ebbeaf5a21e2acb0b3b493349c82e7846e8740ec0ebee35b3e73e197d4128802abcfb9c4d5f48e1296dc13e868ee67ad00ccfcb0b09ca4036187bd5bad3382bc54d85d9b375bb27255276c2528fd2dde64770dbc59c49b4e000d1ac54ec66bce72fb50048073748462141daa2765d237612317fab755f83f2e83d3f7d20cccbb5b7c3f16a8d56e061216df7c1827591c3b75a46563be548840be63781d929bc08aef7ad6523d29e84bab02bc9c7eae34e760319e9ebda2fc6e1082489c8493693da37868ba7ef00b4048d555065bee64dcdbfea9d1aed92943e7a437fba543675e749790098da3a0774abd3d7bae399bb68d283c02032b0f3f39683f66eabf5025b870a16670f5c1ee4efe3ffcbbc3bf0da235ef4767f4ad8557f348ef0b49ae214a1ae4ddc7d95b74620c8c4d838cbd842b40229c0a0636513f78d8aac02f5862cfa8026acc57157cde593aa4f5da5e1a7293d4752c5a5e3e8a4a2789b759e392ac4261bbd6eedec10d496d874b8be5df5adc9819ce72305a4164d59122d59739e789229941767ee2e3137973264a9d15dbd151ae6589f497cb7d5d89df571e7392bd452e54e3bbf8376665e0a6ea8495410dfc268910f240eb2296c547633d86b0d67f4816ce21f50f771d093c81850f3fd0e08d2ae9ea659f636c13931a386d9f26091f47becc5d3a9e8cd7d7608f34eea7353d92dfc8bd73938e616eadb59c9587ec2dd946dcc71558c1e1b3bde7b3c576dccdc787687dd3a6e82f03add4cab5e703a1b49d348f6dcb270d59ca35d4192a4a2f4d34559996566db8ad704f8ccf5fd993d6fd7cfbe95e23d4832f37d59174c29ed5f6e81b0195392a6cd8e6d98c5f07225df8e9845bb019876971f6d7bf9c65cd14aab830db62bdb1909007f6e6a3e3f83cba9b2b1dacf01158923f078cf0f00b1c7e2a6fb0d58ecac00ba84b06ff99bef03109d19db64f641620c8a9981f670db917c4bf0957283547cfa55ddd7fe7ec05f1c3b3d11c0708e961a6fcc2e3dccc3fdd72d7345f51c530d22f3f8132f117de2c515935175107d93865f3c785109efc56bd9a7a8f6bbf2e0b7b79cc9b1b616b937b6d85516e48b7acf6106419f5845a751c7dfb247d8c8d93e24af0e5a85706a7d0d40ad1bf7e7d9c118f9748c40ded2543f83059922dca232968b88ce0b1755a693b5c57bd572477be7a1dea9b119b80830832462ddb89aa3a641199b15b067930bdb10b7ca4959019e700f065630ac1df5b8b4953847462ec1e9ae3d7152506aa92f2109b90a7ab2fc016868f627b5dc5c7e3d37da672a3ea4c3285bafb72d4db33373acf9d46406cca5d8823c3bfc0aaf8e91a9aadce204e2c10124e48d9482b2c254d2f221941e619d45ca9c2c7dd23c86c22112a59ff851648bf891d12bd6a7822470a8d934b3550c7fd8a1fa622c0da69ca2d36d8c5bf85b1ab20bd286f8c0c50fcb40a3decbf231a111a8637a7a97311ac3f620d7ad373965079b7a6b426173abddda12aea3d5daf9071ec87379845335886407b9d1a5740b5905ff06a0d0ea48934828ab8e80a28ef06483965ccc78dba14c1dac75d63b0b636131d43d6be22a7ac1e6fcdccc36229ab90e1e22e48d61fc6f52d177804f7dd47131fa7d3452fddc77b873d97e2d107ee6bd610739123e92496f0ede1532dfaa3d1dc762369bc76b202ca19295c5fcc02b59d8a744c487bf4ab50802564c1fde84678a3fd04fb21206e3e72ccc64f617b675a394dc1ff13cd220f09add174c418aeffe992a623c5cbee9aac03bcf5fd57d0520bd025b3332feb1fd4fd60489c391accfd32a83fe60eeab20590f3d8d8a4b5425df91ef0b7aa9414ae253896f05cd076f0fdd7954056d1b06aa5d35eb552422b9f77666cf477939f298476fc627c5e053fbfeb94aed83794e85e43aefdef8b6eaf6e2f4615af9e7566b9326f71837c423c91a98edf9bbba43e48fe49440a3d3957738c54e1aa6f5293e7ff2969d046111af130280745eec959e69703f77e9ec6906f417e367b3d7c093e15a6413eaf1a461dd00b5e0866114099d77ad24f45ac13e2d4870cf764858e7530cafb5b9d23c1e0ed0992fc0817d93628ab47eabdcc1bb781c4a5443ae20e053bfc58342396c2bca64d331169e316b3df073cadc87b4c9742b26e7c9d9cf9493e48e148c89d9639551c2ca98c843b27bdd9b3ea6821d26572dbda3a6aace7bf6102f11e91a64bdcfd83bb75ff6fbcbcdf33f82d026ad8d4eb189126573fae906f4104a668d0754c231fe0418e3644f64c1741db1a4c9a45554a12a924bee0c513076268421ae2621938ffb41394c80737a890ffa44b236329caabdc3d162af0beb93c3900c5bddf154f53f29f6ca9d3c04d60de97d8fcd314eebd93731677f52236793e423d37046188e9753fe42f475e36b2b66b55757958082b4ade20e47be6ea790ddc1d40f71a01adcfdf6d09d9db36707c13a66475e00bb98335eae6f283a7626c03ed45d5e2e910c0f83b3697ac58a7ca1db4076b1f8e80d88da73d6a0f786fe7b34104c335aaf53b9d73b89d517a62337729e99a7945aa32b8fc6772e735a649a27e6bb6065012ef9514bcf29bcf15581dbbf52d144d254328ec6c1030f870478b20d9fa844cf5db5111924f294ecc4039ac8e594942f2e60ccd62a244e224d487741218fb169e49ffcc48d6639ce66409e1f9638ecda661c871ad7a7752f8ec9b3af5a33b13fd7f816e97f300a506360dfa894e97428f8dc9ad64e79c1537945fea2b821d2fbf738ac4c126031e5b40d846dc3ace19ff3a46db533ba71a09b986faebb61ee77a709b45dca1b3c4d650e801a94b992485b5eaad7479631127c5b5a77a6331f8b2df656fd3e30badec74a0c2e2fd505147d3aa24ad26440cd7d724b7fea346476176a1002be8f4eb2d0f3b65f17a8050f77af6bbe2efa2d18c9be5fdc304f4bdd5ddad9e5c8fd4c4c9ce65529aa846205bb1531ccaa83bf9fd02de6bafa089d73a795c0d7c084f4d8c344eb1f00aaef38c53e0616571e4b0a46f5606fca5a9448b179c889ceacc444b33d6bd01dcfbcb09441222dce92cbd889790671fb536aa22ccc73ec34fa3fd63a2b2b1fe770bbcf758d9e1213fdf4014edb30eab83de89ed535947f34112680a3c85f18ff5ef055dc45403eafe35d22c741e1d498ba0014a2216c6b8791828c910ae231b717d75a61e07a0da4abdb846bf407d56cec5a54501cfc78e960532d3c440fb5c082a6d16c47b0a9b1d2cc7c415361ef20456c798689d457314378ca7bfa7812539481594a26e4cb0cbce956362a9e751272026706f95c560ad41ca190534d734486ffaa6182e6995d09543c538c4c7e066c3366fd7824a87ac587a9fa7994a7306acc560ff602c565c5ba028a624db4d9f"""), - TestUtils.hexDecode(""" -36DC7A310D995379B796EB8F9CA346EDF60DEC7F6C00AA311B3E09EF96A6795C4B077C1D371DD8D4A538AEB78B81927D08008E817A6FC6B3F9B14FE56EF9B2664E76112F214EEE848E67EF33B4A4E26A2378E9480CC7D25C369E6C25A2673B946B635B6EECB5F5F1499B484DCCFD5165D6F14CAA8E1EC9A9E4FDE417403720D7B4BB30060AB95C6F227767D671B75A1BB5AC5CC33EF0509C69652748251869B072B9042618071233B48A9BDEBA330F0C450A2FAAE79291B9E2480D1CED11FABE56210A80C39F25E5574356CFAA32E57782145920D6C0D27C3AC7C63DED6A770A5A45119FAA92209F2A066AB90FCB81A886FB87641C550368C1B412E43F4FECC2FD659B2BDA6B7309797575DA2893314DAB058DD92C7470F570EC0B1D9C9A149FE0934D40182CAD14D5B3D98C4B7454CDD2AE7E54EFCD554AA5B458888048BD5201C04E7D6004FC2A597DA781BF15AAC9748B6659EC16602F10AD44145607917C3599A1F53DC95839086A6A4FFD66F8EAC8AF8F11C4F2EBA3B58C46B93D0494C4CDA4E8B8FF7278049D2B4BD7BA16BC57678219EBCB5E211D51A168B5CDF66453412565B9BD606CE29A5A70E60F3D451D4214B0A258D6E9325EA5196C55125F0E115B14FF34FF6B172471C2B4917FC36B0DBDC82D0475AF56249AB9297790535C0F0265D2A853DB0B41B418072D0ECC17CF91FCA86F6E10762EBC520F0AADCC3C79EFC25E9692FC0A66389B15ECDD1377A9C3D744CCCC4BD160FC65A45D4144DDCA04E5408576DBA6D5C875BB4071729361B0514E8B96405E2F48D47138D2D2DCF4DC865F717428FA1262DB0D2B7B1A356E9E76301D38BA506456B4AD70ED09B0D5A1375AA6E132D7E06F8745E7A5B5E4F6455F4282A87D2B372C40A34C09699AA8C2B2E060107BCDE0F9D99B64F17DA5FA01B6DA87B1738882976B21AE12D1BA0AEB37644AAFE5AC20E7F3F631FFC2A24EEFB61DC37485DF27FD9045BD9BB5D3F00B9B2694CB94B01E7A4F0D909B8612DD28BD64E6C1C5A612CB30DF6004276FF58491B8129FCB0B539CDF891A97AB58DDF04AE40BAA5781C3AEC65FD7E84DFD0369A53CF36303270DC80E3E428854D82B08C7AD022BD99AC0851B16C7D8D462DA21126F70D661A59E4D0FE4441806DEC48E37AC4A271F15D916135408A2751CAD53564967196763B512D52240B2B0D3D924B83CF482B5316B7988D73A16B773705097F5ECE0027CCB2C2EFF598B8F61ED4D6BC015E56D4549432A6A95328FE3122EAED0149E2144E4CD2262C7FE7495E41E0AC9FAC9A11E21AC940D25E74AED8EF6FECD21747FF8166589B7038EF1DD504F51E01F1ED911FCCF44949638AA6E8526F0B9DBC5E536FE2AE7D4DA9DEE66402A45CF55D0137FAFDA9207AA7E22FE396455F2F43108961FA6B0339D89EB8ED7EF13B936E3D2DA18E5EAE45B05DCAF5D845DC62CC55553E37CB328AA2C649ABEED0D862E8083962B81B84A85EC12D3CE5B600123AA7CE4764139BA7AFE5CD02F70D06DD9AB0BBE868070A9AACB951D362E2606FD940A8F5BE632393E0A179C2A62151A094901F5625D952D39D7CAA87B77C4919A8633458AD9B6DAA16D1B1CAEAA8075741094FBC0C08D30D9956812C1D3A75926C546ABD78A2B9D44C1B6EF8D6EC2A2EA8B7C23D0EA57E1320ACFB576FB9C575DA98B714D6B01F03364E618A2C03BA84BDF0E5D2A0403B1379416D87B5E022BD958B0C9170E82F8E9A727D39C8F7549E34A14792776AF0D72A27FCF63EA985B3882A717091EF35F5835D4DA127554B6637AC313BA3BAE8170B9E70A6DDA2DBE813A49F045D8C3A65ECFB4D5F71FC75AADEDAA91A81A958273ECF0CDC4512F0D0ACCF9D9D001A30D0B6B2D50BD216D6086AC5C9DE7388A7B1319F2E9E6CE128B1F72F765804E060A8A92C93295A99C66D6D79BD7DD4F7F02317927D60B2E9FD59EC3F95A874337228339EC673BBBF53BF0FE1886A4B14F19CD7FA9B771894377F904EE8BE48D64EE5D40882C684C81DA3198604FA599DA8D4EDEE8EC3294620B6555B3BC9627D4514DBD1F7E3E9DF7B56BDB4CD395A8CCADC184B2B8DEB2AC7CBEC6C96001EDB67E6CF6F872469B110097C69EDE1121D22FB5B5AA4CA540474630651A4F9E8F7B0ABA5DF568D882626BD158F925F8DCE1D81668EF7CF770DC615ED0F5A807E25991EC97BBF2F9E997A532A1BD82A2A616250D2232F72067A17550EE516F28940D8EDA9CCC0E02EEFA496010E499E62C50B03F1D3C1571342DB8A5BDE1F432F7B6163BA3AEF35656434937A42C4E1F473331E38467DEAA483189902364463832ED8C5E04E0195D3435A6FCE75EA3BDBDDB0A0319262083141B1BBC0C278CFD40319647E90BFB51374B0AA5EBF3C564EE95B7AF618669C935756AFF3150A93EDA92F0ADC29253758A6C8A83EF55F97F1A4C0DB566668F30DE59D93D8185BDC1CFFAFAE472E0B0FC4B1E16F0B748220EB2EB85EF127838D576638E738E9F93A05D41CC1264AC6BA03B202D9E3B06946CCC68DC15261A029B0C5E91DD81EC1D79BC51F74BB5EF778F00AC091513443308410F60AC1850F2548C8101DB3B6B4D453541E36F0ED57C2C14F465196F8F1D0D3ACD49CE3252BAA0C10521311B8B8366C579A430526ED58BDE92FED3F0B359ADB31D67BFD212BEDA7236DEE4615ABF13C856CCC93DD02AA28D1CE1F12C2DD69FEA828BDB9F4CBC9242E1017D1063A7BF842B00C75243303EF9060C8EA501BC73B3EE470919443EC91D1F0D6D0F23A899AB86F2E8A0898D318BA520DD15D9B24F4F10A1B9FC52457714A151E075BBE419E4216857500B8354A8445B5FBB526A6E008229F33D8DBA14DD42F424DE3675E704DB308048B2D17904DE46B76622BA08C62F17EBA3E9F414A1B10921858832EEFBC282755B319E176ECCDC32A25CC5E76479AC112570AA86518BB1E6CA3F46E010E8132C0A1E8273403C5C4D7046A05398D461CB6843D70EEF8C94DEA5DF53CA1A4C7842AF5DBBC6451554FC7F9913E56957C51E0A602D882BC389C5E5C7899539DBE6832B0AAB5EF26B2C96CB03D1795179A62F748CA501CFA34D5ABBAE3271AC1F005112645F10863AABB062FD2C781E4573173935B5392CF9E88A1A31989E1B8E94F77CEFBEC591DF6529C6D2FAB72E678C534C4EFF40177C41D02AF0EFEB6371835CB55AE0AA99C0653876CCB56ECA127A0A1DFC0F9EEB49525C9A5786F618DBF57C41C5CAA971A9505BECEA8969D9DB28B0E707C659EDC42280035254E91C522300368F49F2C36211E455FD620DC956AFEE41A2493BDB2B0B8AB78E0B838DA6584FF753BF88CA6A523042A285F84ED90E0FD5E28F75A21B53F618145C16925486DBF6B1E7D76585D0D117EC562E22239E14A49ED714814F01DE2B250E9B3B6A1C99D1A71CEDEEB3ADADF611C4A4F97E1B26AF9780AFED5783129FD58B1232C7E2DB9050AD3D494EAC254DC46B0461A1B4B63840621D45ADE97EE5663C9BD8FB7261152545AE35536611B5C65DD6D66878DB71640EA429F801D6FFE291B06062EBAB9B416DDA7D261A46E58B154684E86176169CFDC4A60EA38300C3D44F9A4C9DCA0CE1BF37DF8F786F28B5B3CC7B0199D3322CFDFD2CF88C5B794C69F59543FB985890471DBC93A313992ABD33691CCF69B96A9396E5F55B54FF7BCA82A31199E5E81CE94B6B523EC5C3E2F2884D8BD744CF0C072E29E4B542DBB370FA5966F68CB20ABF40619E76C099BC7A9A373707707624E8999D4CF0A75D4AEAE113D7823D7D2ABF54FB4E68B8A6A57A198B128DC69584D2DBA473B6725FBB8EC9561D6614D606ADC4FD9CF449008C0D54BE4F62EC1441FF79EB59442AEFBDF1F0976844B4FA3969EEFEA10794FDBE35E89EA52F50AB26319BD1604D3FF5AC660431F1073575ABFAEEA00E1246DCD1D9399939D655C222E19E9DBA5FF42709FC11E7E365D7F7CE2274FBF1738DC5CF5631547549F2BD4DE896C8FE039720F5E0149BD81533022DAEE22B93A3AAB9AA9DA15180EA071D98E9FD176804A5B04D089E9C2D386271A8B13E7D668AA74BFFFFCDA3B4E528937C41D43A87DBB46C2B49B63BEEAAB978415536A87D845F6C2484F21D71D0F904438C46E7B0A3C6DE5ABC01C6F7CBCFF21D3E74AEE96C20C32884DE4EBA0F282C0FAD06BD9CD6B7B5031F149E4788F102D2AC2C99FD09B14A4AE3BD6859CAFE6F5A494EE8CEA29F49D871B79BB66AA6E6EC3718B97E83765E96D5603B209027BBBBCB09EE6FDE3AEB65AB1D73684820AB1FDEF88086B93B6338BEC7088E04F5F6E520E3D715C6C5E5B79E73B9E7AE1C5EDEEE4015860CDB9FA21FB434C3F28AD865042284A7FE9A5FF47E8C6158DD83EDF28BFB18DD5AFA07A48BD5AF25B9644400CC976A9B0FE9D9071E708113802A78CFDAED28378AA4FD6FBD9390D8A17D6500A0E1835652C7E0B332A382576AC4381CAD51A31E64E5E24FEDBC62EF9D0CABA0C8EBD8B94625207D0C8C1C6DF4EA2B20832EE44D1E2DEB799BC97B7245EC404F10764296E5BC4A919EC24B4F5F7D18692FA8DCDD5BBC170A81BE7590B7BF4058DC7BEA0C545BC85F0B3F0936386C37115A333285451CCAFB8397F1AE1B56D0A8F884BC968E729D622D21FA26B89BA2726C91E6886838DC9912797FF2BDF6800665C1D1DADFA4A240BB9BBE21B6DD750389AFA49C5C366ACA5E9C3B31B358FDEC42B0032D9E2C22112E43BED2023B364DAB334BBBE2C3B669EF700702B5D1837A6EC15CEC2B2036D56B8760129F593A669FF00237D26BAD9F9C2F4ED4018D998E555D2C3CA1D53EAD6A1E27906353983D4408904E5FD9D79AFEFEC26ACEA1F39218C36637977F6E2F3F6211AA06AB9D5F991C76F420B152BC95C4BC10047E107CC82E3B00B2325ABBFDB0FFB2966D5FBA0EC7E8DE1DBCC053C4186AF23A6BDF3F14A7186665AC2682FB94B0E10516D500B7F67BE4BD2523E194A1ADD8B5564FAD9105C86B6D16B08AABA604419D55F571F11F4989197144DD12867D1636D12800D54D36FA88C620008095560103366711B8E3AADD5624FBC7FF51318D17311F02A807770466AD559CFDA0AE1439442E4413944855D4D0074D529CA8DD621DA02FA98F46327A7BA600387EAE5E724D64A82E94ABB760C891EE39F27F0CAE8D1AACFE20629DEC5DD9BF4CA91E65BF413FD2A9566B7DCA9E500C2C328F533AF2A957E46D9FB11F0DFE99127656B1D4BE20C946BAFF58E5FE1A9ED282ABEBF6EB35A35AF324DF0A858CA8AF507CE43D228ED81D863F7096044A084DAA37ACB6AEE98E5A94D363963D4F852B955C2F076848092E6199E07990372E56BA1D590BB83D0C7F834C852CBC39B666B801CD32A0C36B034264F3BA6911A719001FD0F4B63D2D628FD0CAD34B4C9355534A8A38512E758B110F48E5A09B504D20D178508E09B1423A1E61164E7D138B4A9455B95EC8EA786F5FFE67806781F1E619505FD7DDE9A904E9003CA7E5EA1077C94C228D36667031502D78B3B52C3B5A09FC398D8B5497B6E3F0C5381BC99DD7B11DADA2DCFAE352DDEA2C749F8CF5AF39587083C2C19576EFFE871AB94D1C7CA2183FABDB74B27A80FC4F20CB86B46B0B7F86384540EFF1C888168F74634F2C0BF7FB54F7002EBF90B6C4B2B25DFF068DFC7D087A27749D6C36AB0A33423044AE027DCA8C42678987005FB9DE5C2774924AD2A5A8FD2E89C288975F89B5C0EF70A20EDAD1925060A12606A9B03626039635BFF332A0E6BDDC4F5DDDA209AF8DAA0FEF045FBEA9523D04458FBB0BD81F65396938436AFF5FA66E997AE58D64E7B5C1B589558B3DFF6D035E31008D2C76CA426B07F1644F609945909DBD16559B36461CE882A361D0415A9D93CB98A5370C56913A299B2DD1AA372CB75C7E590A9629CAA6C439CC5C7D94A21F36F998C6FDEC1C1721ECC500ECE1214EFFDE65E479D38C635EA223286DB326EF9B19B3CB862C96C162D3DE238C2948E7613A0FA4843E39EAC51EF293AD7EEAFF0F522934C982890F83E922B2BD52815136D0A758B33641C54E7D4E0F3B19AA85859B750E7A7FB80892C3DAC5048767132E2DAC5804709B8560A4B3828B1CD25DAF263A2466AF7FE328ABC84EBBA26902FFD92B0D765AACC0C0DCBEF962E1B35B1195676E8A67ED593B23B2B0305B611F9E16633E77E3F31794C58C5309BA07DB5CF9AA1CC108186318A3F16A7141854C2FC8B469BC0F54BCB22976A3CA05FC2C8E23F1B6A891E7527F204ECCA0A5400B68565906E795FE4DAF52ADA95A9883676F9110B14CEEA389CE9BFFBB5D040E60D3D03C4E6D6CBE9ED53EA44B1AB6ED7EDBACD0AE0613DBA5A5C673A534D48B539DC85F48175F13404016C5289348504141338FE958AC28331853AE80ADFEB49A6637936BF82FB26B95295B2E46F4F9534720A4E86FF18B31335877C9CBA96A9B450C1C8C9C9862E51CFEDBE3DE5C8B901D792A179AF9A782C330035A14CE6A710D398BD28416CD72373FE216744F6237B38B97351A77D5D0DEA1A26A0A9A24FE15503240933E1CB5AF458E6FCA8624669A0DF439CD7FC13F7A1F10A0CC7DB8C6AFAD9C99B5FC45A7C565B5DCB74FF0EF426FE7C260D3ACB1E9E83DD8E6E11A642145BFBB7566D582D0540D7931AA28B7F8F682E6E2D90B6E6812FF8B7F15FCD3DEE686DF06E8E6C456C99C6B4215C4E874BCEEE3B4F94BA825C6A45C2A2B4C6DC04F8FF5939C74E7DA37E02D8230340C6E2AB7CB82BD226DDC1A7C7BD0C0FB36F71F9C772233132B8871A0D76728C2A141741C2662438C5CC7B129A6C8FC587A0E475545D176818B51190F0F19E91E05C04477283A0A7D4D646EEDA3BE64459780BAC1862D83E6B99C5731DF91F0CAB454E70A0D94D934D0CD83C8B8301DE282F9A1FFE49E73EDCB520C016FDB4AD02C261DC1A1E73E38809E60F91A4E38C69EC70D2A621DF0D21588F24CCD59D331C69E16F0F6BCAA8F24031DD5718875BD9EDA5B420C116E4316137D4B77623C9D73D182900BD7A0F90A193CD16107E692D469AF09F74702492E22C796B6B4A960D47FDC571B4A264EE3528A0F5A9D66DDAA33FF20C3101D50299EDA3225834C9429976EC8E590C6D48A721A14972BE70955EC1A0348D2F84347C1E8E21EB0C1FE67223B42A6BCCAC43648F3BB5464121180F8E3E682B4B664D91584AF55FD1C7D2E6F79A93C680238D29CB7FF36D259CB703DE03B2EEF6DE0CB77AAA8F49C61EE482A8DAD30824E603411D5F09482DC84BE794BB6EB65A7BC1DA92C8BC8364AA88D4B8212561745BCF3CBA0D6AC8B8AF80373DE3F44EE39CA3CE4C5763F422CD4E8827B1E7BDFF79DB990A52530E4A1E21F6CCDF50A322A086AFDF24EB5FE4D99F1D1BB4D6DA965D168E9726FF7A4C82F327A748DDB1DA5A3D0E9C8E0B060872B009CC9F913D35D94FAA912B0D6FBF233DEA3AE3C2A4E35BBCACE21CA3E5F7A7B9A486AE9D7A7D2E0B79FDB11D87072F1B307402BDB22746B86A1A0E6B41433D5BAEB2048ECA53A1ECF895E9EB9BC5D6AB5D5DF72353566BB90578F12C6A16A163E95CD35DA27C79379756141DD05C315B466871E2B726B8821FB6FB439B49430CB3CA47CD211D03DF40AE4A0BE87B6000BC9C75AD23552E2129F47AB64BC9E5E1620C99405CEDF7BC059547D547E2868A6D470D813AA5095D0AA4BB18D91964988391EE6F05DD47CA1DA0423CA238C5E50D43CFB0527973506B9F1DA4A8055C47D1FA1E0DC783CE3CF75FFAADF574EC2849631E2551368291AFB5F2C40A4F1A184E37A19E511F482B7920F6D51B13065E6327F3C21DAA7F73986F2D1FBF375DFE2505C0FBD35F403D253BDFD0BA1B00CCC5A20B683D4F1E1F2374FD914C7D674901A0F01BDFDC007E8021013BB9A2F885F0699D16805F9F2511A0C7D3CDC06E36679983A2A0F12662C88BB7DC643FBFFB58CB51AAB3CED28553910D063ED8FA37FD756B79AE4151521450E552E4F2B62EB6F6BCC8086BBBD30331F3F2534AB3ADEEACCF2A6E66F205935A167FA1D5C747936050E276E8E4CCAFD9E0A056E4AC2AC08738BC3A598F07E933B0ED285BACE3D24AE6FF7574351758F983FD7EEB3944473EDB4EC9A9828A5FC656BBF04DC623C75F8B8038F3699BD5F255CCD3EEDE4FEFA12AFE8F64436DDB1FF2DF100B09BEC657DC5D2B18E5722D5AB30D075D9A52A576B6F9FC8C8BA3ACA6A92E6596F688FF5D2A7E3183B696AB277B0B17F004843E58760683F90BE0C61DD0D1BF9099A865CAFD1BD1D8AB1B7D4AF2F86D51C18D7868BEFF3F6C53EC68FC46EC9F23D1AE1FE85CD97D8CECFD57A562E7E574ED1D0A7005813EB980C2A46A98CEC602C0E022E87D4A6EDBFD7DE9FDA8C02EF85701BB1CEF6013F4869D32CBA56B0AD6EB007591D03C76A839F9D01985C546C39E49D59395B10346820324F3E298C5CD977FC2FF83BD422CA550DDF2A69607BB8125647B389246ADF0095F22692BF907EC86BF8D70D7E8F2C50E35DC6EF34FD1258E1FEBA0B254470D43C77CB0073AEB2D4CE5F6772D49A101052D8CE943E1C7760F2994071644D27D26BACA88EA07F29B2F2050BAC5E05F2226F1F584D17DB80E4056B7F9C60A5D9DA0CC577C6BC802FAB26E570BF017DCC7236A1173E273397E373640ED02B4F9863C40D2A2A7828C3875D8081AEBEF349143BAAECF9089EE736EFF0EF80078D2CA7942FB24A92071D229A1FDD0F6A87D362E5165D57F62D927757BC31964B5DA63B90EB3591552F2B9902E2269A163FF221863ADEADC9BC92CAC0087ABDA02004C0B9F34E5CA8599DC3C4261489F7527FD27AD2B6501E602FDE47DEEBF3F3EFC0166B1EED95116CF43C8AFC0EF89BDAA9ACFB6DAC613770DEA78960C99C9628C0D21FAF63A0FF7A3F2733EDC0FC07B83F107A811BB3C1DFC6CFBFEC105193272A4BF915B1DAEB232E16216E40FD3F9D9399B15CC4C073BAE8D08A4EC42D91609574EB009A9B52F06D3F428F6EA9B0511D8319A1B1299C154C94B103CB586370A58F18F04F5D21AD3B638660D6C04E99D356A7289E37EFAD643A5EBB488D54F4A0194FBC4283A8C4ABB8D9A1D70150AA50F991204C038AF54B5B74F722CD6515045D62276A9E936476F42B282C3B08D9328089AEA259510240B95BD5E81FB9D7E006DCE0DA832BD9A833799E05CAAFA6305D16DBA4461BE13D3CAA95773B98F09230F2DBE13936495C2DF5BE3A8F3EEB4FD211810F4B07D3E2BE1A11CC87079DF1B32D44B6FE7942DF2627AC19FD9F584E771D7ED98AA4C074A9DA5B7C156F83D90EBBDAE78D636D51EB0CB30C7C7CBC1A96273C0AE0ACAD8E15D1196BCB2EEBDA332896BABAEF76B4275F863732D646C24627AB014AB602A47594D6031795B17144E6E2C23F0341422886C1E2512222ECD530017DA02FC015EBD5BDFB319F3AE942D75A55C21BF347A44B300ACCED7A339007A2527EF4499E3BA5DE334BE58D59918DD0CB55B2F478837F71E9CEFCBBC90808E0BEF8CC7712A3B008B69476C61535FF0787B7833B70C69B1EF506EC4F445B72AA12FAC2589815874E9123BA13A17477D61E41163CB21ADB8151658C99F1422C71A8183B8D0B1D489EF436564C47ED8482A0DE9170CD1BC34D88CE76E1B47B84E770020125F718B4AFB1E4587668634FC7464114762A9D74A93E33A5C0CDFA824CACBEB097B5CAC3B554BC0D41C402812D8E43DB37C730A6219AB6F0BACD096BBF261C78E991DE0A2278DCA7D1BE0E5F2FED72CA38BAA86924A84275BFED3B91FC8DCC5024316EA0587C96E030544F631076DEF65F05F98C7641A958313686B8580CFC20221ED50DE4D2CF32461FAACD0174AC46A6949EF8ADEE6FFA3F537228AEDCFFDB2250D7BDBC848AFDFEA67AE53CE9ACA45F349557E81F70F9DB92926FD0CED8C104E6B7AD180C7B3BEB86171EE84A8DD2C243F6869E04C2DAFDF0C938C0768415C56330C9BB6EE756BB335BAAF96EEAA5CB52E554E39E2435B0731B0062376F4730108DD2F05824A798DA24C239724D19F12C6F2FBDB52652352021E0167F31E0F5941C4687DCD13A81A20A0AF05A55D2533280941865DB4D5715AEC293A64AA2E5151C8F44A14B72C0879499027E67E4E2B487612216F6122361E8D34E92C2163B0C88583E3887DA93A3AA0E77FFAE3FE8FD5455BC86AE6D6D5AC7CB7BDF156A960C98B0BE50E1370A43E7D183636DEB2C64B264FC5922D4BD46A8206F911E7A742E72E4EBDBA39B6151AEDF5A6CB4157B375D9A59899808F1838C61EB4388B923423D3879E8228AFE0CEE9561135849A89363F84B41BCB166EBCD0E65A2A74FE710F2B3B55CA9DE2FA9DC163BFFF4BE91F10493936FCA15F5F39422C75233DB22299456D1EA3BAC26F6671557B2A5FB0E9460997DCA797C67C49DF109CFD597BE34C8E0FA0353F28B815D0CEB31DA93E49EF29CEAF20FEB0A8F5924DCC62E830353463245899900304A8C8DB5830BC0E97AB83853D8EB05660D6A9303833D170E138FF6F1C30D9DD64574D5F875F974225DA81ADE3D97924A38F552276F46A5208403AEF82D1E92959675EA6B353E5C6091034A295D9C12C288241055A2334C30DF0A37D2590626A7D1787A4F591A6E494BF55ABC76842BBBD508FE54C5630D11C54386A487A756ECBFC0AE8957E7CA8678D5B9B044117365AEBE79AFF2E6678001D23624"""), - TestUtils.hexDecode(""" -e8b08c99776fe554292851f9d80f785b8109d6edcf9d30b4b3c8c11fe8b2e024e333272f4d72e697aa20953d03f013c0c3800e840aba56daf36846b0e958f7e1a465deee3fae6e45931424ac278b6d1916dc71760b7518643185cdc7b06b1dc0a54c83597e6a2aee0894c2066b5fb1e2439b2782ceec63aee1742d10f4c36793b845d5b86db9d22a200e12611bbd102cabaa00ed5cd47e6cdbfc06d7bee55e65e4ebcae019ab28f0f05ff2efcc3c44a5c89a5e80fc8758d774ddb3554975346aad922319273ea930b3718562c3a96602645c58e375e8b78f38cf636b42e674ab4c5e1a8da59c64100984605035e1f735d6ebd2948b556b056a07ab86f8d07f8cbc72cb7251543ceb39a9deea50b8189face6b5ff23bf62ea3686fc0f97598f36ca445942cf3c2acc5258f9a870eba919b99c75bf598031edb693552c086377ab84aed818e795b70a62c14f84d5d01fe9257cc9df2f4cb2f40173be7d11592e9289eec23ad30a8e5dfba2f6a779464e79cb5b07e6e5a19dbb9a829eca1ff64c0a672844ed2e636903bac6edfce1315cab8751e9f12635160df14cbf5ddd341824e8033507de1f6cb7dd87c5496342a27a8746e94da455ddbca610c7990ed01ae5dedc90cee503d525ec5033258465e282cacb2c0e0ea7457e62d06c194a958322e64a5433e4936292fa700dad6fb7ea4d5689d4e3efff132d61493859aa5436c9087fa9ac5b67419a836460fc9bbb4d53d0c9b6fefab2d513b76f0600d097b0c3eb7d7a82e01ba3abed5354fcbce02cc7e85fbeedefde5652187fceaef8e6c05b4f37c33a752fea5af6160a7da084e41dc7134534fda67c4e1c6b8dabf7bf05d25a0ab7e05c41c4e0070e8add04f20d8c72bf941ca284eae27cd9568e9938adf4f55ab2c40d03bb49c58c6fd8d74245cc3b4922891b865dad534e256ebbcecdf5227b39ac335005bdefe1be10c2b7c969f4dea6f581c278f8479cd7a40a6d369bc5e1fe5e074230d01795dc664e488e4e360b169976b99a0b9d257badf3f397ac914b15b8ce4b3c38e6c758a169ca015fb6fd339c4255c51013e7430c991a006591fd69a069cc2f966c24ad78b8c0a4f4601ea08ccb683e8d427d1a0db844308e86afb0e3f6965af9ccca755b5e2a8358fd2417b46bce7a69b2edd6e9b3fb617dc5bbbf2803a557e33c907b4ee7fa7a9cfd9f148730d48e471097526e4330515f3dfd5e4f0e6c6dd2c2db73c2c0913c82559032c15b3e580e3b11f5c319db8b04ee4a3dcc87a4251e8ca8f77a8e61d67a5586f2494c3be2d70d95076e6470cd3c3ed1b780ad9217153fda872911bb01edf13c13143e4082cfc9fba96f14e7844f3ab040567faef1f03caf66eb10d92eada39afc6d70d16325008f628489ebd9e80913227e270a8c272709658aa843a486039a21951467dc1e5df0feabc68c28ae9e9cdf95f7db12cff0167657328985f19595b5aa33f44701a8f40242a0f33ff9829078abc53be36c002405557c61b9c5585f7d61d0fae020b2ad18358a278aee3250b12bc7f0887d8cf42137f26ca12a866c35876bdc737a22b8a722e71ef500ce958723728aea23748924eab3552a7cd4142dc7e138c84df1251a2ed8f94c939bc7aa0ea4c0ebb4cbe817aeb65ee5f0f9cd407899459e719f0558f8f40d73b1226a004b910e26648852bcb3b08aa5340f6ac6426aac89acc4945b180dc4f401d97a6fc68e3fa4b8ed65ac74727e3ee5da732b02caec13b88cb167b15e4c7da21dbd937549685e8068c3eccad584698291b9c3410aa8314762fc838f9336b6b09c191409d1aa2dd5e2a075b070413c805f116d42f90af6c7ebf8c322bbaa14a5692ac0749ec7df91e5eddc7ded2dd873907e07b01f14fea1e0efe6d7a1a5ecb95f822be8f3a2f65224c3d801284de6f29a25725c3784d7bccd1253706e107fb9dedbec4620c87c615f4458c4c7078a1e69a0f5178b318fcec51e73995df8dda6ece7b7267d28daa1fbe7f36680fc001974577e4a128282b67819227e5d100baa5101c5a1422f096083b3b522a6b71f8943b536d7798e86e18129d1484cee60ac63cd849f5c9e8a58fa42c0298e3d595c3c4f145aef17f79fba8d7424e5ad7d6831321e51ac88eb1c54c6c1e2f3263c899550b65cfc52da78b7ebfabd474851b3a2b5457f4e646c15ff50efee6a8ad5c99e91853656255fd429e8982c56d65d005cf3ee1a725e224c768e8c92003a72f3060cb088f7a8cffac0d526c028f3dbbe84600d5a9568f03b2304ef37d5ed28941169f8e204a1240e6d910dcdb901932982a6d45a7a10b1630587d31551b6e4424fd929b5a7fee3c4a20929102f5791062acb3c53a6edc93ab5ccc703b8cdaa39857ab06b7f818a59d8324dd1ab342aa1c3b0a32dffa0512b92c1ab9a4f66e57e9bd27734ce2b2788058637cbf94b03b7a1b640f03735f36bb36052bb461c22fff6c0580b6eb4bc572fabc9a141c1964d664168116d9836f7c7581cc9537bba32d1e3e5519e29858f889e282c805084fe3a64db0234bb3e1dbf57956ce4165795648f4865c1232e24a6769e24c0b271aef1146425a9032884393d275fb68e3b3c91599ee82a4cc34338715a8590f436e4185246df9bc4c066ed975f502b967a5761c1b8f5aeee302f96aae3dfdb6f4519aba3e04cfe5c9b2d342048a4c2721484e9b311c9a18ee5f726a512c93a8d37cdaf6ee96928fba315a4680dccdfced6a13f46e06aa162a7ae445bae5b1134f1656a2d700dcb2b5138c780b428d346feb98be8ed911de7aa5ebd72e2a6a8592a81ad4fd6a6da64edd2f5490cead76fc652998181018457f1cc0ec4f4588cb8f418f1b6d801635847914c3f317369027b4c4608e65457f949e08110b23dbb6941632afc1d1292c55c169965f0153ec72d93498f5a68140ce2c8282a59b1011ac705fd5f0a8ed1ecdadd58d4a1fbd4b09e94802a0c67f2f5faf905bc4a35471f886a8f2366c25b710eb43aee8fea692d12b4f94513337b0ea9fce3c255188ab7b432ae37383470eb94abc2554c6f165bb356415a1f8d8790e1bf76f4411c8f32fc550e38a0ea7b8d37537855724c08eff4730484e55accb2f975637b74f29937c19fdedb5aab7d5a3bc9ee1df2c83ae8d0e59782fe18b3a17c82cf649a4299b74f022012e189f19d88b06387314b65add0720aefd0018a09bb3d13cd63f98fb73b8a57564137e89811d59f1c74a047e264ce816b01e942038574a9d1f4fa5408ad1661c31bef7e97742aec79b74df757065e8e1b059b5134e53cc8560bd87e9a68003b124b15afb6534cc6181b6b71eda535ae7a3c107abfd2d8e5886cf8a7d67a4b723ba794c0c5a9d1a63f67a6c42de3e3632b8a9e7bc7eb9a5e404930265a7d04c1e16ac17a7b5e1535e1bc80ddd1800a7ba1b0d73ba053688137e1db64eebfa9b5dd8573a51db93aeb0c6c644c97ba9dc87efb2a5d79b3e3ff396a45ac1f0aab064dd05c1e6ae48b2686d662b8bff1e87db3745c7b3126a091e688091d84d3caa1adb471df496e79e42b276088a600a6f8d2aaf3d31b22f7e7efd2b894fdef314f2258d32371fa022e272760c704997b2a605b0e1a8d0602ad3a134357b0f2785d79c557cb04121fb054354608655afa7a763c8276170c13f9e76dfa711e26ceaa999fc14c686e2ebd61d18e74ed08fa1b872e09246856d9e0477e5e21a72c7869b57785248aef0d516f670978ba4dbac563b77f365cd46cecbce0b7fc7c9fe7373d6ad47d094b3669849dc21084124999ed55f13106d4be1e52433d86ffafbad0e4f221c305aca71063037b7a26ca73ca37129aec69e665cd2e70a94dc5aa8d22e1a425853645a3eb05f8998c6d766806087f14f08fc95ae3b2b9190721bf536ac20cf49222f5a0dd03307995adadefa43a205fe9dc839b5f27447611a93012d3abccf3f5d7a766756111dbdadf6c5920782545c853ae1a550a08b14a87bf296ef0aba7669fabc13a8d0d85d67e36abb24a77bf87bdebbcec1e28c1f82fcb95e82ee936f0c1a60a38ca3ab846eb39cf27acd9a219abc2c6244878ee25efc38a6552773b7444e466c24a15458df3cac856201a12c3bba6483d886482d58112effb0cd72c7aba4df0c11474a41e1fac0419495166d5b88b7e5e169c96c9ea6ac96dc5c2f749c858ad524e7f3d32177aacbc836abbea91ff9dac9d313a8004a186ab52083662a03d42518199bb2b81f9b03501ed8d1e8a8069e6a4fcad2657d4e69c0cd8e4ee56389d026717c72c99f13b2d21780c122bdff75c0469f32a1c519afc5900855539b1c75a3019342b7d5fd8ad7fb02af96fc94ec29583a48b964c65586a6f17af9f268a6cb9bbff237ddf393dc40d03b69ce5925a5fa8af87a6d0f497ae82d6468726714f7b53bfcbb647253c9db17a7bd5e760531ed90d7cf044ec0bdcf9724b640a201f5a08e223ff20e818e16e88fd92300b07e89ca333bbc05e8fd01d847bf9d7ce85da9478833f5566662888c8238b70cc3481ce0b8fb5c5e144d05ca8b8952c4374b261e48352bda2bd2e8de39b6318a0cbcfe3c36e6dd924e52d82928e964930ea6526aae08ca596fb732dfa02f2f6da72a05a227648e1fbf49554117aed210263cc6f5ebdfe2ba852d1c4c4af8f71a8a6501927109026e544432504a5bd066d7c03d443a191629a2c67b00f634023bb07c676294159db4df69555ffbd6c4b5a6d4726a54f9a0ab243cac6ff603e2ffa3c4acc6046a849b099654d0d894ae6536deecfd326aee5164eb1a59838da8cb33724697c17d6735687c860a13c8b8fbe497b99c98b58c8a0f0c67e1239b5a0880c1d4b0e2cbfe268141d035c02047d0a5c64c4fc79f245e50c43f3f64130be4b8def3085330461a12b1cd047afce58b05d2d75ac4980376a2739821149c95e17dee53f6da1afab57c02c7cfa3652784caf90f6f66a93966c636a29df19b2ed5699ffa1aa0cf5de784f5b57c15ccd22f5963924fc55f997b8a508f10d8520c5498f3408daa04028ec66b3885c5495e10666f8125f4761cc09071717244928ebcb985cc8ec8ac777fd411b8a2aa51320c60f6c71bdcbae9f6e37eea62c1f595ed27bb83b25842d2e26988d48217862afade93f152155166ca55c13c143d6c176208157fc8a836ca68ad5094de00d82665b2675baa86a6012fc36593e1c9aeec4da750c5c747643072dea8fd786738f5e788e36767bbd29a87ad1731adc579396eae378f8c4fdfaccdba49304649d108b19dac8caed2d08f116cd33af7bd22091330ff4e99936dec531ca9d735430cb4a0cbc4652a9c1c43168b1ee012a46b1cb92d3035714eb4f7f4d6b63b60589b946e5a47e961f3c575d13e1486d9a388dff8c8e9aa4663e5ed91cdd8d3d59f02deb394ba37ee4a05df162208286c19bf0204f4d609b229087351981b6e62fc580ab06ff34474db029a16466d9630eb263de0b76e8b53239a044f15f90c4836aee8b2203d6db413b583d62c8bbe7d657b2c1185a5720457a79f621bad76674112e28c34ac65abbf65e73f54f918d0b912c429b29c5c32a370ec1810cbb07375a85df5167b32a321844cc54c34ab54b87fa6378924e54a874ab871c928d49e704dcaa40b88d7a7c5774163522a6620abf5d73643338be36e5b2e30659d0e39695fa97a6ff8cb8064e370eee36c5a3b57de7d218fa325646cfa4fa2e9a0622bcf139eca8acc28de6f0a5d2e37dd2b0d6f6b39989eda0de372b20e2cbbde73857ae39b7f0cbb2f4337e04a52f1549bc4daf89e484b06177bc9cd6b199906b62789431e4a29251cbb4539c62ea6fdca9c84721c02b8af585f64e8420a7ec91e6387a897196685ebb760d1b4276cfa36b51f4d3e840e2c5e074c69ec7f6557afad4ef6774dde534f88cd7683a6855bbbf8d43d520cbe0312c9e189f710c75ad64926a97ca0e3b2b575e3aecf7b9145c160c415f8c90160aa5208744addd8b52580645fed9c66a2f6d8b0afe577ff63e3fda7e9a25519f0d2fbc3bffa9f45c40f70452a78b903d923e4f0fa9475659910f75455d144295e4091f8a760e1e68460227d37fa6220b4f0322d61b8fd7a40275c4d9446255862682f775176c67d294ff45205726eb733e5d21302f4df66fec98102611e3bf8084035b42448e86ff9225935ebf7db9a847e8a0f72ed177fa3812f4f5c0dfb7e452acf0e1a23d781607de22bdf31177d5eb5e2840bad442feb2f8baeff6f17bd63ed9495b0351949ccbb6337d907831e22ed31cedaff7cdd13bc3de40421ac6afb536ff89bf041a3026ce04316b6a082c06e0437440313ffd36ff78d6e31a4f5652c52e53f06fbeac2a7f13c64c061dca9ce9dc2e7598ed90a12307e5125397629887f0a3d3bf8d24b675db85ecfbcdf8b3fceb50e96b0a863d30a7791db30ce4cafe8d85999ea1282ba61f667497a8c52a2fa3bfceea070b2e8a9cd8e51a244b73a0a60a1e4076829c1a4668717495adbecde4f4fc0323325d71aae30000000000000000000000000000000000000000000003090f161c222e35""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -f5e15972ad2246b58dc056182273172d39b05662b5048af41a6516a04e042cf25c9c233ecaf6416295430b3e77e8bc81d1939c0c6a6304ff1b750bd145a18a2a85e53116f2d3ae39e39afb5e342b59e66196b1155c886ed149278db268c22e7202ebd8ff6da2768ac4d5fb15b1f3307ec53dad5e6ad6db55255e7460677ed6cd8ac2446414600185000ab66d1292600b8120ca1611c2486c628828099929c2a6640411651c164684364adb887021348c094182da0664c0386263020e40926404b8410336228a046292421111956800032dd0321014832001122cc2042113100d6048650b108ca24428020865e3022924c28514c34580a864c4308290c86181982912014c92308d04901001852c44402a59b4414b022c49822100329199b00dc204915a082da42245e11632c84044ccb82488469022b66098288ea2a088da4432c3124ea01469233546134708c8a66dc02825120084cc868901a5311bb8500b0046820088218804a236481aa9411a0351d1340900c62861384109b081d1208a9a282160448818996859c60d011829429485e4a6900b9129210368081545240522d44444a002121294048a3840932852019590410870cc068ce4380923828512090d44b20082b8651ac42c22922dc2c03119a7259048208a0286e4c24c1c170224c58c02174a5a380811268a19298a08232a01010502b361d39270e2b409e40830a11629099821c222059c3661a3b050d3844dc92431c03029d4400d2443468ba4645c36054cc828a1b4201c4706102648a4466d00a86848b26464884914454d23b1644a3440a446525432521000911b4580a0b4219210311b802491120d1a16110c432e92122a1b037012111120096d1a252189c40d8a2849e1168d804602241170cc842462b08d890068d29004022884013421dc8401a2328d58260e49140244b081140946e2383089446c1a2946e398459b224c9238000915401b956523098ea2081208937021264903210621c79198026c1a4869c3424219908dc83452923650221571c4125101866cc3829058a6480c442a1305066338919c422dcab431a030298108110b425120c42010b28c21388e9990491412105986495046441cb405c1b8501897840ab9240b3260e2c6059c30628c48211ac78800182c89408881484de0260d1044108b920820166c12381019b78460286ddc328e4c04099a8450c396659814814288214a4405948484a0c8045a08040c3529c8488e8aa66d183890d9b46101394941a64549986c9ab20484c4110431914b002508330683487090c251224006d0c84121090544348622b345e1960589009010344eda02515948468c0462882491a28830010606c0b4008c24292436508c14662046085822244c90610c066dd8b20054906d8300919118259a04001a014809c42d0c088658b28ce0984ca3060d8b162563002e20340613b93183c624442884c1140512354e58028e8a8849dc4266a3b0210b3690048988da383153b6105b124e99182c8924918bc80ca1c48d194751c9c42da3a4911439241b19819a28868b320e48c26483c42143c6690907215c30660c086cd2b88c19c9004286054cb28d9a00295ba2401b3409c028129b285003a96c20146aa2044a60486922170ee1b6308b186cca085114b524643800c210055ab48112378c12420423c98dd0a82c90309124164e2496840b1924009300181160e4466219a620d3c04de1c04510301193202e60086c2189851131309ac84c9bb230244001024384ca245003c44158a06021b761882091999805d4926954a201c0a4288ab42d81a80853086ac8002614c12cd30825849024d3c40023002e08276d1c270d8ab86861a62118a648e230248c862024a584598804d2c849a4048922394c13000c11a310c9b08014016284448911b841a3c24d62a0890b861123146524006199200e520830940890c0c001c436600ba791d98601cb268292c221c8c668e01864491088520865e0062c18882ca2006a64c28919196c90220514178dc8000a11a6851aa8841213440b176959c02590804899260448b670c0a06943089212170554c02522000d1b360d01068e23376c1905648bb481c42202c824080a002e11064c2335725b1222132969cc2030100725c010821c17500027880ab70443a68123a82d0b8149584621d2c8215086280a896c233282440648f7997f3a4a02dd96ea05f99886e7035f7b872fd07fa322f21a3dc47f787d9914bee7c696dc22a45366e839af8eb0bb2bf61719b225d0d53ec79c27dbdb681f325d0a4c58d4e86f7dc0767a4d3f20e19025679b924d3953b1213ce7b1a08fcbf127dfe860cbecb06b90ff62d704fcfbbc0b7478a4e63e14ead7ee05634c7278f7d659a8706b0f16c40bf909b18f01bec20e95437aeb585899c0bb0af3328015af0aef1f14029b01f3a7d9cf188022296ac5501a61a6145b1ae36eac142b5c75fa314fec0a1d482690fe98c0895a042e2d893f42fd446cab8fea7b6f2eeae767abcf521aeae0620a7d5c6d8693371ff320af03cde468166b0b592d9cc188efa31b42b0e7eaff7356436ab7382e0a12a57aecbe989fc249f6c0dbdc11441e63b1dcd707eee1948df10d6a2521f8abd525ea05987867e9ecf3a1cce6b978ef0fd869c8d0c0539b58f3355f0dcd6ec6016d276e38455c67638572c6738d90e2877a6bac552cbbc596e474d403d8ab8ab69f40b7c694179a5e7db3664d4107de70c5ed848012af5edaf718380da6bb3eeac6250bb50d1b994bb96524e580cc3413c9e7bad19065c0575906ba4ee7b582be8048c5126ff2c45f1be6eabaeeee090c1fb716e16477cd029bba2ab1085fa4afab3481ad0aefbb216086c6c4d82986ab1f5d4695fd2f9f2488f741346a7fef2574568d0632a7d1b8ba706c849e524c0cbb397e18f2085c5ae5cbe2a829b3755127e35c2db720194824dc40e75144d764d7a2ff253a6f1b109a455e319c5ab28578121d641f41af2beb6bb71514a84efabcd56c19319e1bd3468531e8a4ce78c4f1b89164ba170123ff8efc61f01a92dd9a19027e11e2141ba7b4211e47ea5206608fa8fd9abefe0995a6857dd0bd3ed0cbe96cafacd110cf3233b67e8daba02a1f28c14529676f9902a87bcd0b05fd183ef4ed1cce31527cf25a30ec2098af07d8658e789c2b94aa9169708ed686401b73d828bfbdc8e943c259585da6ee392853c1f7fdb65ce2b5871f67b38aa35cbf851d4c721ba59b3a49e251e533f92c40128ffcc3403feb3d66b342e3fb58ad621e86ae4ea694e33c24e132ca123be19bf33f933edee5ed9a5ed6eaec769815eeffddf1892f9e76ea0893efbc9377366eabf1e32a628e26a0362451e4db704d1445f4aef183c43ae37d9e96af9702e5287275d2fc2c563f6a03528be62cda89cacf9458eb4b336ee78c814e52222b503dee582fee523473b97fc08a41b4f4068db2ed9ff94527c38b3e4369b702983539aabea9c88aff8f7c4a424f45634ab5258e3959681bdf1a038777b7525e53748abe024d824db279ebf2534adca871fe186b3bca61769c065486cd8c289c9b88cf6500fe7d691e1aaed1579ddea5f149ee1b4f5be1ec98b2978a82b8dde4a79b799fe6c98c7f0a7ab2aaa4d103e484014d6b989f560dd2ea6d9e6df9b1b267ffa1ed895ae6bdd5b13f9f0a4ec1a5d65180119abb4a841ac1d73841d481c37ce1b40b9ddb5bf36f0fceb9f33e98ba0cd4b57fe9c36cbb07a104c2e0b3481831ac2da6824edb76277e9c06e48347184208e4137498864dfaef57b45232afe4170fe85e7dab426b8f918d34ae28043f81a914062cc5e35d761c701ad6891ed3d008a800f1c63600690f14ecca044373648a0c1e7f15bb7655c88abeca60883f275a23e50de845f594ae839dec8cf9676f3abf2e2223aadcb68815d4519343f73e551ee7fffb015196728977bc8c6addd870e96bf439b37ed849f42ae9ca1d850b601c74382604d484c742874dc35ab740df13473b5bd55e61adaa012c5dac04696df0fa2ca3df9943ecfb6a76bd8ed39f185f45503b3dbaf7d4582fcb7a3825f3125e1c804488474cff917eaf61143750da50136311663a4fd4e8a9addc415ffd694c4cd7d4998c057aba4adf6c07ec5b1f6d622ff3f8f8d77deb65bd6c088a47caca00d551c38a55b6b2ecc773be718719a6355560d00686a77c68cda8efeea442026d99badbaafb6a861f222d6f9d7edd75267f5cfc87731801ca22a863afd7f4b394d90af2008fd2e799659a0843584bc6329b6a84f7ebdb3c374cde50f6bb5f9884b39830c4409c967654f5a64a6b8d7e0e316c7936fb84a3651eb5bce7ba80f3ae6093273dbd3ba337484720712caf9b3cbf191c8a49968c1e5e2499c4ade3cb350fa6049c491d52c2ed697d2d70d62aeecce9ad561547090b7e4ea7ffa0f21bed61468686f75303721109b440cc8cac0814c293bd9b219cd86843e6d3ed498203e7ca8f4ff82c9cccd229a2210c7f32e7b0a6b0646b8e4e9617707183f0f5edb0124bd0201588baf7e8b23fc7bf2d7aae16f54b37c963b3660a2c3257bc889ff9d00de92e1c2da98e25ca31549cf854d58af17fe346f0ea6ac4bbefb393f5908f1b64254e6176cb28fb9dfa70b7a0462cdb263a2a46858d1f37dba969e0226ab9af0b22a141e52bf8c0ce9f7234194a462deb924ff4771a5beeeb6d5686121a5fc01ac1ab9fcf701d7401373fdc2af3d8810a6783d3fc175f23f85a113bef7027057a967fc94a5c93b60f15b1d87d1be3d74d1d377b1604536720af47f6a7c2ea931a9fc6a0d9de8c2cd4c9b71c7e653a67b7aed5a8c2d0ce3c4e3c51ffe12357ca08438934952de8de66ea836a90b644e6a4241da70a15c08ca9f74bf3fc6d7f5eaa7cc2e8abcce78c8a19aa597980603ddff36eebed77f658bbf3d5e7498b16668bc8956066f3f5c64df78c6b9301834c91943be35c6e4f860e7662d1f6d9b36fa30a4b23322e6f7b328bd86e92da8937837fde1766adbdf647d7a2718f5447536280bac48bb1b53d884327b7077e17c4de67e6ecff8e89f18afb82f5e2b2e2dc7d78f8273affa55efc33e73935ca0016933259fd09e07d183ff884298df3aabf7e7907b08e457403cb99e99ba95eb854234f5593003cfe661daeba368aa456f9408b46f7ff92fbef9886bb93fecd778d09c4f43ffa5fe88f32dc4a404fec7a6d4b368403c38efff8d1758049a778af5023e626a01046f36e5c569ecd3859781caf50558cc8649301d0fdf323042834d7ccaf212ee8a4955fa9e4cf65ebb2029a0835e5db69993956956545de4cd1715980ff554a160e1f3e48c323e35b64274ef64bc7106c15e2f9d41ab4a92692a9f6edec8e66a73c2d4a6ff1a881e63163764fd3cbcb3f5601a84d4c26bec4fb978a3e2473d50bd561c08d16af2542a49851c8f63e0653bbd6b489799736fa39d8707f477218d918fb283218619bdd569e52b63fccc6e3c859a7febc7196326a69143af3da337cf0653a5d6370a5323f6c31f8791b1d5e55032261c5df8e07b8df185a31a9b398abc345b87ed8198555a0841e0927035f5f3cf5da4fb2c0ca18b1bbbe3a9c3b3df9d1d448e242513f5d0dd481d3d586ef61d5b857bbf2d1f771a2aed0ef2bced9a6d0bd576c1c8bd2e3ea9ca6a6b6f9e8296117012d48af013b1a607dd70fb2edbf409a0a9d5fc0a438464c773e045b8d124a0c2ab99b26f81afb2dd5d11ef44aac1eb1242de61af723667d1d25a349b4d842544fcb4e3bcb45e0e9563039bed3c0f25f6e3584c80a5c19e4f5c83929549ffc9f9c2be16c4bd36394ff69634a1550eb60c53d7b17e08f21121e10e2d792cafe97cfacc8ac6728d3d0950d3c33c5ddeec089e979598c6839cf981e48b5dd11003e91564f8bf52d2d20dd61001d3fbd329c22a89b6cf70816c268afcfc3576a29285c9123fbce1f0f6bed472a23d9b09f7eaa7be73451392f9130c7264ce87b942e679af7c91954cfe529869555a4cba8485f9ff3a9419649477ba45c1e7e852c3dcdb637cbec5261c94df5ccc30e904bda8413c4570bb978abc02aa0e909bf74bba0549ca34377ccbe36f1e132c074244926f0008671c9ca6a04aaa8f8466eab60543f5a0a39826aa231c97ee6704d685caf2873d918ee42ca7454dfc30746b8078829e8c89c831dde2ef7a6b2e5d6038ceaf4e24bab7b4a54792b58cd14548979e0fbc10114fbe23804eb997b765bff34b162a354a4d9702f4acdbf46d11b679e0f423b5c6e942bf5567cacd39053ab5512bd6e745c9073911f5735be1e5289cb7239ae1c784074e76d9364ae0f6482c1a31692156cdf4cbf4c140745cbbcb3b213ab1d8eee1370e9174e62bba205659507b195bda05b229d00be377c6697fc35cbbb14f9ddc32ecc66357321c915041dffe20be5a6d71d5236fff001ecc4b69fe08bb4533498e00695f6dffd34564e5c69a63ce0a0492b40a7aa45d0a6c90d6fb86f8ac006a1df480eae6adf7c78ae447ba7a771114345972d2cda9a0af25ffc15ddcc243fc2e90fdcaad91a216bcdd35a5f7d735ac4048a72dd510c6824df4098d9ffd7d71229ade24c5dfdaeb09070c99bb6b84cc91d1bb754e963e5a0d88a04282620102a5266a5f0ffb43a0e41e4370d66474ca6bb95144336a4c54bfdac1e59a678706f6bdddaee602c9bd3c0081c13dbe1644a755928f206a9e28006b3db33b6f265815e666ff3403d118d41c099c5be988332141bb73d2ed7ec71b3c2c4b2541b9ec06c3cd563c5e7ee8e6ed289be91969ad646b1260b4490aead12ba8f206e438f9260914f9c79549157455cda2dfbba3b4c1aa48de004bf002f366afa46573acce2c54d863c865415e887b18f31fabe9cb109c222f97097891f4198776cc8d710526956"""), - TestUtils.hexDecode(""" -CA0104B9DF99E87474389167359968A307F63AA32F0C804A96B18FFBE00C748B1D6894CBE2B7BA06EF17B6947ECE31DDC9F614348F01995FCCE77099A0D88B2BCD1035667631991C2BCAA4C86B4D31074A2FD46C38429B52CF0BFD7CD3E5D194DF22E2B0D57C0C9D624C772B54686AC963447E716C6B4DAFC00AE383CFFC69A2F6F931D616954BC9A140D785F15C5DB28ECC793D88C78D11F8F8452046ADDD3AD26988B21BF895DC810739FA7C45A8062B2931AD363B0C7EAB4CCFAC71CDD0DA3B54CA9A6388DCBF79AF799446395DC7A5B7ED1788188E9D03EB3BF7B80F8CFB9B7F33DA0D4DBE1840B9C6C5D80F6AE64487BBFEC86C596E2ED8E721A11D783F7552A4B01FA24F60B5B683E287BD75EA0DDC15314E014D402F527C5DAD74CFC49B4D824EFA77C359B90AFF15AC89C1AA35959570E2148DF7A09E27E2FC096AB5CB306B4868AB80A24DF745DCF9EDDE57357866182A9AF50796EAF97A1A1051FFE6F9038BE1F6239CADBF0BD81B23E2991941F34D0851AFCEBC4D3F8B472D6259CF61FFDB87F79928C66E69D969B254D57541A87C692160E5D58A837A1FE90A1799758A70F958DBC1BE5D6E6836845940C75E745245FBCE59D1F83462B9578534D7A05DC3F21C34EA93ED78387B32DE09ED3CD2A51EE2B8F7387C8C2D426EAF3795E99B158D467D9A039234FDF207D65D2577D1688E1B1E72B5EB096FB6377DC8EB6B3F51900380BEA561C03D546EE242EB4264C0369AA2D53B2B190E0422FBC4CF896CD549C2A08A37070331F15A9ECFFA0E91B1FC4D5157418914308EB8C6A992B197F33DDD517DF4610E88F2E35E505BA7C7CACB8E76677CA9B39A4094EB4590F6154FAAFA76C1D95D4072B5CE01F42355C47AFE569FA80142EDB49E2ADB34D3C356F4D882A52021C5216B3678AA6A5D52C51CC8BF09E7EAEDD2501A9886FAC977EA5F385F46E8718D39073D8995D392074C2525A4ABBE228F531E6B16AD5BCD5EF5CC4C3C71AA77EAC1747E2B763D0B3D66C7F35458BE43369BAA0ABED23202B733B3C7A111F9CF407A7D62EFF5BE3A5DDC3E49AF130012BC6D5D3641EBF268236473EAB09BE87BAF7707546B7AB194D2ECF5B03A56662B1D6462898DA94747CEE9DDA08A9026538D799F163E1E771EF7EADF8833C0510104FE7AD7EE75F44F8D4572E299A87FB17429718C576B29983B50FF81F8D48D41CC764809429A7CFE05F68168B6B36FF66CD75DC0021D774D07BC716A74F9450EAD2995089FEB89D1EA73A9CEB83155ADBA737B3DE33B6B617EE7F5CB6C6672AFC439990B612A6AE71540FC6D7FF535FC88DED0E6A80A484735F63209D39F12E6E129C4ED2EDD8C8B5A24472B83A058B0F1C86B7F4C53D88927C7E9EDB5C40C5D6C7F0ED8A626C5F35E1D3981936F0F1FE4E8CEE0FC7F66F0016B14F3D1EAA993A5DB9B92C03D99C0A867FEB343D9F43BBBBBD85F58B2380811CF153FE66E5B5DD07D5A87ABCADBBD472692358777BF17AAFB622D487A100062465D9BFBE0E63B9D862A02F09E371EE820D969B29B4E6F6A1120CDA9F9E3FB804B26E2E9C3DE219044D1D6E62A28CBC90C262B76914B8929465FD901777F6F5C112D196A002A0F4C4FFAFD2578B5CAEA21452968400DAD6490E313D32A708A42F64E9CF412EC0E358F6B833EB0190C5933037202C266ABAD212B570E609FB7D338AD3F850EFDEE9347EBCFEBBBCE90E7F27372E244C3F035D4ABF1008055215E573F0C4001FFCDA5E6B6C5B29B7F59132CD86481FD0E1245EE4084DCA3D44A0C9E6B6B14E1BCBF56F470F15609DE76588795D5CB62BFC9C253EEFCC155C116D70CCF9112D8E0A801A3C640C7D16634EA02DA9DB9AC57DC2F7D43F48ABE631D3438C2BD3EC97832244E81223EEE47054878BB2472F64E9ACA0D5A8B0B04F783C5052E0ED6AFADA5274C94084621E989084EF9814128226346996CEB6FA07FB957C7432878505442FAFC4D945A953336F9C92B8ABE4E4A092DA65E2BF1A7A274E1EE9D7958E35334D9B7CF8B314F0AA5C45E93111460A8F5409C0BCB842DF9C9887FE4643BF8958CDB40EB66438BA53972E359EB712BF4C553D871ED702F74C41D1217D7887C891E49043C0826FCCEB2897BFAF9F217DC9F566DE1C416DE9118491162113E2EB56CDD4C024DCA4A33359D88CB0247BDD6802455063DE9666A4C52075359316B3B557D42B7C99700F55CABCB2B802AE4209C6B937C798433AF94159A4EC0A7DE00C809F6E6675A4213A1CE8A7099FB7FE6A0C7FB383233444B64AA120BABA1C4E61C6426001184E897A3C6B0BDCF9759A72146EF848EFA65EF09076A4FF2E6DA518C5A08F2A2A12D904C893297234E53CFFA04F285F350412456C9A13E153421D65DD30B236653AC13CCE3D5CF1EBCB8AB46808414BD3725987D6E464EB4F97321595153DBF9994F7E19AFBD19E9BE929D18563789567B28B1AF05BDB5D2C5C289FCBE8EB159D0017E09DA8FE5E9D49D3A231814778370DFE703ADABFB175859A895A6ED86F9B6B52CCDBBF936622C5E5A01D50E2B6D5730EA4588680EFCCF390211F211472F9E10314482CFB45A24706BBCA8CB515B6A9AA6EE1D2509E8F9AE9D6F545BD3971A02CC26699608FE1F076A925008AB6CA8576CC5A962326A369BDA8ACED3618F02BBC55337FAB2D66050514F904083D4386B43B6EAD553DF5603201C6D684F7156FBD2D3DDE3D7EB0D569AFD42886E57B747F21D44B88AD58FA2370FE6BF2DFA4D94D8FF983A1C2B89876E75AAE3828D1306DB9A639D052EFA6A0EFA0F61737CCC45E0C516815E92E256BA49E7853F9E9D4670593BF9402E59EE80F6CDFF8244D156FAEA8220D483601794A3CB5E1D7B60DCF991A545D2C72F62E5EA05BEAA77FA86A80400A07B97D8159F0EC170913ED885B578767CCA7A5BFB8BFDB7AC99002555145D9DF5011654700D6FBF2EC2BA609C969EBECFCC0EE346FA01B6CF07E6855F3C832BF1DB6E247448438BAEC055FD41CDBE921E5F62D93F4E7964258A9CB3991E8084BFFC2E5B29BD1E32A64E32BF5E27416CBA7FA3DFC143281F3797E1927AE9D9E07FB424833A7911C23F231D676EB0FB061C179C72FF0038E48068D43A805D56C3B6A16F5A2E5E8457F1A3E0F927A8880CD261F0D0AD8F82EF0E52E1BED003661F1D4510F7BCCE680CE84A0181F046366126A53EE67C7309C6982C28966B6CA1F324D03F5E09AEB111486C44B6551B1C36E84C2A72F78AEF5CA31AA66EDFB0792C00579C0C7C1FAE501735706CCFADE03E9A0847E498A24AC1DCBC7DB8FFC946B8D914633559B63E3031C214414BCC1921D2A53726695340648CF6C2BB4FDF132C77BC39E9CEB2E4D22EB138D807D7B79F78CD9713F5BE7512FD32E73E886DE16A9B1B19026B91EE6AB92DE4DE663D9774344B283149AF4890BFA57ABD1C9DFF128F9F169E4CECEBA0FEE1C33D4E34B877EF04DC887F7109B2BA65EF5732ED4B7C6B33131EB5867811D4A8A3536102F5AEFCACAA681A6A45A3BDCB24C4FDBF49A134244044E2B424996CF6F3C514C77EDF2AEC177B8F80A1AB77F6D3D920E508C76EB71ADFE2209A132839E9BB16BD9991A545AA0587B7594E0422647DC84CD355B20983AD582324D4F19E33E9CFA5CEDC739B26F43BBAD1F165720306F48CB15B23B961E5990C2DCC39E5BF58A9BFC10829590A7AA8F60E13EE1DBA85EF5EB9B1F6DDA891ADF7357E16CEEA4ACDC00E20F8F364AE3EA838CB4A0FDCCF8B439A242F8D18B8E0B9FB8E074922E0C25922CBEC46C98A82E93F0E95884BA9853CC738AFADA3F08BFB66C17DE7977EB7CE5495B8620B537B49D1D37EA4B3477B79759EC7D9AF17EFDB2EF89945D453BCBDB349CFC623FBDB8F125EC492CCBAF30006523B543B6A17245CDC5EE7E28EA895654A5EA74781CCB0F30343C73B4BB88CE07BD37DE9220712F11748EFACCE925626FFDD8447D37BD9CF2476437C093BA4CC0AB674E4CF9543CEA67BC25B9BD56946C0D077F0849796EFB74C7F66D5B86CD9A38B8138D816F677CE08DE6A6A911BA4DD1834751548578CEE4CFAC50C11D685E52DECB77A475FF5468C38DB23853BB2118C78AC3D52079042FB7F370B3D0406E402EFA6432D3055C572C81DD999876E8306021118BA87D5D430E4AB9C24670EAA1274ABF4BFB8149D9067C427DCC026A61C5B724CAE1858ADE366FB42CEE52C36F0F99AC02E8BDF784EBF311334B83B2B277982519DFFA3AC35D97F9F30635CC17BF8E017EC4E209EAD104B52C58E8762052CA62BA7A82FD011860E4F298D889A11F6A2BB1B4157CDA42AF9CCD0B5324329A92CB9FD6EB81DB3FC58431BC5C9A6DC1B07F7D2B00B32E5A39960C5E2CD69CA2914F23365B518ED746B27733D713E8ABEAF9D1FFC6D3D9B601FB386A6911F24CC818C0353658CB826F43FEEA792055720065601F1364BB6184699F16E3EE2B359CF0642C85E9115B18E55482356E2F91121C5884578F3D2C45462E47A3D477B3D63448A8C1679E68F9B7AE509100B7B2B142FB6BA20179E599259414520B02B745E592FD10D0D40D780A95C164D651E96A7052B69BBDA979216989A57506638F891336E2EA123303F997194B7AAB4F22CB192AB59A8BDA7CC88D0F43E4DD949146006CA3F91CF28535ED42662A61F630AD6E7319A7B98FF5C7200FECA768F14BFD43BD60DBEC814E22C26F1A8191ACC869A6BCE61991E4F36148908A5B1557A507C407D73A6FE75A548CBB8CACF13E57BA6B01FF0DF900051AE7C0C346D5DADE5F1C1BBFF967236BA5BAEF19A70FEB320BD76035F3A6B11383F13E6DCB8D1533A6529C98334A3F2A9105A5CF1C940659459C405C197130EBA44F0A2881B4614B7A0BBDAD5930DE5C3389A7349265629E29C0123CC89F3F540FE5C9019662A4383A38248F22201967D908EB48D530D17D50A08B35FCAB73AE8ADFDD72A8A7551EC28C7573E2B33EA4F61EE84C3DCA33DD5861B8FB7176C4AFBC174250D51F86B1452903191E39EF099C0CBCC15B3FB5DD30A2822F68AA37D59583BDC1CCDAB1B2E0337BF397647FEA9111A5B94C6A3369E90F3B86C266F4C11C9A7D9E24802B31B5F93B8EA9AEDC6C2944965D6B54601311D251E81C77AC1BB2159263D0A92F377F111DBC8D554C3AF747FE7E82A6E6BF0E4E3743B7AA42C3B5B8D3E5D9C3B427B3290452136E61592609826F4B61D4960B7C3784D0E2508363212AEEAE624489B739D0573CE23B35D30826182DB5F4D09772582E4D6B61938041344EA434614C21B01530327C08539A84F03275D0C4A77FDF230FBE6639CC7A12C34545C5CAD34AABF8E25D64AFCA8206948737DBA643867A146F17ABF81A926294E2368A5A2F0C381E2C244B21843E3ABBA680CC3F1F0509DFAFF4C70B68C82D3D7EF8EE053DBD154376FAAB5D561A19362314B037CFE18DD03BB817444FBF08D771A13B9D745DC066C89C10ACD53597B74916BA719F9EEEBA865252FE13EDDF97978092FDD1524CDD865FD6AE9C14329EB62B322F46905804AF1CFFC13B46B6AF4ABCB107D44DD27B460101F7A38DC786239E34CA9D1A444898673BB3DD92EE88478A3C539A563CEAF5CF499AE8E07BDAC0CD5419DEFE2977105B5E0138D84A8F9BFAD82F58884377B803C8B68164A3E678648C18127A832FA994EBEDCDE4FECE85DAFF8CD6F44F4CE57694522DC30BFC492BF62796D05A9B87BF13A7D538EE5C55E6898D50ED127E8C12F87D160AEEBD3CB126BC4144A51F685079E962DB6FDDE3BA6D0C8038BD6FD8377C4BEFC2EBF1A876833516D206C2E309C61E4CEAB5F86ED83FF20C8723BFE63D8E480798292E6EC6D418D3CEB623AC6983A3F8A3AD568F73E408F15AB88C8F56F3CCF5B32C76BDCEB1FA41357C42E1215CC503A316EA0A83FB341ED6ED20B1154E5001A754F92E97570F9DA7EA8AB7F2EFEE7B79A1DDA705645ABC5B1E04CE4F922BB03435D11FC83EB580CDFF7EDEB78F2CEBBB6053410E84477864C16D4CD7CD9D16B932372FDB99DBCCE2DC3B5CDCCF7DB86AEC9BDCB8E4F27B65ACA9A3FB985CF95C5BAE253797C8474D0C25F0FFBD151E6558E524C6E96267677EB7A3E128C918CD3B09F1DDE311401152C62B4C59EA1D408ACCC4A12A34664D7C0858D7E99A0327724AE9CA55A9322D865EFB4FBFD37FC79F8D7B2BF08B1824D44777153ED6604E05DB1FC9B1ACCE05F8C53C32594A84F32D97AE49E819029204AB7713AF2AF2C281448A34C69D5F3DC76345031D2CC05B6B26303198E182901FE65710EA95793DC8495F1995F0196DC9473B7AB922786BBC61A91868BB0BE05E2034EFFB288502DDFE2595887CCD144E98ECA4D1E0C044C642396F98473BFDEEE796530467F6B5EC0D5B79674EBDF5D1416F94A8EAC7F4833947F1DE610029779CD436729E55AE3D959F99D5438E0E4407D0A870A38AB31E08F16A06345B7BA730CCF55CF1FDA1E9D04833ADE5FD74A34E2629DCB75A3482312860404F7E75D94D7FD2C8215C6A21BD5FCAE81CF4467931A984AA24B927039526B95C2F5F39AB2040A23C76B64CD2D04E95DE6DD9B8EA849F9F7919A619EFAC498E7E3F4A70432E28B1C5DEDB08D122AE503E98D34D13A4E8A69FA267C3E20671077F977F71308D3EA1AAED5DC33B3F41E0ED981050B3B915EDA07AFD71CFD3AF13A2063813039BE85EF98706399299118D2427A7912A131DB7BA731D18DC2838A116E05C4CBC660895294A73D170C060CD83C9AA0884C5F3FE52F4891C2101997D688709F356A556CE202C571E1170BC339F3E2A75A5A13810E3A2F2133438C1705895523D03F00BBE4F4FA9BCE6D7A14517BD54E281F202BAB40DF35253961DC9E94DF5C2C5C3F0E420AC67A85BEC2ED70545B94202AACE5E58180104E42C5AA6F7F59915BEA69AC10F678D40506AD2B502D77EBE4D05CF8253B4795094F04BBDFCC8033EA131BE83F3F647D22D1212C16895F52FEA576EFB344A476D2A8EC74739BA62632C4B5B08076905BC0103CC9B2193EF6C4785685F2B3F79FC39B5ED09B258E5E9BD346557F24CB542B69A3ABE367123179879A02F941F9781935D44BCABCC563BB1F31C44BB77D5E7A4FC7EC2C11D597E7288C6088497DCC97910CFD8245A4F255CFBCB8FFF95905E8224B770E910A253356916EAF1B3277D831BEA5BD6681C6C7D57D363608EE78973B7BBBC156FE5536C963030B6BC8D306F3C1EE72F14163DE0DCD0CE741EF975A9DDA77EE386B991F3096FEC95FD394E26578269F491572B36AF42CEF1D86CDC82D63DF00AA397E1960378763F5CED239BD2A6D0EB7C5BD7CDA2228B684FA57B7FAF497310D510CD386DE6406924CD592ABB1E9753EC8BCC594ED52B70C04F7C53E19B0CB607DEBA79FABD6748A52692CDA34BB7CBF95D1ABBFF8AEF8F8AC7E5D52EF58FC79B0C7662DA90A0F737CBD42E64B648B624AB497162A7B27E41850A9BB4AF0489550773EBF1EC6742CE8D53A20921149563AA74337ED4CF1EE8685F41D36F748B6DED5F894BBC50A8DEC84621B6AAE690D6EE0B392A7266A480CF985295361B14AF0A5CEFC1EB737ED3AEA5E5894FDE80CAE477FE742395CACD1174CF2B345774BDDF71853BA1854EDC8F5CB03D33C5F58EC386ECBAC8E4209F8881473A4FFE306ED3194F455D4441D132B7685425435E58AF1F2964B657C71EB6E28FE3568183F7A0E570821EA49DECFBA3128002E77208749DCBD3F5E15453AB6DE9EB313D7445377B3BA74BD2F67AE31F560ABB628CA0DDB120CAC6CB62EC9CCC65051F70FC41BDCDF29F885FC9A558929F58CDE1200072F96C3D8F22032A0AB3F705884F0D827823FBDB62FFAA39EEBFECD9F57DA083D1ED541CF36465A999558F2299A865456C94D67E74F1EDC7166F91F4CBAC8F89E680BDED946A174E9260DD50C6B0A980A4B886850797149FCAF8871AB3080A76B645E333290A0DF319DE058981B8CFAD7A54FCD62345DFD9C3E6F7A26D212C97FA6F09866E23D5A19EB9CAE760E876B2AAF43BDF9004D5CFDC41570EABACACD4B57662087B6A91B6249CDAF905BC2B1AF5934F1A05D20E6C6784F0FFDA0A3E79A2C0939BF36C55EA0E31B1AE614D44CD413118EA165FA549026574D1549FF7D63B4C464A896C5C0E8D5569AB2B10D1DC56458FD1E069B5F91B1D084F7AE34F67ECDCBF33299B12C102F953CC48B0661AB4EFB493F7E4B2EA8F6FE59C3D5EF7D121B26B912B86BC0AE987B6A3543558F0B935AE62B4711A586DDAC9E5960C48B99CB80191B11F4053527905123D20C549457BA87608948933442CB06BEA0E73FE99E3C4198E9E7C51BBB7074DA46E752E46B3E419FAE2AD60D180303D710C0A59C6B980B24F0BFD39959368B5F56AB3845A2167F4683AA82A9613257BC801F5146CFCA857F2DF4FBEA85C54930D4373F70C083F661077567F1173819EBAA585EA3675F97951CF8C9997887BBEA9B99E17A1E0215DFC2B9A66760A277F68E747141AFE5CAB6B25D73D562B91BADDCC7938F2EA75F1C990E88311549F38FCE2C52933498B22E2810227D1EAFED4BEABCB153324622E107A6D96214F3C6D5DB91855005056A8D1BC5D5518867C373709D24DC1FCE21537C58999E26CDF4FE61ABE5E1225DE80F98D02253999F39A145FF3008F12880C173A7ADEE15025E3E186FF0C2090872A0A51505A09094FA2946AFA1840B0D6D526DEEEA95FD8E259E70B2E794C97F50E7833B165E7BEEAF5D3CAB7C3AA1CEF00003B94159F0F6DCBC74808E3FF237D5C3E94353FC0E700CAF48DA8BD94B991EFFF2DACC9E423A2AD63824CF879EF838C784C7D4C0CEE3DACF5884941BCC14E043082D382AFF598BBE0321DFE9406434DDF558EE2BDC272C2B04CBF8CEF92EF8180D0FEBD3D62E1F73F3B1E7FB0EDF9B50538D49C52CEE53F3000E581FCD7E6FEA1CEEC9DCB4876B3F1D1B1A301A2D395DEAC54D68181406D7ECA05A416D3D8E0EE10228483D8515A0F662D933C53F945B50C65C5B8D51EC45360661C92761A1F74EE06FAF8889244620DABA05593DDD4D6A82A30F34DCEF50B1B1D261CC357AB0673370A38DFEDEF3D591377CA29DF609682EFFA212092ABF84FCAD677DFAD758575CA35046467C6925B6185F9B734D5E194F5CA48DD10D0B84B7E9096703A9EEF0D3EFEFFC0F58C4D38D741F15AE766D06156B26E9C82B464C9F609F0A4FF699D52E0E11E054738476456CB81859ABE457F3595E9D7F1CFEE5D0437094CF093F468C79C093CD615F7409A505C610169010F46E148F3D264FEEA1DF42B3E78D1C4B33C92EE9BBD9C508E89BC4CE0BA0C412F75821EB54730FBB627C6C93694810CD741167D5288768165A68034CE2B16B0E73ABFBF75A905C9A9E577024EF2070EBE8A68076AE37BDF3507C7CB10EAE13D3A05BB3DA33F873F488150CE67AB892D61A11FAF5850B6A26862FF0CE85E4B0AB3EEBDC81F68BFDE39B0582185E4322404A0195BF5951BF7CDDAA6530DB0EFA0A2E6B2A9CF8DCD8B0D15447448847D1EB5FCCDC80EEDF166988D55DCF3BCE37E24A0A5F302F820C2782849E70BA47523A7AA1FF12F144148E9B5A1E05035A346FC4028BDA824B8D5FDECEC4036EB2C3A7DA612A703EFBE4D5E5E17CBCE1EBF546880C227EEE2D9CA4113D0ED61AFA70171700F0F9A1BC7CE7807A081EF09E9CEDA5DFFDDECADAA7CB5ACB2DBBE26550ED006C5B7DD89A2585EBED5995F8F76F3EF8F13B6AE77084727DC894C74268D4D91000155FDC94DEE049E54F4E4D2494EF926F23B73E60EE16CC3711B67B6F6B3A3BA6BA8CE602AE1BA87ACAD58650AA8F7F0F36AEA21080CA8DFC618AAF865B14BBD69FF7B413FFC81DC6C8BF2A7B122EC2C13DD7832610DB9E6EA0E5CACBE1703AF551997E6C51BCE7BAD4B3EB1F392EE12C5691F795090C6F1D6405D0E682F279B3DE64A9F45B1853346D8D337FF8037370CB4DBE5B241959FB8DD985A4F154470833E422AD9EAD7A14EC1CAF6308FCF7E9AAC13ACAFAAD98011148A2D52D40511CF13C7CF0ED1E320617B908BD1A6A442FAFB2E543703844B0D40FCBD1B392CDF5DAC9CE4C2CA69C8F04AA033F5D6D11DC1A5667FB352BE6BF88A9978AAD37B01BF8652A2C475E8516AE1A6E56F8CD596B9A780864ADC65A04F615ABB2BD4BA97301FB0CB7D9AB5423BB14C29030DCD5345C54D556ABB116051C04D79C81402B70AA9F32CD01B6C06FCFB416C4CB7709CEB12DF3E8BC541333C90E6D991B24D7D1D98D0839AA86614F3D91ABBEE5DF138A9DF2C0591204FEB3D9DD546305FD017B72FCA4DF01A7C1728606EDBA07EC101D7172971C9F4ACE7D6D09E06BF9E8552A4CB3ABF6FD84FD350F60A3E1826BBCBA484D4B5B284E2E1EF2A164FEDCD0D22AE77026C4A6596ABCCEBF6ACE68C11ED108BD3C"""), - TestUtils.hexDecode(""" -a3426182a616883300b2c714932258a288d6f9d23c8339e1639f0cb6affa7245fcd901acc5612dfafe3e4fff1171e24db746e388f629bf6ab0e2090deeeef36a3b3c610ef0570193067af930c98accbc0d6830173136316ac7d5459e4a2cdda6f26f6509c35d1232af44470fddd0142b6d584766de939dbfa3edc9c905189e0c861eb16667d53576a9d4a7df0073a5d54058500e1f54d3898faaafc08b116336669568d1d18004d33c2b71acb0686472ad04b23a667d6d3d7d0d9e3a434e34d505d63f17b26933b4427931701aa35f2f6864465b650c9a6673397ff4aeb6af2730206f1049febad306ae06f30c856ef643c8c8ae9e3cb249a10a4646f9b7d985bde15103d57630cdbbb6716f41d0b7b1064346ec31907531bd35fff03872661bba13bba7d9a03031ee4943fb2aa549a208709a528555da3a42020a5c5827b06e7c917eb07c02732f7f559c122c545fc36cd006f33bddc2ec1a2dd67a60355c971e699d400110aa001a442fae92e24d05d1d091eef447f643aaa825d974f4b049e6e0f988ece4d510e79db57ccadf9b5e1a564c64b029cd265845d41474868afd6554996e7dbb2b3e92fa5f544de6f8840e841e886f7a5b77d1afe3b29f74dbab86a3f68cf223f9cbf41715e6f1f14b91146b64475a336fdeb668b27ea28fb87321f340c910b1814ec7305e11a0dfd0eac1283c0d0131092267de75cef5b2586399804afe72f7da133d04c02f19c2289c17bf4a2ab1d01bc2830b34bc77b15edc8fddbd0359587fb9316c3ea1ac8a146fd5229f86c38920907d77eff0b1c581f6925a1bccac2d234c52d159ae44f6d93a11d133edd6d0f6683f5165abf5c7197a50827fdaf713eb3bcd562ee9055be72e879849b7e4105755d0b9052885195e100ce302d3372fa4e41e3ab9e48f61a2ca054fea7132ee7ef77b62d61e02bd8acf7bae2b56cbe5f0224d15c3ef29fa051d2f27d56b0057b846fefa044ec57171549c81d7baa27e59e134c28cf6326d49fcbef62af5937d42953bf5662b60729ffcdb8471733c44cbf34765996a58430c02dacb23c6dbd9d8550eea2dfb669e1738fde0c9fb34f0051fb99cee29bf5ffc1ee95419580dc56c9b2118ea80a7b34c1a2231074195f45dd778dcb1426aa7feadf475e065f9ecc00333d05ec3ca0e0cebb2940fd7ee81e8a18821b59341582acc43ae576cf850f8e7cb040d4c4dab557b2a80fb3891669f86a00879c45c73e6a363ebbad67f99df0c5fadecd53494b5872f902e20f3d41e4be6b7ceccd89783ae2464feaa9fec596440fefa3111bf3efe416481f5e739fff33e3b7ee1c90064acfe18528b8ad3a9f3dfea879308521416da9f6131a3279def7f9ecf8a46373352cd14a0765f4e28ea8f313a988dd751d0a15b525c3f2b19ef0d098298014230bd7c8a042afc6d6eb6886e22449a36ade8b5c8e114cd408dc54ca4554f291882272645f8c1c10eee4ee4d6206525d0656867c0d2b4a134a40ea26019897e6f2bed4b325ada4af846b1db43358d140d54bf61bc8ad585715345aa2fdfc6ff62453bad6d00ba9ea11b053e776d72e0bc28f54056c7e0feb06314b3dd0023b257eed796bfd594d2a2b0ef19ed5eedf68a6dd19558fab24c9a751021c5fd964872e4a8eacbbe9406dbdb98fd505870ce79e64ed57c83887edf6ea916b29ad0c1c34d02f115e9a81b76d70ed6bc0900ada79fb5f7dc069fd7fc2f87ef9ada6be01f3e5c2e87ce02b38bb4c5372fe69fd7cca02898618d952c6706c88bb7a8b05a3ac163baf9deb64a0c5523ea486825f00cc298da63274b4d085b7fc6324b984d86d9e39d2cfce97c2e2a3ad8c3c04399e23af07f4e4c8a49e58971f8c379c88258e7ba25f6c6e9bf8c090eaf06424ace3e91e3ae12bd552193057f2542c6bb89bf1d16b7039395a8f8f54bce4a67caf3baee88af88a4a34ffd0d3673710dad8b1a98aa7a7678675f87da138971b0446e868fe1a39ef268252fb06366eb194d1f69c7a86b7e805761ee0de00c7113a2e1c5f405cea7207ec634cae3a43308d6d3caff7a9baa0670c9256fb90c61a116abb81910fdd638075283bc76928a82074255a4375872f02cc9ff13b75240609fc44125d46e8071a94cfe1e8fc68ec03665daccfd0dc385687c79e5537661bfdca8462d3fd86ce26d599f5add12e57c49c0ab1347c2fd967cd62b6e88613051904a975051309d5a43f9782ee31fdba8ca641f8d5a27c8cac9131e33e24bf5a1425dd771aadde8bf0fb7a0b7b896dceba013aa5c0687e327c27106ffe79e545f2249eaddac393a6e062dc296aaf4496c4936dd0365d3d248dd2811a95b2789797fa05e33cae686819789fd2b1315aa90395b0afb2f6084836ab2c78216b27ba6a65f09b23006957522679a4e372369aa65a3bbbb8c8af19039ff0cbd191ba65c0d7e0acddfb468a253f631c4495a808083e945496432a10195fc221535e240fead5672421cc1ab3010ffd3faa39f818ae105dba8d6a6fb621f0b86ba9abb68dbbeffc24b26e55184d4f21d8ad733ef0fecd4c6cfd5a403e551c91000cb9b6a26c3f6a246eace5717c784921cf154bc7fa61da54cd0eb55846c086a6a134716dcc49f44b55994217d5e92523a07a28733a95efdb2c6ecebc6d3ef790ab10ccd113d4fe96144d0e4caac971370d78331fe91648d32c2373c595ae848ef70a5a786c36c61d5961195b8a2c287608b9596224ee165c22336c07643b08d3c92aa5808bdef9c3c35bb3a5004f386dbff06c9dddc925fceb7f10ada52c9b5e100ce0e45fc23869f18ac4b3ca6561f98c148a86ae197d17066da6421f4d73ff4c16b489e84c4b09afe4c1e8f728f9dc4e4563c36ea110870a341632a390981fc1d114052eacffcc06d550c329bf38d7460c51a3ee0342d87157450989c43788b508e9537d08ba1017bcc0dc4c5a8d99ae5591d82fa8b258cec35a1446054aa449b48371db2f04f25cd618636309b5a40b7a32e589c80b69ef5cf19bfad44da6687abcefdd35603f32028fe079c1e541854e5b0b56998b4bb02ad89b3ef22229c9a8da7a381fda304ecbd458c625c779d7e52c8c44fcc45322a21e7a78d896417b513e298700389d0de1a50c7a3b653c87006bff64fd297a54fca09a4662d9710132d16e2e38ff4eb2a4eee0bf9b9d59da5d828da4cafe77262af02a279fc22a1a83aea33f9887880542e274c950d707e766eafe8610b0cb8aede80cf900f6a36432019e4d1f561f33ba1d273573cf1908a9dfe9922804f9e5ac279270b21d3b5edddd51c1fb2e8aa8789d0cd75c672eda3b06686ff6e8c7f5cc3fd67d2fe91aeda8a22e73aa9624b7b18d0060a64d6ce2ec77657b1d1a878672d5bc033aebbe3b9a7a224b74d859d47d89a360e2f7a1b03a4bb1ae92c063ed85d5d60391d9553e4d3776c5d4628146aac13c22eadd0ac57c46e65c525775ed3edbf0b41a01f83a2758aafb5324c1888a284ef0d47c12b15c6c5d68affe6c330110e0e8bdfc2b1a8f2fd67617e76f975a7d72630cc24e98eb45b5e9c8c442a5af3ebe4b3d3809db4abd88e49004d339a36265898c5a65bf5263d062cc9a307563081ec6b0c46bb45b92eade67a15449e0ba26e280fcd403cab8c29ffa15d306285b4052611ab63ea0549e8aeeb037e29cf23dbf5baaec582754768b2e357187343b3186bd6e1128ff92bd7c707f8b5f7dd9eb88915229eb0c8437d715f1b59d1e478b696da3ae27fb756db092c885b6636f6c11abd70ba3f0bcaa6340aff1acbf2182186981e74490f679c6b619522a85441902f9983231c2319a1420a2c3e050fd62433631a7d9b6947b247571303e22121d25c30c130e90b73fcc0367d4b7747688ec709079d9b28b981576e0fcf89593be1bc2868d12cd9b2159244286f46d3c270ed38bffe97bfd1d51e0254313703439c148f495dc73c6e534d05d0041c3a4f02ddec5fe88842b4ee59284a1cb2dbc3ee0c4c5ff17a5fd6b9ece5b23f8f9548cf537c4dfb6d231c0e8ae2fa7352d2c6df9d78865418415fce33cb613593071d83bbc30ac710d2c313648543a762977d43979b5f48c2608a68769b2abc933046762736a42a9b319c78e98be5500fe55b9dfe9976654e95999eaa2dfcc090500c8155369f49f3b9d296db180268de2bc26e3fbb428803d9075a20582e075330aa8d84fbe36417f9a3ffc3204583ff4d2731c27ae4620cf065acce9df4e8c728dade6eddfd09acb726d27a7abf9409a49739f84044d6403f5b9d1855da0daab9d54e2ac26e4dc9c71e63da692f60a755902e9930c21ed5c3ba5d1afeeb892794c5c948a236a2e01066892cef70267bda3415ff51a404207f2f681bb72fc0a14e2720277558dc201958eab0acf7157cc78ef8a9c12266932d2548a559c401cb4c63b36600638a61cce16da6005fe9d59f6a7ef14fb2a4b860fd7b79f0a27b8a7d631075f6ffdb9fbfd8d2764b069f0e10b78605b25fdfd14bfa6825db8c46cb6aa0c976fde81a5929c92240e0b5dd8d664013e561cfdfc59bc7f09bd499aeb45b8623698ad7242808e50f568d830cbbe864aa4bd403dad6a4eb67c33d7db2180d7ef9df51b91bb946bfcfbe0d216673ec34bf2dd72b2656344311191b8b24b263aa6852d1fafbe14b45e803c2b6d0b6293d4f58de21f6ea849f3e8fda46111416eaf6b8284de908f28e7f07eda6d42e4f6196af945fc41301545a848d76201cb84b3be2be65d14425d7cf0822177be934488a439bcd1120f3131d5c78c213df7bca4f92d39bc4274bf0b984fe7d6a35af08362f07250d98e8941d7859fb19a2fda77481d13563eb44b0ab019801d3535ce9ee1b8c24170196a8d42549345bc4d8af3d7a12f66b3dbab325ba4451c345588878c697f16fdc7c75a0077c31b2542407d339a90db740a9f2f3f696ed9d8729c61d296e0eab52a95eb5d3d6f1a9207cecb9b85661128ce3fd6f53b205783c95b11f3d599639d66967729fabf5e0dc1d4e24d7126c73ff941d6d996592cf26a6f124b5a08272b88d6f9f3869b10a7adfba87cc683f2a99e695bc29220b611203e82f67d80ca3275a79004479802182431d2d7d8dc4859820d17c483cd94b0ea11c286fddf5766a048456390ec48b2d5a94d2a59a236ed193f14a9d65f30e82d3df3571bcf7883da9bfb2d95dc6549cd0b9dde70ac082efdef59beb75299ad178cfe7f00679b9fac03adfd44677b8991f9b2da8e3a74b47b4f41f9a063886073a19a43408362497250e8428cd18ed437643766577306975a566ea499ccd3b78ab89382cd5b0bd9b84edead83285a6954264ab6e602e018e69754776070566408719e16ed075d9129fee670113899015690b3696d55b95b15ce290b2a9e8aaef3b869c215de4e1775a480a05be21e2a699717c7c568a755f4411bc2f05800841284939d08bb3bf552c2630f541cbaf3f5e12a12f907863afc72172bc56166c0ebed4e904c05a767dbf47683af7f8b98a16c859180cda8ee3d92b143aad733bdcafc7fd88fce16c39667e9ad26b73a496de9f5065eee7fdf2e7babf2ec58ce83d3762fdfcf44f76aa8c48a32d546761c1011e785fa09bdd5b9b08acf3e5f407b1c733270d495005d5f8709fbc3b3eeaf3b4845e437ba8d2ad2c20faa5c7f4de572ec1357e9c8ee7fa2987529a72572b59bca31467a6b77720acc272529b0e00ef04331e143946287d0ac080d80240d2b31297687f56a7a199b8f49a727d40cd14b61643b6548aafb0d760f3867829bde610960df12851e32c8ad61a507ce824fffa4656e92ab12dec825104c5a19379e11a2eca89165569d0de12b25a9083a355172c34e4a0e26b32aea3ded77f04bd2a6df6f951e295a6544871a06c4554a645b2e29216b3131832b4291230a0f85af29c1a5bf84e38c0753d8bb381bc5414b458c9c5568837885431d5db43edb64d81ef9bce7c20d89a5e574f376600d3e9b356fb1a819b73f6bc16491f7f0af200b787359e5de299f35567888796ae99b3a6c82e2b579c8338da8ecd499cba4a1ea92dc8090487145ad6965e702f3d9ba5a09f32e18a507a2ba1b40342ea2e3c4e02c908c99a2ac2c4a25d08387d8c444f78a4cd6237c047bc605afedea209df85ed0924489209a3da321dbe671041d827e022dd97ced029b73f6c8bb503bdffeb6d326c6a4cf5bd3716fb01a0d3cc43ee43dbe5692049591171209b47b86154d91cabcb955646479ce9d11ea660c39d7b4bcf1ad8b459b4f1589bcc7e1683bb4966cfdecb626ae1379fb66539a3cd5b28e24a0ebd290d2f214307f3d39c64d15e45d5aa17d339fc6a09a14db59e1dc2f07d16c97b117712c468b1beae5037ec65ccd569262fc9b8e250f6951bfaa7ec3b0511eee88d13001c4fa091efe03e41be5eb09e2a54d56b166ae26b4cea5869937801359193aabe0d17313460697e82b2cce51936393b6ce83167c5eef9131b2f7d85893a464a6bbfe7072fbac1f74c5f6579ebecf3fc000000000000000000000000000000000000000000000611171c22282d35""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -b5ddc2872c67aee1328b8becc910a85ebc35da9cb9ac8d19f282096d0022bc51e742ef864c6da6116ca688a707e1f4bb86b77749f35d50d0f196d788539cc83fa9c2066c61d643639b246a346f2ed24b2e585f0a43b16277b8d4a17f68c9d0f8aad05598b904ed2de85e7dfcc478259e10b452cd33c058d477abfdb4e97e5d13102944211091984860443421d4928944105182b82c99c65118394222292583183118b305231584a3164e08886504488089b08498b40500380508b148dc022114872c1a330001044619134c10c9011a36829a407240947060c4689190045b9600c2b0514a429009a6811819658a16854bb090413492232690c048488cb68d4a0664da1082c9b080422852a1860c21a18124b590921042a484480c900d01154111213062c80de4c00022849003094814c1092034800380311805481122702325319206861b93114148048438706110620932620cc60480a22848020658348201866920808d60085084c84420264c0a1272893881c246889c947042442a13b420a190305c420e5208714034260183258c064a1918655882700902601c148cc2340a931204c89265c2468188a2849a8880530472dcc008d122410a014999104a90442124373004372a12c37112002d10b180a248929cc2250cc8042396681c004c09c46420a92c09974013296214054e61942d18210e809631142284cbc04d8ba681030321504426181531030882e1120961168604186824c14d91268d01108a80444c53a02c6392655c264d1110510b1665d9b8490b336248242808852c113462129591d8008c843884a33671c49640639428ca406e53c6001124649cc000c34290a38690d9060c24c3011a8350504246093784d0146609130c1c39101cb90589923021a0845c90840802511b9924c0982d1407018b262d18099021062813900cd9288858a6841c480120081260906449087099a00ce1386920a42c21b56099020942808423460d133089642622e1c44d88a28121814092b42cd4a40003336588246c443429898641114981d010515ac40c123420c1c86189442a144771110632180102a02012089965021081183989819489ca40020b282112074521a84813834509398299146051368e01480841042ea2a80d24a680d04065c9222614029122a9298c8624c42470014086cb406902036e11a2251037640017088c988404496154269049a070249861d8408e2106094a122d64224d0cc59114441299c070124931043065114500213765e0b240a00071208140c8826c13880949068e0030021449258c26269448045b026d0c842de3368189446cdc40450cc48c90206943422843106cd1168c4186804006915000891ac148c4202ce3a429cb8805cc4262e4166582882413c3401437401b3204909640d09044a2308a63268e51b22d0a1624ca9224d2186601118149b8048c30895c0822990005e208894c000e01a24c0cb57040c82163840441948818802914b130c0382a8bb89002220010c38d8cb22cd8284624a7701b4741184461a2028e0915869408480ac96dc4440a0a927008252902064c0c346592946c4c4801c004641b170c4c022884b6512125611bc90012c184981251d4968c13404c523868e0344e4332645220914bc4515b8609d4c841d3260e0cb94964265140240461482e8008820a3025cba29109462a12010e019985d39425e148800bc51113b92018437209188ca10662433241c8c871d4346d64a04d9c360013a300929691922621dac0891a346ae0c6641823511ac080a1888498a66800244c5c8868240501c14861c2206e092865c944029a486e83080648a00552c04c09396453a20803115103290223c52482824cc2b86924178e02428a94262d82a46011a705249860e3040994c41101904402b101a044285ab4118cb8092437429138009244240cb925832809e1c240e0006ac1282498b0405c406d504445114342a4c63061b408d49865cab80854b620208741cbb04409132248848813206c81b85002146012074a1946491c420a0337050cc42520b351601062501029ca1422c9a06c0407020b90618b323102038404404a03024404074062228619930d541011909240d04806c90252944270110568030830cc0612c3c085442280da408992b0650220614186294c404d91343160144a4196691a154d1904214b266660206084838bcdef36d832a9f7ec4fb59f74ba844968c5b6af5fff4aaace98c3a72fdc15ef08d34c9408502f59947b051408b44e5994c7f9690f1c62ea8e9d28c28035b015c5686cde3cf6701b222877ea972204e42e6122927b89595b79d347a63b98d54ddd0174e4b17ee672dec0b36e3d10b849eda667c4e6fc973a56d2e2e048451e27aad10ffaec0b7cba07a1c1600b78b25c0f5057798f8a394a06a95bee4265f900520855fc268eb18907805f48779076e43f9d7377f109292f932d3539f41ce74ba337762ef193d2e10a26cc96b89c53c7615ca39fdcfbac0b7e98504bbe2b63e1b12f851002958734a742cf4fd4d623d557fcf5bc4c30a44234e76fa15e8d151cccc190d1d41546919304a284c8aa13e7be101e628da63c014e6208c0ed1a686ed261f6df4620d47abcd375723d3bdcae88bb5b2892828636030e55c65b152b45a93c775f597e87965b06fd357c0a1b3f626524fd54eeca30854a79a9229fa3655235af6cb282c359be16c38115d3c56429cc9f06c69615e745fc331d1f22154b393aad861ad2c32f84bb86d191ab2c3061886d8d19d98f61ec8d7d367c4b49e0bb0e397c357d03488e61c839482112a5f048e459c1c17147f3b86ec6084800a1e76b40bc93015a8a970fa303fe0a14611f9b56f3ffc158a0a56d2fe88e79e3d7f6b081e45101685e1d39508bd4e12885e528f2851373b098a6f194d3de6e9691f7c6da983c851d57a3fc7f880eff8763b442f259b7ccd1b8512efd92cb5998e34fcb66800d262750ab5a48b06302a6bdf3e5db99295bfab4495e3b000c9560d1e0b47f3b09c8ac152aa3ea2beb0baaced4ac848dd0bca3d469e7185ea8ccdaf3a00dfc5b94d8cac2e2808a124ddebc0a9cd8cf149b0667bfac04528036dbb4f712119bc16d64a3021b2224b87d71eeec8c7bc76fcfe73b379e88f3333de4907c37275f687716d9a800f20daa4c997d31645c607d68675ca11786fc0ef0661dfd86999f8f74ef0a725eeb0542322c8d93b44e88ed5f5c14cbe844298883328e3a308dc45f5f1621acbcdf07d6d9d50046ff4b9291c29da17ad852e6c9fff7fc079744c43f5e15b09dc936c2e0bec0b193e46fc554eab6141edf6ebb6f1c2850c2b86d7de1328168d452e7e5579c5b073a644ec6a7fac8bfa84395a61ca58ebeae4ec25904e434fddabc46b5f20995e3c9777b00a596ff5941b5a314f107ff6f998498b3105c4af87e4ecfcd8028f45f1bd153e755a5dad284d9378831eb7adbf77fd9aff89ad3103ae36a15c1ce0e0790779b831d41f1b46c3debb9cb0de31014b256bff1e762648e8281cbfc14d9d112ab09bc0797edff3e9091891dd1d3d4793a5b3e3bbff48c547c4f85ca692a119dfe7441c391631cdf88bb96c87b604bd07b0fb8371442a00184fb25a5e667b3941bf2efac804846f083ed3da56822580360053820730f2d2a5e1cee420d6dfe4d332c1247ea5289723cb85e388ce90282100589800d3cbca235188ecb2d5abfb570c7eefcdf22306f21bb4da8c43a15ba12e9c6fef7285435b27cb68220bac84e391cfe771155d76765029a419fffa8e816e5ff29a68bb06a7f47cbcdf1a26e906244fc72c386e659d19df4eee6d367160ffc2cfe817f29d7ff909da9409c3299e234f134d9973925f36629a8782bc9ab3512d8728bfb5050a5869224a5cf48bd69d2872aab8ab5adddbea766fd0232f4d356db56e8b160cf96d6091bd5d778e168799b324d9956eacaee57addf8d248651e818510e84e0c4405fc142619b684d7a877b1a38c0185e4e6868f2fd5127e053787df17b5c395912f398ed3bfe4cc71266f70c03669e832ffed231d0205a80338adf332aecbebd18f144d49d5f4a56df53125293588ae01b0759d89f9065892e34d2a3249b8b725578f0f3cf714dfad1974988c4ca3773b9645f4b3042aede71e7806583a6c99a23034a30b11d9781cea44ff6682169a7674707dbb1ea2fb116e040147c09b136a659859982bfd823ed02d1a0d76e31881d04d4fda5abd11ac7c1e940e47862d97060a19f6ac1d1e765f3beb1b1b2dd4598cd7919f7532b809a6868f1376a37775a878c70893151dfa0295e26b28d02fab07de2230c655b93b3ce9a100edff4de288ec6342696a19cfc94cc2050b7f9a31320746b098d58eb1ae658b9498ba464e22813e0fc4857c6859dbb25839130eecf8739088b15922b58b2b313d1485d246d45b01604d24f824520f8de195a1be7bcb091a73da2dd24c9b6ed7f7e37b457dd159a42d2ce3b583ed58a9101af5952049e13a48cefe3fdbf2742ff036bde3033903e4ffaec611e56930111fa57de20491b27aa3d0a4b9d49f2edb4b2cb5b2158e5d2afb85a120c7571e302ba8282c72a642dce90518040852855e0a5014104afb9ba59e99694a3115684d584e53c6b7e4b91da922634bdbd39989a78bd1a78a0b704d19efde686e0335a4b9a336377a61defed1df47392e3a7d8fb54e9cfaad9152f151ee3becb9d2cc120694aa7226e31297f075aab8ddff85b9e8d2432b0aa1b4f566c1d5450309cd04a87cf7fd98d1c32798e20ccf5186ef04f6855d1ffdd007258769cf503426181c0db43fc4475b15d0fbaee1a108caebd0e45b61f4f713f0930d4245639bf5a280ec5f9117107352e40441f55384d65219d0bd16581d84b66db1ab08ae02fe364143c487a792fe25ddd943c79216f060b26722213af273a77c71b116d472c1192ab17476e14329e91b97e628c0fe31cdab79776743d1b5502febaf7b4997c5acb7f972e4c14f29404729503c2b777798107436654ef7d587109a7c84cf3446e9acd6e02098470ca57d362666807d070106fe0b2dd8b5ae2df7df00af2fbb16d1c8b682c2d78cbb30a012c61381bdd4f4bb40e782be5f298b238a78daf7d7b9fee2cf5741fc874143a3b2a23009fe9c393fb07b9eb9bd47c81da68cf36ea55d026513e8b24e32256023bc25c04ff1012a53c391e0e1a9d67d9c0534ba3851658bf5aab9358e1058d0cf765a5342c1a22ff844093170c98a8978cbfe9fdd66ee2f0a5212402fb671ff514176b6e682476f99c52a3c92415b16bd0683f5934a72c5896f0ef8e66641bf57d8a3c32d439df35daea00233156e7bd0e0344472a5c61b12f0f56d685a2a33a930f01abdc5486afbe88acd708bd1d91a8ad67ff790bcc1c5182d90b3c773888abed5d40858a6772466cfdd615c939a5d05751c31a840f8527c92b1610199f8b805f49eb2f6357c3514edfe1408f15d80a279acac7b81bcb0573929efcc46028e010fd63da182b275f782b440f97ad406fc7874fd82fcef86e66474e495da746b66761335c5c4f91ea4ec4ef1e0a6e7c1d2b387038c9c1ec2f0a3d43723ac87a3dfb11fcec3f5237711eb51ae05e922bf191bedd7195701ca7eb4954e0ffd4b5847aea2b2371a1190655877fb3f6db2b2b711e7d78f94bebe7a13c80bb60fdf39ef3ab8a41f2320d54afa737544fd4c15676f3f233d66fe0a15d3359d391e8c3459a4c7d45832e3bfe9ed84d259322844b1eac42c4671c4c83682ee33fcead04dd9f7071e0c05141ef4696a34f04312c33a422a99c38c908ff288c82c615ed6547caef3ad525c159304ef2ef0d43fae4931025616592d52e74abbcd29c4f70e5e3f34bf518812f856996039a5d935a83e50c8fbbdad797b3b8f7384e32eeeae3311914b4c3af5ab44f571b951d93b4223535be0710107b179ff0ed2e54ea1a1ee0c1f16f9fd0bfb49067c7d1131876047372b088f8edae28743d1ba88db1446766ccca6da5920d8906e6efcbde6900e7c1258855c8beceeccf688c0fd33c662e299ae99d6893808a731e153388d34f9800fb79962ca0ef9a74a8436027f9e3f7e675acd04f7a229fb90a8528ec858f54f27d86470d41be50e2d0b7429287585650f8fd4fb8d6e59330a48dcdf3006fe6f42df93daa5895c58b88f0aad85750d3c334159b28f10d2789fc7b6da5151495b351bfacba9d93e095312fdacfd4ea0820f01862fa15eb854a0e6b35555e175c9943774f597db629bd819b7f9fc2739d0d05d7d4c0597d0f47559d1ee568d3b46636e84bd8655bdcc860b8bd83b0224fbe0012e65807d11f32dae38386ca685f7e29293597898652db252be08133dab4e135cf51f8b0d673d3044c609745ae0f2ee1be7424ad13b7c9b1a4cee828ae9e42e67eb6d788434332ddaccc39461482d2735794e83dd84a3a06c79c5ce6890c6edc46a5c659526ac61918080ba96aeae6aba17f6a7251abad39ff239ce1b246c1633c7c3cb23baaccffd2c14e8166e592464bd52af8692854e18398dff5dcbfc0b13bd5354765083e7f5512ae0944a682c874c85b4daf0bf4284d1192523b43e31c138d8d539437ffac9ab1f7b87554de81b2d0c6ec325da31dbbeb0a02bfe7aded25961d104401c59625f4527ad3c6387e98289a2ca2ece960d8d17d3ef8898753f09242cc7cf4d5e1c012efe7c2941a884c974138981f4459d19f2bad9e635d80d4c5155fe0da12e712406861fb8347af5dcc60e58867b860ad3824f713fa41022747387d0da1f4f973fa1bf65ba4fb4c805b9ff38559535c40acc74ff0cd8d60534257c668017bb041944e37096243ecf3e79e479938175edfed4a14432773aacc5a245a96c1e5fb4e5735bb07332e6774a36fea31dae9f471c1ec818677345c67"""), - TestUtils.hexDecode(""" -D46F4482D570F26C7E9F0F74A354174CA145033097CED3896350DFCE8200CB9448F522B118698DAD51F6C672E1B12A412DB6B7B95CDBDAF6205DEB631E44634412F026CD95440258FE5F0C72C5F3E64FB3FD13E545DD856EC2B7F51AC28C0D5D698C66C700DD3E409BFD96E14A9DAE1677ADEF2CA2CCD178B826AAD3859E569541561073095EFCA329B5B216563D956D8B7BB918224FB479FF7025FD8168F54D14ED1FDF0B399130C6117B5645D0E8DD242C3C7AEC6A8361361CAD9A8FC3B5A40BF7E73F1BBA9AC7F5A583A5B0EB95AD0AB4C1360D0145FC2C3A9AA50186D649B72B41DB7EF392E663497B3166AF9BD0C1AE21650D6CD04DD36532AEA0FD1071D6E9554CBB575B2C1ACEA3DD4E18615FE83AA211F8AD330C78FD32D920ACB40627CA4AC80F840A64C019124079484B053F525A5403383C21B164D0C6BC1B462C0E1C269A1EA0B2438FA64934CEE47149C4EFF566D9C2234E656969C1C89A0B0A4DE124EB920FF534B934172686A18A1A269960C725940D3307B8A913D56B78A6CDCFD559FF97E225B61AFAE7F62B060E7D3E2D4040D8D9233A24827434AB4EB31B0D528CB0085953D9A1A0FFB748588A2DDEBF241F93B41F5C856159EBBBC6571AB12F4EB534ED3C624CD3F5F836A99C7E6E2FFA0369654A5C07C19D44BC9FAD96983660E4D6F95DD9C38D84DE11271D23A6158B685CF050121425AF91C6FFEFD0B2061F54CC4393F99857F3B9775F81B6526444AB705F9CB88A2D276AF2F530B646FC3D93DE7087EBC1FBC7F9A8DB3F3C8FA186F7B636CCEF99FDC4532E54F560519C94B79B1158D85BFBE23D4F36B64F8056BEE7558252DBB3D9A43748E2E6A338162F5E2BC0934E89DC79091180C93D340D3615F82E7780FABF782E5FE2B5D504F3BD1874EB5DB76CB616CC034D9B2B080319FEB8EB97F62FA4498878FF049FA97C56ACACD2414E0BEF018F25A6254448F02E64815E525AA06AEAB53969A66D453B732891E31C36679B5C0A4637611A5983F21F6D4ADA1DA5E890C909A9E968F947C686C17EC73A0F9BAE5C7BF7433133F35F22D2A0B40CC135A7591E2CD216F7D8018969940EB9A5C4BF21579C524C41AFF5DBC0E141FBD02F1BCF376DFFCFBD06F9CD4384E128CF1F03139C853CDD04DEC61EFB8F1DF1A6450E4ABDDDD8A9D85BA79479562A08CDF06BDDD2E740DE7AD9AD1016D72A649A73246E8DAE183AFCD6FBDC64B6B6B2EFDDF525F3B764CAB39BF8D617D47FD3380B4A30081AE6C3165E9437B2F37A73AFC5E596AA626FE5A32D8873712F99910DADD0DE296577D4749F88639D07F83B0F6A05B1668D8008EA749580EE5A629FC2313FAA2F8ADDB5764B242B6B595A39AD76CED4CE5BC34C580069071BED1F98CAF4BDF740A5B1DE3FD30C29DAD808537CB16D0EF22D937F297F50E1681C898375FE0374ADD6EA1B84C10261DBECCCA8E1D224A4709497CE696BCD2BC1369F4135E815A781EA26A055DEA28AFCFDEAF6AB1117085EBF6B8AA6845FD4763FF9274BFE5FC6E377B9F9DA8263DC1F3D53C83F446ABA5EEA4095AFF91F3BE30022B9BBC2C74FC52A3B15CC76F29E541A84C5BF42D499F9B5EA134E24F01E8D866FCD20B7F7A302120B13DE636F48FE8EB99F17ACC153CE4371B266CA61D13E19793CBEF12C0EBA9C728096A3DC6A6750DDB0F52E3807C22EBE4DC6B2407593A1B7BBCED799DC3EAFCE50B483818D903765A63FF572F5D4481357CD6ABD89EC260417306DA1CCF71DA568240D4FD6858BB7833B2C9C98B9E7286FA491F9E318F25D0459071848BBA0D3DB8D2BDDFCB7B8E9C64ED67B4A2B5E1E49B55C6DCBF93394010A078E6F52065AB777C7F6D831DDCC115CF316ACF3680BE8766B4E15574AA383030EDA83CA45B965836FB2374695B50472C4159CB7980FE48B58B40C6CDD2629FE3C6DE6E13ED6728FCE45024C96402B78BAF37E74A1C071F4BCC2A1B84933C872FFCD87C02DBE65438A3E770903A04DF96C569FA69828CCC32D13A0A419FCCE454F06EDE43A97CE5A9A169C6E849F075C66BAB418791778ECB2C158FC19FF5927ADFCA90BFDB3B4216E19BE11157E858610BAA373237B42F811EA97EEB93D735828B2ED092518160A2ED894BB108AD74AB0113A8D5882D99A06CE2313BEE3F902D5CE9CECC835974A47FCF6FD1648C635FE56D1B2404927C49EB53FBD625E0624D5AA04D6C0D5A082C37BD67F477850458B8672C408CEADD9A55CC268B75BC51D7B3D75668D52BB701BD980ED22CC20611EF618277B82624A1192287B46BB5C4468F94C68D96F3CA3ADED476A18BE6CCED70924139F2E16C8A54FD6C9F6695E624499AC8E9AF86A430AB856924A0899E75C1FE4A51DA0DE1588E66044B2465C04809272B2A5C8EDBCAE42B47E439FAE06938810526DDFF4B64C515787B41885BE369A31F90E2D6F6C71528412572A67DF6E155C3705929EB28B80DF15345E0E32540BA9AB7E1D1CF0C015E50C9180372C678CE6C34BDACADF45B0172A1D3082565E16938F57CE6B55D9A711CF72E362A2ABFD45B7B56D48E89A0079E973F597D2E457EFF423E229AD439C3193C264E0BF9A8A1FB50266AE4E0BB671817CAEF10A3BD43452A2FD2DCBB2481D63BB539E0C81F6986400D3A619AA92F250ADDCF661FFEDE7617162B532EE2088A87F58E1FD071F5D720FF1F72335A5B4582F1BEB3BF19DBC9D51A62CDF68A855F7F6DBBE5FEB226C9918E7FFBC8A38079E411EDB44177F843EB8CC1F73B9765A0EAD825B3C43F6760B5F03BB75DC7469701AE555C2B7037952180255612DCC9CD35DDB31F3A9218397E1924791D29C410D2E4C3F5549B7EADF75045EC78D579EA7948D121E8297BC5A3A9F7AA2E2EF5776CAE3B9CB73316170F9B48B657BBE365B352A8129130BF1E718B386AA27E493016ADA86C4B3D3D116B7252A747FD50DC14AA28676F1C25150A86C9F4547189523280A3A897F80FDBBA073EC645C9953B7F8CEC3BD08BC0CA5640545B08F728AA38A860ED38C068F0D"""), - TestUtils.hexDecode(""" -4e4fc796e18a11fe191e08e2e59c8864e0040297897b07d4f62d8a003c50f26e7a6e3d6aac87899b27b308c206efb435b7d48b32a6384e6c733ff5f47bb86ab493d403027cda502831dee50a116708aa01dafa83fefbbbb7aa7411ed417620ce6b035cf27cfa6ad1cbe7e1979f024a436a39fb6a6db40dd21ec16b90a42f61daab8b86efd38ab87121c17fa77bcc761afda7d9196de6d6e4a9b45f32d9cc64ba40aec6c9ec42a4350f841c1e280d60fb1382540f5ea25ad4e7c72333d4a6a4c911a9bf142062a50c2c7f61329ec502e4b4295409392facedf088c321929be05caff934dea89cf0f13b771bbb7832b956aaaa329c666e5582d3e4c51c53bfffe1502559c542f5cd0c6961f1a8a6f4db4e109818519c85f781fc8b81ad4db1a2444016523d79f33b9deadc30030a453bf9c9f48b8bfeac3a563038544141ae621961de26af46860e0d80d4b66bb47607a559dfc34cedbdadf7903ae4271ced072c49c8b91aefac658d1482c913559325be77794481ef2ee6007b643a27a3eddcf29a89237c340867dd3a8bdbbc0a1c8d07586fbc8c3bdba699f08afb44d728376d12aa7547912fd9b8069d5d699773e426f6aad6256853c65a896b5266475b283c17e60dde89a3b79f6b8c262d418b219a9aee8de0718f171d31c24a632e0f9db87dd6ccde3e295241a1f85e439f09a8e17a8cbc8d2e2c5f68147c3cb0138a6b386d42652efcc71315ffcf218630f96734f0c93d0f7ae946a71ba6939401b7d60f9fafab00021628408c3cbdc4c25e2eeb9af29a16871843d124551a4437af15a6042a9b2ccc227190eb7b22eac650a5ff9bdc1bbe867e0ce4222b2ff68d042772f7035ba911f2c4e3f8aa094290584d3902e4e1416f11c313efe437128761e2c9bb160aa58be7f2e3b821c128d69849c6fbd2a4ea4662477491e48c482051ef8f9e1c62fbcb03ea8fc25134e59cdc995575570056cb57fa0460731f3a82af5441759ac4f7c1ab5f2b2f5207e9d1350e1d47cf338c7be3aa05bb9ea4ea2632eac008ec50d7980d681bf91d1bcc583332c949674cf42de62632fcfbed112da44fae1845ee2490801528dc5a9f14f226d18db70a744e5bfe097ae1d17d6e557f670998317d64b45be39b9fae81adddb53aa5c451fa9d525d8205adef6bf5a500adc87a0af2069db0da6dc56a0a8807cbf19172bf8f96992c3c0d2b4e83722463e6f6a702abb058c0f868e9d9080760f2c80a1f85e30018642c3c88b1489145de6d53d27ce3c9f1765dbb459e865d3f8c05afa507d6421f303080c77647486a0611dadaa0a9a58d83d0859dd57b492c941d47f97529d962863821455e52415a231e3704e8d208c15ccd4a1e5cd0c2b434bcf9f82495f0d94f3c91d1cb74cf5da019d0c2a42fd45580db8545366a56febec804a944ade29a2cf87fe5772b3c969495e304c6a7ec148651ee93e2d894342c830849db83f40d9908d11ab2c919704ad55c74aa968501a38069ab310945f0dfe253d1f58fb8dabea9a8160a9fd2b5a0455b6d899a22386c8e814cf50c0aaa35e4b0420c59c339b84332047c9f193de73a9cdaa6463ed2bbc81060a36dec8b10f002161dc56f2085ac03475a6ed6f7ce9695f8a0f4fc044d2494d632598d778afe58221e5d435491ebdc30c2a719f90ce17ec6aad77df11b50232bf1d4eed0195765e3d1c636ae13f0cf95984581fc24a699640ec5ec9374588f8d74baaebb831c219b4df35b73eab7e6e15bd5a17a2803152c0053f3f3aa8096facd15a4ba1d2e0d90300f548180cf9b9ffcacb0cab9d6e4877f7a63d2ffda4d9697149b61f8ccef1daa976f92889c3090c7fc5c69bd87cd39d02d2de8ce16c6eaef9ca623872cf4f91fd426eb23ecc9457ff881da1b25373f1f6959dc4986cb0fbab15f7ed3497896621dd6b45bda78b7ed75c7d38cf7e74443a53ffd456ca84ee9070421b796285e023b5165020d3dec38078e599ac79ab1eda37a09b67d4e20fecf31c0244846fe3ad9b5ff9ed2b2f1400b7647a1a12db22bc24a2a5f1becab6bbd4a911e0faa4f4758219c19d970d07c90efcf8f3de432f526082f73b4a6e6b9b048e00e9887c164a62f3758b8b2a7d0ae30ade451fb5b405fd3a7aa2454a70ac22af75b986e03d8de972814b25ca0ffc3335206d30a7b748a10ea20149477610874348c07fd45ddf69c65d1e1854e3eaa00f6e6e0018c7238c7c311285f1ab9c876c52d212781006a8300bc2ce4c3729121b8b2edff63b99a29a8bc8166351b84ad61b66620fc7d0d5760b6409e42450d5fe58ceeaae5abfe937091d2d2d022057b2bdbca1ff2c6f1413021611e09b3a79455aaf2512c6a3d2a949e45db154ad328ef646db243a3242440159f05ec72ee2f5cd2eead4885f2d6dfe23ddc70ecccedab451645e61b17e88cb39d6bf1f1600b2272e3fa523ee9b570e515d59c8e04ccda564ed5ac3651d206695a0b8eea30a097bda798645d6ce20164a2cae126154fb5d50ca5749ec608db68396d9b6ce620cd8d78b701d6f9dfc701a7900db628fc9c25f06e41a70ba6e9745c4be3c0c9b0913d2c584fb2630582cfa1d74fb598515a104423124ed855a9a900cd6985eca4fe1a921a43188fd87cfa5e9defc046000641f58573a70222f6bc22462fb959df93d1d5c2a2266dd4bb01ba465e4e301c26cb9f49ccd87f92b5d92a30c4e7e4583d95a38ba2fd2fda90c8beb60ea9510a43608b817a51b3c5f05275dea1a857e581cde0a5751a334c9e233353a213bf3f7fc38d6843c839cc06df3c6e76b4b6df73c9aa90bc24196f9668cdc2df584aa10dc8ab41882a532bfe758cfcf16f2e6d0e7ef2fc900a3e5f3e261b4062b1fa3aa49422c7c6baf56d0120710459b949ce7b21089c02a14d5907ffc10c53557477599d59d83f368d5ba349c3f3693da678f2764dc4caa11a669e5b703a97a908ea7abb18175b1f208e448b1b05f1cb3deba9b4f244c5905f4659c51f0152aff9cab8bfffaa61a98150425f14acb154e4db9aa03d73860973750377284c275405d726dd615802c8f4738799fac49515f8c04a9b2fd693d083d3ace8b5e872413767114fcfd32436181f30c25621bd6e808919c0abc67fba98af581aa4383133b47d7d8fb67de035f65d507aafb8e1908c8a3ab305b0b40ebb2f70958cd69ba48c3d0f94807f0159f3c3205affad6b2e48fdd54be8e5a7e5bfdb3f1599f62a52c11819b0a7852a3bc1a424596c4da3b1ea7e6e7989d3c403979263424397ebb5b5a739137c1b3d1566ead912214341ddae970955904d9a5e79a002e3cae156694cd895873fa5559a7a9d21f090ad77d09471d0d00f3ea2238043fbcb76e5ed947a3384b05b838a796410b87971f95910bbee1c6815dfc9b3752382f980d48db75e28ab8efd094046de4725c802e1c3de5fee6503d383acc450ca7d637a1b5a68d7f099ded08791a3e845b0a8f6dbad10395b76745a4576bbb66fd6a8750a83616fb5dcedf961c2aa6d90d602d0526974a93ea30b26b01245c74ad5d060f8cdb3476e2a6c155a676ffe0e4939790daac867517a48271501a702568e7b349507db9383f6001c596077f82458291ec65813d6d7306e8a83c36d76ccf76e7531823e8ba7becaccfce8ff2e25504fe2cf86434d81a43b28daa7d479ade72e302f82030e240bd61a52b84b372d460d606fb4b2f649bdc51ff2cf379274e1c6bad82b5407516b792d7c3cb6545557fb2db306945dea8092e7ba6d033afe77833375214c816a4c463374cf36cbeb77a12ff095e9bc4631a3b459273bd3494b1cd49493a712bafd08c6a4d2c866958fbb773eed52f7398275128622b7436a39eb724c28d70f55694cf22fc3ab311653fc7c210265fd6eee872add33250ac495a2f54c9bb856d1ec8704c1c9fe0208a312ef3a08445ce3e9b4db2ea1c4b1ca4e79aa5ded13ac3c7fb69612e74255e0e6cc3a063d28b8e883fcbe3fea5db704e674497fecf7ca75110199434d79ed8102c510d732e612a18a8ddb3384b60f19aceb88e4cc35cc4af247edde5c8b26101db84dff825f9878761a6e96e104303441b9954091e5406aa9cf5d8e4010b4c075c374cddd31f471f694b3b9191a1f3d7e399693e235898bedc55628de4fe245e59fb02ca5fbf1944ab74e2783d9c9fe59f0e6f0de1b2bd70ced8f5e87c732c82bdac560e714546afa3836b73ad16373b72eae416e31b2ef999b2f3fd13f6f52deac065d0de6562cce840ba490d7fd1121d8fc66a53a27d3cab9db374e5b96d44f64b11232b2859df9468286f268bd4f186d434ed3b3c807cff498d1140d7d4b018a03b7b2b86be6c6b3a76a49c94a821989d2372744b1ed2e93e6e978c9cdd5564104d6ad141415ebd06a2559887af6b20f6b664e0bf7582d0dc1ed3e66661ceab0533f4758ca9d9c20211adfbb18a7eb7ed460539a48a131c59ead08680e8723276c1926a35081573d4e0c057457047e0a8e031861e5305e04c0619a06867be34f58200e4504919916c0f85945d19c7d2b2fc20af7c058e5f99fcf83206607f561e9619219da8867c73c933896e24f55363c0deb0d258c3f05c3ad71b3c03e2005145a6d7aa4546d53dd24109f20f902f7b77c8c475538788d3c0d0cd7cbe07706e144ca238c08b3f95672b90076ed237212adac8751d335320d2ee0ae94e95bc7f5c27af3c8da67b8b5d3630c7c6d006ae3ee184b5ff781ee470b7a2a9fc87f5d64187538100fde4bbd67be7a2f9c25c4a6f8e0301595963c280457395883a80ca695e98af29f0ecdd33dc3b417d09d0b2d01c5e074cc1abaf544ba9048649525f59ed02df6b9baa0b61871c4605678124cf5fd1dad07e892d2b8c0b14c0a9bf031493aa304bac36ea200f8247305394bef54f4608efad7435ef3ed5d5f5393225587e1ac3123dc1d92ee383e17d74f0ecb1bb025fdcfdbe7f2d41d0708f1ad2f766ebf69f4933ec0f8ef6f65abed4d883a38e0127530e8fd6ea36bacf454abd510b1ec49dc1d3bc31bc7d2b76c949a24cbbe7f676ba4677e19198d86ce72628e26f56b7c595cd07daaec87602c78a7838ae0d7d03a8ccaa8f90fc2f9e4cb9555d096bdfeacf4619eb3562d91a5414d2a5ccc90b565453f03a0f08d4ab41e6542bd2c687f62a9f41f348a7382bde0561e7c03700b0102962314b014b83980eb887783858a0c2e7818e7c7435a02c21a004360f29097eb414eed5ad78084a1f3cce2112639ec7f9ee6efaf166b3e31aa4af7925e6866743ff8c22d865f28ca97e47a3c979d0c2ba32eda8f862db63e07acda1757c8c7aa4b61d6011f5169f0fed9638b3662af701e486fddf0d599892d4215ef4252dc3248d9fd9f5ba3b5fb3fdd9ed601ee2a1b2192a5e01373441004841190d4a3b44eb80ead8bfa9c541939732913eae7904374d288645f4d5832691e338c82e2fc2ced10cc75e353103f383cdedb81e22ecb341ee19e400451ad3bbf0d10181a796c3063c66b1db825ea00e197d7b41558eb05a18c8e2accf0592a331055d5d09e436983efca0c334919d44f5cf729a26dc9c2abaa4c9086c7c0bded5814de50b86b86408473172e0e90d5d32fd6f93621a37abe618ccb7dcc2df0573d4006bdc0d832156c82735bcfe95527dd6b10e71f38e8b46ecddaf6eb7175879b7f843d821c7edf653b776cde1d389db91c3333a1c733dc45ead2f72644e125e4e2c7694dc4a80b4bb594cd052b470afa7323c5d9de044e9de8fc307512df126e794fcda65d4906ccd8caa5607eb203d4d183569d9cc530bf8db3989b331c7b4372ad0514614de405634d8cd1dc603189bce42e53584dbd7412dc3a7c9fed69f194bc753f45e24a289db30970a9a68245cb62196cd8a36a02dbed39edd9c40f4f5e6412ea5d9ce4d92505112f6dfc1fc46d0e83916693a35e01deb29b5c0d08c9ffe75aabcfb9af18c35e04611429e52285c5936f782c11f2b849280f009d83911bd6ed58b7c0ec9f8d822a538db8492e5f410020973536cc460861e41515c2e137d1f373e6687136a5057903e1afa8aa7700d5e39a23be933e972dcb1cd67ae7edd452dd3d229d957c5822fc1846175d48a5dd25adbe1963048bdcb5ebbea8bcac5498e7d805a0746a95f6ba9a8386c387d4ef863c424d62276a90c847e9019eb752ac6d844e0e45d78aaaaf567af013c3bd313ef23e06f4fc751537561ba52f7ec15cd460d8ab9ec917e1e33f175c3c1f38ec99a09da921ac62dfa458ef2d0d15d4669aeea8d797ea057ccc86431b4010f56fcaf4e7894b97d542bfe0321886333608e9d56674c8eb885086e9f312c6926713ad129c6faba2b764e4646500b72ad52f4158a071e0c0697dcd50bbb17b4689092a36bca28b1c6c02d39dae78e2484ff6b00ef8b5311cdfbfd061884d23dd65d1b0ca4a9aa491939e13202b515d6c709ed4eb0b86c4ee45484f84b2c8d5ec485686999bcbe0e746acbce53977aaeaf400000000000000000000000000000000000000000000000000000000000000000000020c10181d202429""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -dd746786f61c3e55ab5c50adf85106c1e6b427fcd102ca6495b52558626a21a47f456ec45fa057d0e1aa9010416f9d3e8481ed052935217b3ec0baae80beb73688b4f772a3c3ec7114072a3a9ac5e19a0c32fcbe7331521bb83ce5560700240420fedf21d515a4b69121325116da94da0ab9b51f0c66fdaf466baa0ed1d354a51b41685942056304820103911881001a1480e04251814632c894804ab80121166d0ab64d04a36cd984508a462503458a20873059a02899c06c510268da865140982859c48c0a106ec0c42092b86508363022126cd144254ca2095c0062c3968cc9a80490029103128d19288dcb1448184784633241418670c434925a322e9ba228038905dc1880a0322dccb22049b80861a00c819044194680092345a02231012221cc00122316001480401c46400142268c027198b84004024ce098692425895c440999a28460182c1b898d83b08d10a50c120466c99004e2860949080d1c08410b49219a022e59c42d212770818664c90624442440d8a448a4c8400149655cb24410c9081c4664c2a284001668a24644214404814825c90021e4801044368ad2b00559a82524b391e2c229d4304524838cc9162114206989100594009121354dd4045012a86403418ca21865a44421e196309ca44c0aa210238984d8b82c229600002041db328214c02560124609c985cb32115944891a13429122048308491cc621d9c829880245e3a60990802554042cd80465da066d03060a01c10800173200206a5ba4315412254bc2240b089000242d83468e243105a406658b285103264ad1b42c5cc04c09a18180226c9c98910a35840b868d44106204b52cc8482441100c01846004b065c1a86960882ca1288d94b265a1c20123c369214721622042981489212962228500540072594029cc0622cc342091866902c889643025e1242cca406c84a48c1c1321c1924dc89209e4148908b121d8a4011a957048166d01190951320c99148d18150a6314688b44260214469b140d922822c0208941a86d191220492806604209898888541085a122484aa28dc1846008110414c60199c80509088951440e84a04d21a271a0b02c03282c894880c43011e220881b1846da36241a499220a061d3068048c00488a0299916042123402411690222699914925c262c48963192044c08304e8ab67104216160266c03456e2290618140051c049223354d0b42500407924a306551c470d91012133385c40806248640e202498a8289cb08661c3650049844a3a20c0944250a872d01c6485ca48c11931184464222018018a145d4120a2147605910209b9605e1288213854412a28d1c930004c065e2362062b4601282495436704ac245a0a801c4b631ca82282201921b922920a925d8348658464d110449809668cba484e398500b470288020582a82cd4b820d34231caa08d6222890b236c0b87211909281925128c40709a2808e3c851ca867059148aa248729210285a0812c89450d1300022b8654884202490082396116128001a460dd1b0280aa14104044840c045539401414832a19421dc2686e0b01019184888324a09026da0a045119429238005e028255c968082087220a3910b0452c0b04124b505d8380148126898088c6406301a842c53c24d112409422264cc0602d00869c4468d0b366a218649a114301a95704440128b286cc0388edba648119881a2b2702244690432685484289cb2451008720005101a881002250510a2500b35724ac05050a2811a1688cab8205882610c152523166a93107053348a00438ddb08328308094a10080bb98103c3851a16319c0461e33809d8268c4ca041012591d9925104a6688c8024dc4886142310c2386a843289c948450c128ac3826c8448221c09801c108d19048804373022308401285024c561e3108e09322111b404d102096148128a866513a02562162003194251122024324d183666e024614116888a46910bc24802368de0341058046150445150b689a3a091d4c488d1b0059016329b48654c100ec9b84d2096809a088aa3168a930084a3102418c54599808488841118a7699908604b108cd40608a4c82044a0415410845cc06550424d10379104360083c4404b448d9ca8400a876c9ba4609b0211d3b209d410891319058212060b2551a3c86812a69140b6005c862ce1882044920819b3101bb860ce18425f2c44a094f3f95c4b2b11bea59d00c8adcf72931628dbe4a8b1c4aadf1bdd97e0db31ec98e63b76a8fb0cbc0c9487e76ebcb198aa0fcb2c82162ef9c980e437810129717ee8f285a8b6fd0dfbe360de8a006966c495c560a1a57a41cbff1857dca6efd5359e3b31f5dbc8a3d79c6fb73de995b77fcd5cc359321b18636392ce1a9aa47b7ff9fd4deb6996471ffb7d34a1afc3cc59a1b8ed15cf2b1cc1862de68d421a7029d79adfa9eebeeaed25237344b0a05693e4a61370ed3e08c4f2fe844674ec64c70fe2fecec799e3ef09348b6bf74de004098e6fb5a8351f4749fa43a2035e443e0b5f1bcb0db0ea30958c417def6e6111a68f101ad11441a758fb8ba2212044b7524041fa12a417793a708b31f7e4ebc8850616143efbb9b1db20e8e306a05fae31afdf6f1a5a389cf8aa3e17befa6eada3d231186d7be8e076b3dd72345fe539bed1622645b75a7cce268753e95974277f242d52f70e61daa57a630311d7f709d59b782445cc3be2509ced95bc4ed23daec3e130684d9ed85cfaaa457b877a940786ce854e9cd0d0f87b37f3683b2cdc8540afc14270a5c661d3d99f8dc978e67b57b4792d4626202e8f61be355aba47eefa5a3e55a17b49eb124be57836f27e5cfc0289d28b2c3960eaa9d677a0d2698bb5bb9d3b53aa48eed8a828ccb71987bf65e443c6e38f5f5bd143bfade0a1b48d60ce5f0ecff2029c9122bfbae67cb74f956dc36d6fe9a722b24e6aa2cefbf084141f725c7178ca5e7892c076ea64ead689efe46c7bb64d825c1cb567e00228f1ecdb84c9c8c5f49508addffe58830981f2f57bd88a3c8962eb4b22195bcdccf42d584bb878d10ce5bbf38ecefe75f285f2ab3a594b8a3a12a889162d6a45895db914e99e35884c9b031612b2cc1e0bc552f49142666914454b1069ccb13cfea0e30b7e4c978aaccc77db7049db19a58f0bedc857d869ca91bfe2dba2fc8495d2c557419b7f92a1db1084321a3791b3811d7ad096a121b338c15dbf494dd703f7ef85b44c445f6e93847039da73409ef04c75ccd4bf524238f4cc2ed1da38198ce8a20a1a956eb078cb59309d11eede544c36d273ad18ff32234d906ff357f4ad6f5d85fd8628d16114cbbea2810f3af8c484681354ff6bba268d5553d1a2962672fc2eed27f2e77fe47b96e11903af01c96d919322f533013dfabdde8a3e94f56bb8377ee3be1a7583142655a49c52eee7c7503c65be61ce0ec04341a71187acfe329b2ed51678a7c63f750ca2932bef1bb60dd7889f4e0565e0afa105b19918fe47e57eaedd6fbbac2706a2de315416d54874b065958df969d7c1dade1e0b615a90c1f2708cc6dc27ca66b3d261f933407baf18bb51736941628034dfd1fd1730421dc92ccc7e29b87067c17a03d12a921eeb642a7705d9abcc023fed08a34b621a265262f706f13b7accd54017acab57b2bd7813c5058abc6d1c3e393f3cb7c6c2be70c27c3bc2f7cd01011d71a9a682dfff4f7037c2db2006bf8c30423b3e94298075f7bf7ceff8453143109202c93f1dca8d5d60bb276aabb8ee2dd07e30e8a720abc5ab9957abc3af8c478e8b5ca2520d81b9d1f6bdcdfc588862deb4c67071f18d90a95f3d4805a8e1d44b8590659096d4f7cee1df9f55f137f05a316b293b36a06f4a2b66d428ba141d45cc0d85abebfac417a56933313e9faffe934c9d930de5b5b1af5df86881bedc6691fe899ef9c1398f0ebe790e5d7ac055050f7bfd319e151aeddeed96f368035f82114a85aaedf5068f81e6daef4430d4e4a1b30703278cb3f72f370108e78649706da8003ea913ad4586ba821e313aabc5fb4abf57aeaa53a641f8b9ef2c1153efa20916d3a1ede4580e20c93b50dce1bfb4d08ac6c4f1e7a0e1a860b809700cc42e2baa77bd691757c7766a61d535e2710d2a61f25dbde1c08fd373400b733a7734f580c53e3460ea4ec5dbd7a628b237032888f665758c38a17380c4f29f848355fab6db832e48f1c64ace6d227f783748da451d080a58bd4edceac5c1318c17c9780a3d7838c9977dae07a24f5414911c519a52659640d3ae703cb8ad7a8f3ed7b43e862608a4fd54e2218acf43b1b8c0d0eacf4e019c38ba7474ab4f614d3ee034b5907159a9a37c07f74381f66efaabb51af473a271361c6654cc60f3f992120f9072e466b0c0e99f95efd64c9b56d02a138c66f558efaf6e7118659bf14137eba0e72149992e88689db0177e099b3eba33c4ea14c74f0366ff699a45c80db076a16390d64b18168a03afdaa0e028aaf5e96d9dc9e300c2de01471dcc3aabefc758676895609fc53b7d49a3cf7db81d314f295955d3a19dcf279fc8ced5c4e101df8e0d4c40de7fff3a1eb6811bec0c88e0daf9306547ec320acbd1b2221ea016a4c21de0d6729174fcd2939ea354f16da58f69a911cccc60bc9189d4a98991b20a3279aa560971549f8406d7e31bd393730b7cc2837b228144876b8327f4bd13c59f46ebb23acc80f3763decc027542f9b939331baecc47fb979e8044ed740d5c3202df98c46b387da579373a9e454260d96e6c6f40f8c080506a08c891ab9be829b309292e8d064297ff9aa1c1360a3821317666bc8ae7316e12642836e17e344c063ad9c5686bd6dbe41bf87f2987cbd75c0ac83ce63ea7241f93e413b78eb69278a062b99dd6dbd5e76a77f47eec2a024adc31f50a2c76049f93bca73caf5f4956dca7f52e758299589a1b985008ba07d0691e6fc6dd430dcb099b0549d3ac09a941f89f5f5f6e9e45bac41c197229c757d1d56d3515e054074fdab808377b68cc1a2d5b115411df06a8e3a0c8191c2b078d3ec29d1e17c2ee657e7ee63fd9bb120aa97e5fdf1b6b01b5026007d7e65934280b43164a9cc408281d2e91c330f49aee15d5e5b2db0d579e897f80d1cccbad5014cde2e1987e3b5766a926f875457088ceb508a59464632a798a47c3a2a2dd15f7558f26b7c750405f90ce2211dbefab598da23da68f00820eed189eed8ce73ae9845ff79be89e3f42228d53defbe2fbb8de0df315e6d96632c81f6f455ef87e0d2079f6aebab3f5b318e178157d5ae0de7729ddfaf8a17c1536ea9f05bcfd01d7d8992cc7ae7be182c8c7c6529f381615ceb8fc4cd39e3630445a65575159727e56bade8c331b9579b42f9c92197a239969825ff6d7bbc1afc517efe8fb48b792e823b2c2a34507b137d8d92675ba19ca752fc102c652536755411f40b2b135daee04bcc34acbb428541ac894e52d02b29b5b33ebb46ff4a499b1a5a143181f8b143ae0f0f7d47666c0ba7c058477c1e86d030a384c1a4eb670aa4e1a979cae06b60f3f53bd69d7cabd28554adb61666e1722e17b32cac684ce514b8b8f497899a27423c97efe80d8d0c157b2d34ae04d632cd7a5cafdf3ca06be5db51b478dcaafa0dc9cd0c3da2cb98af35361f8cf659fd73af41f536c8e50f940908507ffd8e99733831e1858eb6046348cc85b1067efcacbb157da93ea757af2b9bba0c22178ce1001a57483e30774bfabe3116225613eb5291936c48b2d0b5273c5be7863b677c628dc3636da5ed2fc4acca2da553b2bd0f2cd4ebdbfae4b5782c2a9b0f62249d1c1fa04b5b641aec8faf451a1f342a430a0b2104064dff17c85cc7ad8020cde6bcf3fc4d414c2a2e98d468a02f4f4a060223222817cf2013e24404c441e448b6e88cb8fb7420281aa007cf980cb7bbe1d9bd49f3e832f5ef6e8af20b1ffc9d63d68862ad5582a23b2a568daee6a3aa368e441a477e275d917d53db06285c56864d9e29ca08e34ec9ddba84b4b02fe11148fa01471cfef24f37f697bb9ea0f81449bb6f81f3c860a08efaf658c5bbf049691e08f5be510d88f3ca1ca6fffa4cf0890731e865811f21d2daee7ea57ae7cde041963091d7a8ea7d47ac649a72a9d1e1db6d428acf9de800bce90bd097391d281ff0d18f6faf4fd7e1f47411da694f1ae6f38e68a561a7d7a9e8bd7dcbec874e5946c63b5dcc707db8a32a7e9d6e6a642430402304a7acc5b4cfc4a7981f2187f7988b78601d9e45f767f80c7af2bc102d8174319ed108745f3ab7bcaeb6d5e8ca7d1c466d214871ebccfb1386d4e5e7a30be8b85a447273f6f14f9d6c2f3931810bfffb1648514b245f25ae4b1c2ae3df9dfdfea596ba3784e937f4ca2d1cbbfe09111b753d55c22149dd41efd2807c349f80f18aced772b3178f1c6ae4c03d36319384c8bcd061e881df41114d5b26d4145514d52800fcae2e72eed53a86164a69b72bb48e124916e3648d99813a7ae05f446373a1a582d21426c3533f34503c70982a15fbd9602ac997f27588d34ad16821e6f11b4903635099c2ab02bfd6dabca6334560bc6e0ead7b2205f483b0b032ffdc8af9332978ad9657917897e8666b1835938553188280dcaa2c704a5eef827209a1089c99c8869f23db2c102589963a70e85fb0f8ce503a8b9f5e0aceb65acac58acafe6d82d3320a5b828b49f9f21061ef74dea4262fed180b5f88dd8d8c1794c19e01e3ea26bd6c31f7befccbaa422138809ebda613d145ea5ad67008a794db89460face27a1b0b715be9b21abb14128d7c7aab6cf2c646ce2557f692c0d063a265e3e8e91f0ae9e4a8615fffd8c2d84d8585e1927bc50218381a8df3e976e73bf8bb3932598c8d89d67b70e030e0c6ad710a3d79e449ea1470"""), - TestUtils.hexDecode(""" -78A2B7A4C8441C36E0A9831F65D41773FE6B81B3FA6259A320AB03D460D7E38F4AAB2B93C6142FB0F9584E4D47074670B07F3CC4513675A4367EB8F7F4168F2EF7CA26AC45C8F23B2FD3E970068F21D9A3F7EAF005DB5A7157715CB94F5E83E3C955DD68E0EA689B6F419FACA7CD159237085678FA5883D5330796AD64627CCE7F913D1C2259E1F970E44988B08E78ED1EC01CCC2D0274067100C1C1E3D880B9CA4F3A1FBB345354D4837A6E5FF4D5F5C87985E51C471EB9B0F85075ADB57DEB53A87D85834167A4A538134CBC24FEC2756F7760C3D46248D5BD6022D8F88CE7D037935DB74A6440DA49B97E8FF376101B296E3A9D4D22E70634CFE88142EE5FB6A33F323519EBE3A915AEE5BB687DA4A5E264C657438B0F6AC977A22D0E56882F74E70D981CF37FF0C57D285D8CB07ED7FDF6D7CB1DD39EB0D84F2999DBA9273E0B716CE754A29CBA2FE32BE13BE8B9F2117DD7359494A0E0CE623AB9ADAFD3F15F644545A39055D42C6C5FBDB46D121308D649AF9B86A350B70F77A977C8268FA1E04F4EFBC2C95A2D72BC37E558F0460BB281D33F75D2AEB240086CEB8246E8A44416A5B31EC58AAA88246D355591BF7C622CBEB1CAD3B785026CC04C73E352DFF28D77186CA93870339E132D57B11F0154E0CED426DB31BB2E125C5635BD489B52C5E77593145D3100E48CFC8FE6975FC3F60ABC7FA4A4D9030A2CCADA3854BF9AA213EF11E2F85E9D4E79CBB434C65ADC378F8A7DE33E66B4F8588B73FA7F79AF4130554173975280879FBE0A59D25B969FC45AB20401CBF85463A83578E63D0C8324878F5CFAA191428E7EAE37BB17A18D0459378CFDD4C8C0B23B1429950F054DF5C67174E99AF9FCE6B0D8C98BAA9078D2CA87EB8A014995FB79F7F49D78F2674839E14C8F74588B45C28E4769C439A930B2A187764D87D71200E841263EBF74F7428EC554C12A7352FD3912D95C96E4BB1D325DECEAA9D6FE360DBAE7AB897ED467A300A8F4C6630F8E721F24860D1FBBCFEDAFBD94DC9B4237B91B243A01C41D5E98E67B52B4A8CDF0F1C985EC0EB85131F5E970A6DD6D4E1F525D9D94530157F70B333F5E50B1B95D569A012ABA959456AF773B59BC2891D745CC036D06238AF3F34081A20F00A831422CCF6E4593EB56CAA3B7DDF44B388CD54E5EF9E3FB8A260847BEA5EB5FF9665530A4F4B56726A4C5E669904A933AB1E56C020967FE61E72185D56B38B03D343302712FFC1DF9D857C6F744E3ABABDEB3F65628932D69C65FA112AE3F7D6ABD2B4C3CF572EDA73C959637D0C5C188343415E9A26E698170F8E31CA45A8E6E8E96BD066BDFDFF49C98C491149D61AA7C456D3DAE0C017A32B81CD5668A400127ABD4316F3DCEA171C3F6A3E99B398CCD4AA7E45BB51963C82C43398050B8923CAE2D4E2A2FF5232AC8F2C770C9A775F29C261E1C7DAF54F9FF606560F869638B666C90112B29F469C3620B0912622892A432EAB443F8A93E3E7953235EE78CD3FCDAD3F1391A2487DA621526EE92735284C347853D5F65395ECA2B50B0CFCBD988F99C86B5AC56ECB82813A93208096ACA04F22AC015CD9860889E9006DDAFEE0B472FF7FC3D5677EE089B0AF7C6C2FD5A322D60BED621B8F099C30C2344F453320B6FF405639CF764B101E1CDBD312495C2D4FB30E2FA7B3C345B9935BB28EFEA69C829EB57BF2E2E5E42B8515DED4C32F9C84C33DEBDFB345A4BC592CA56A769533FBA0A631D5D0E07DAEEDD2FD588FAEE648B6391422924D28D08B4CE36084C20E827E6E73A97852BDD7508E1CDC1630094C9D3A2C8517A25A244FBA388EC7DE2CFABF139888EB7372E2BE3BC4FC71788AC3CBBB3EA1CCBD9616E76F2CEB356C13257A8E5490F3C4F7DBEBF942BDB941937C956DFADAF3A78903B49C5DE34F5EDBF0E98E3E04E51021B686325955C14AA335427C4A116CFCB3B89349B1258B8E0E354F13F86C86E5E8EF8F57D7B7501C5D75B1D9615D942B04E1FAC4EACE0FA10E6DE9B9721EB0651EB3C9DE4C61EEAE7D7E17C0D699EBF7EEB122B8C1A599A2CDCBB9B665DD9A653698735D5572EC379ACC6A8470CD7CC8245F871C83E6FD92111F5128A9797AE802889E4362104775CDB69FCF37AAC22EE4532FD0B5ACFDC4DBD56D9CE8B9EE2A8B923F42FC512B54204CB971BBC9677EBC49D287A3F68A31DB8AA49D6477B287285B88AF298E68C6EAC3C73FDEC94F7062D204AB310686144168C155281627F78C883AFB49DA50C0F5139E2A0ACB9A9CEFCCA39C6F4F0F5356D2898A4F5DEA78FDD20B79662F4D066E73EA4069DCE6CAE300B3028F15C98801912A86E0CF34DF53F7F6E1868DAD92DF22A238C710F471596A49843D3E60E4C381F713C21C3910ACB1515E5E30252C94F040F00A9D1A08A4FCA329DFE190B5464521BBAA32932022BCC5E119A96DFC941965CDF3B739F53DA156553C6BCD72927B07CC3CC945FABE44B7348257A9FB41EF85AD5423304E016E74E03D5164D9F15838C3A4BFDC29C6B9F134054B53B29183A6A145CECACB3EAC7C18E31CB4BF78BC8FE60A3B8EF880CB6C1EFE7EFA8D77580CE200ED96713E32FF23B86CF532D8EFA2FFC8DB1A9E65A78EDC30090E3DC02475D84F8D9F2BBC48B114C9E4A01FA79C17FCACCAB1FD304C7F901942B9EF57C918588C9CCEF0DC5FCA7AC84ADAD547982EF9E855F6E88D02751E8E7B8B76C3796F94C9F7B7C6860042A3A33EFFA55AFE1B94C97D68B76DD240346355012F036DA9C7E025C3633CE867510D54CACD36D8638FAA8EE47D315FCA9D5AE4BEFD6150086DFC368DCE8DC623ADEAAA07287F9B291252628F1BDBA5FE6DE45129509651FB048D3A686FFAC5F2299AB0133FCDBEEE8445555F5C649598649678847FFFCE6E0DD9C4E75E2F6E77B1CEE3A1740A94E678C1191EF46FC4D9648887DE6277B11D4C242DC4A427AFAD5459BF213E0A20EC74EB0C210D0A922B9E690EFDCCC2C160E011AB94F709C174F22629969B6332738654A133E8A13EF7C914CE75ACA1C37DE05A84708DA741161EE4D23C025B405CDEBBAF9040A1CB7492294C381FD069C4622BE1EBB0113F25F4E1D5A415C121055CDE5616662599C2364481BCDD35F7E498E80D2350AD3B34C205C5EA73F1B923E6197E07C502BC6F4F4288EB46013BBACC49A5DEE5071ECAE62B192294E904BF3FD7BE08F0C43E3EC6E23A7F68115FEB285AD388A0F8FB94126EDC0331834179C1F10CA5EC54159FC256D7E0AB3129B22E5AA5D662C6A03C7D9A6D066400859EC2D5B091C37E35DE31365F5125793E7F653013C722045F7292C014123246D611A7FD59E9B09EF24221C7EAB249330C91BC9F4D3A223D9C2CBF7130C5C057961BE89894221AFB1EB27A4604BE310EE3C395E479D852CEBA4C2F74D4DF416C8836861BC13D0692863667AFF8EC89BB9194407222589E1C27B9D59AC49131765273228E79C2933445B83D07E48A789FD6E406064593EFBAC4FFEE64614C5AB34E5C2A717C50AFA79A96161203531C161E46D71F447FD28CE4AEEF197A3DCA6BCA306AF09086D6BDF35A861820C469A40958923BA824F3A95CCAF8531E930210BE46D66CF7156EA0728F3448292F47ECF20DAC7C5E78A2A0AD5215FF37594D37A2AF4778B15BB1B5C4E0A44AD5910B62CA3FAC5BCAA4CFF5BF97C8B8CB239126CA09E92492121C9E6977111E6E5248661AD122C87007318BD3D98ADDFA1B2CD60F12AD1E072643FCF82C630C2093CF4A75B2D3F809A0496727E04AD60F14CADC7331B23D9CBE28EEC92C68C97E597C2EBF99F2B"""), - TestUtils.hexDecode(""" -b9e56f9dfe73c5da4ec32b02af5fddebd5c84e216deae6a4f8611a876fa4993b9b333360ee00007dbb16bdacae8af597cc2d3a82359d8dca6582fbf9546b31867497b6cdf6f42ed3b09cfd094672218c40a24c8905ea468ba91c02c677a45abf5aa0421bf5bd398fad978fddc4634f6e9d36a03cb3d6eb64ee2c35f85481b1c4bed1b268de1483ddb4896a89bd9853c8f5beaee8b760c8202d17af8012a859f30c3023507d6bd8e41476174c2fb24fb1c944fc525b35c6e81d090c69713836e236b12106e02792ad51000aac32cea27d42c197e88f500ad336bc6feb4b79dbbd29a90c6e0f30011821357d111ec1cbb395212cad14b339a40fd9fce06bea1397369188c0d79e112f8c453605aaa3e28afb24730578eb8bc738d1c8e699fdf40438a16100e30d023b5d5be050a934d84d735a5650e2f599a52d36d1f9bdd91e46316bd62e774bcbeecdc7f43a89fa59241c12d2788ffa8e7277707c7df292da5141167d130aff17369c49d978add54af557dab19e746391c9f67157a58b4efc7463ac0615368006fb12c3554ecf35902e5752dfd7c34c97846547c3da9020ecd665487607c084ce909c2b7719acd1c3768ab6464c07c17e1329608afffe63a4ca07f6c9ceb74605c02772615de81364524121f8ffae29360d69f8900e5e9fb628e9ab0af8200fecff1ba1bd01fb6f1470a3771ef57d9b8e8103b3c2201d233de6e6602d490ba822b8eb4ec515c46b7b7dd0bf95cb7eed44573cfe11c168217e32961180d74e4f10463a5f38404540afbb48b21c878f1e7cecc13d664b03fddd6a33bb4d8c89023bc54602acc1cc434f5886906b5de13e89b5a414ba0f75d8253bbe031f2d82863e4e2f85f882a8a64ccc90a663ec9b6abd7edf2e8992f9aecb12a24acb52e0b05dee0803f521f833d0c0f238b06dd530c14bbe9a64a38198ce98a91f80358e6af37fa804710f043e7fb8cb5562f0c093d40c57f1b2c476520ab60782702d79423c64c874ea0ea0f4d9bbcf029b54b11bd114d50ffd80f38b21b4caeb54e9b83e0fd4551b7d56aa89ff0ea546433abc7e2b71a1a73897c803709a85b9f2c45996243445b089d8b3a75fce6decd0c42d622b52dedae2dbcc83181fa23a9d7b813127d58457f03b5e0cf4326188ed9bb894b9d468044897ed7397bfb6634808687937c8dc0d9883d9926d1cd63e0755ab868ab1de5a6d8cef72f72ce4e183d626605d6ceb6da8bb821161f3ad12eb124a1f09789b67f71a7b5819c3a285b7a8027d1cbef580779444dec21bf6509f27e7286c9d8274106cd3ad0baec6fc6f40fa3bd30a96c27d48280b8f051ce1679ea89a4981d270cf34eec5ca1ac399c422ff114232e68601d328f4a4c23ad3d52843c963b21f106f82eb38a379442b0ac389c59992c4326c9a54573b54ccdf1358389346df8c5d8c4064dd216f1d5e8f5ffe31205da0724de69187349a54b916fba25bbc4fc9b4518c57d5b715bbbfad14e50f8f48c81baa2246712b02cbc6f83cfb0e033ea90734495c9f82d185038a843a1f2d0a40666168a4df0b8e7c08973f64c4af66006109fe69a016242709877801e73319e1b2409825f9d827fccf2001b4dd0a4f455a92a58d13886f5ce9efe226dce7f3b4e817fb4f2185eb328c3b20192cb01901d5563b83fd7e13d0fbc3cde890cfccf91abfcf6c93a8c9ff31bfbe12a592e6337a0451983fedeecb6ed9ce67b6a3628fe15d9d6e8281097f8200fbd8742eb1138d3e6c70c1ed95c18d156bd9bb879610c28e5087097dd4a40a102a400b7ccea6babd3c419436024052a8a3c6c4233627d967a91bf700e10687a30316b67379fed8f4d208e27cd811cd27021abe8a295245f865655d2956d60d8564902fac029b65a337aabe99073b70162027995799552e779aca9ae9de29a458d6eec2f8d2fee0102786381b4ebe8707bcf9400c0241b83a4724f81e776b996c112226b8c7e1f5c1d090e9fa9b88c26445367935ff26c8d3c08a2347851a8f40b677b6fc5503a48f99782bf182a177fff9f28b5f2224b77454b545f018a131f8a9df7c61f35ac74edd7481a4bc18492cde936d5cefe03c96fe2f60be3edbe53d7b5d3f8b883523ac6235fb777f1d7a41906dbaa1727d1defeb67504a482beb8ac2ccd9261aeb746f422b5e9a11cc21ebd22dbea164c46e59b09bfb5213576955089ade4ba711d4f03646ae86df0c5495e0b5b5356d55628f40089d4d78ee33ba6f0f4080aae73fb20b47e979ad7dafda20c69925ce818ae62d2a534727d146d8bff6276eb02a52b2d56712da8cba1c0b48ed1f3e180d1bb4c365d6f14946b5f76147aeae4c55fd8be9d11b4633659df5a6a2e6dbcb56d32c7bbb88fd102e8515e959f322db8b6ddb21bad4a5c345d43f1b9a244a24578c75c626dbafc3f10e65e023783394a8357a6d5e005962af2e2f8fe8757a7cdc45823b50a0bcbbfcc6a46809d46ad639e918c97d1f038d7a3d9d87fb67ca95023d40793f96aa31c4bd3431d997746d305579495e41fd4d5b08cba5176924025bcdde3e36ff0c7b04b1b157021522d76e61ac37cd4fd8afb8c86609afd86a521f42b6e1892cf64cf278b02a7df422953e45c49cd07b9be6a0694e977d8e38b582c353442e850d488e26403f42fc2b533247eece1bf8dcc3808592ca51e100e71b50ea0714652f15c308b59d2b5936168acd227cf1a069e607fb6fe0fef48d582811106aaa4eb93ac836466319ba1597dd6a21ee2221bb0a6c068aca48b10a71ed42814a5273347e176c860845445c6f3e8dfd85ec2da37cb08fb2fba67bca6ecc5616e937e5f24464e22e4a699f27ca0aa321162bc5dcb799d4eba8f9725f9240dd2a10e1057e625f286bb999db6bad91f53c7abf54ef8e8a7741d5528f1adcff8783e69c535d79f279cd046373a012da01a3530d65c5aa3d0772e773dc7e692d0b8e17892e4808a24188c0bd48dea755b98a92ed4d8bc9046c81c9bd9800d8ebb100baa447a3432c4de07a68f666177230109c733be367d73c724a118fb665c858417512d91e993d83047622a9f5594a9e91467608b62c27bc07988be98187ee0ecaa7120d0ed54531fd9ccb17329b033b1b9c771c32a2bf99be223271c91feafc475656cdf78b4acd5226236cf50e9a4e79d7b4b4d9cfd14622a2638fd2c634acd4ee0b91977802ba013a98fffe5d6744d75d1a20a3cf3c851387d08c79d9b6b4dd418965eaff722b926c02f1a06563f0d963a2e6e99f10228152fd2a6bdd6468fe97955d4e81d0ad1f0ee301b1fe33c6935c3f5f8d4f7cef773550d32825b7ff05867c76e9797c71aafe5fd6da4767bf4f8c1a62ccf588521157c252c6d5431c5d4b1f15fe45ca0780989a9e99b7e1ef1d73cab9906a27f7d92609388d11b6381a9c21da36cd5245b2c9193dbc1c74e7967ef694a0e928720646b90a296dcedb5de5d90541641220e03e2abde8c2cec28ee3e7b04ef380dc913ba595c7c3352a5edde20b85c2d2a7525035e5f6db59d82a01768c7c1be0c57ca4eb389d958e0c96443e60fc6ff57a1e37c3bd0571215097fe26a87b835da2ea03c83fdf607ce72e5c76ec4a89e1378cc042bd70effa1e823f2129feb64e5ed7ed216c0d37fdf8d42a5320dcefecdeb28e99ec636f01973df6610767341da3233f1d2d50a7d922e93b14dd5d713049da206d3f31422f9f8d88014aa6091820525b50d1ba5e1f9d33f084bd2b5b65210c37f352cac249bfdd0c9d38d4d62e6c2bbe3541bd692721458b3743f902ca8ef6a150e8538d9dc348b704475d45ca3480bafe55265c578f3cdac8c0b0e281a6827687f391775f05979791d3e673b2cfb1bea5dcbb1cebec43a32b34b2e3ad97493c179abec83d02a249d52dd10edec00299704f0daf869d28c2bd29597215aced1e184d5e587caba773461499b46ed8c7a036ccb433982cb89af1a7e243a3466b1b2a9243770e427feee9dd64a96a3a8b526bd2df6ce6ce3425a59b7147c86997804cb109f862df5151e94a734020be056df7769e3f164de280bb45d7a5c43da8b8dccc48d4b4bd3400f31aa5c04a76e863fcf9c7d7e7eb04f5d769aa3cce83251a40e3e32f0d437ea9a279fdc21b4331286441faf0e0e18abcf11318b127daab6c8e2a8c2d67aebd6fac6139e5cf996ba502080dee6cb6fa55aed98f8e28211ee175702e9a16a2cdee3d08a7150881ba3b44f785ab768cc857bedecc1ab8f006a1377043f731ad801b23e6f18d6404c58c0d738cf5fad7cfa87cfe6446eceacf44ca811e1a48fdeefd940324c904fccfaf2a36b2bbb2c2383fb8c995051881a7e9d96327ee92ac43832f98932997069b21bb0868403c6c586f986949a43a42fc982d33b5039acff3d3dedd48ef05e61afbecc2d113de784925a101552d5084f05720230b6fcc357b63a72588317af5fbadeb229fd1221c5bc5f7a53efce19ac146d677027a87e0d49876e12830b43392f1f68069d5702699ea0321ac7ea78c18e64af520c333a8f3f591a1835d4b34b428abe29d1f0377c9305e0aca4f903e5127a397149d4be75369cd42135c7415d0298610572c6b95cffec5b0ae2fff70de6e12386db711ec9b676ec483be1cea8ddfa0df57bc60d2c8a76fc87d273c6ae4b724c4d8d3dfaaa11ae2da40f7990f8591adf689cf800ceda9ef2c8faa96de3290a3bedb2b73350846de4b754d3f7ef20c4defed3d9cb5afeaa6e1d686a3d16c4f1b2e65ed51b505dc3fcad64aea1c491338c4a33292088b60bfe491e1e6ff0314252cdd6767e983b53cd660dcaa4fe83bf0433edbc28b53a5efb2f5e6793ab1177f29be6cbe572619c7d191117a7bc4dad806dc102aff25067eb47a5bbb1d492f80d37c5968c2e40e9d600e7910ec77a0bafd7d8fd938ec3e0086d84926a75f9908392764c8dd8a76439f0adc99ffeb7af9d0966bad2b0a924184a5e9415c1abf791e15c700a69c0e7a62a854886797fa0d5c7a42519a6c887a23165808a608d9bc625f7775fe7635b537b5a35eb94eb5e81fd9a7c0b1c74b27d0af81938714761081411cb484ba7387c6c233bf7ce09091ab8673a3f10aac3f126cbb090f55336caabbe31d05695185635fc85d2ac59ed0066e51b023350083b2b2408ba874b19b98bd360c12885d64634d3c8c2f19f0feda4bcab389038ace498af6e2824c101fe5b069f6679044aed84ca5dd4dc2817b3c3e6fcd4e2f1874f6011ad05fe9e6a5b474b6c082e7ce64f3ec5d276074af695b6d3ec3b158a99d6de3f4237592abaf05a460ed2437e66a78fbabb0bacf03aecf9b96b3ea916d96db12d7cc6f8bbee54183459748a9c8837824d5f7c6015b564b146c255cbdf16ca894186566185574273344098aa03acdfcb8679387ed2c98dbacb6f2e6150306ea35f1bc05694110d83394fc1a7b4b93557a969131b70890933c530204ffc2371cdfddb7c6342a06d87c2229473654efb2b53f0826a349ee93d90fc4d4ad3e7e3ff8c16d74ebff6faea4b07dd5e88999bacdb1b51d8a9d9c0b5e5276153ac0483b96ca76dda17b931c526c7b5858bfa793c166bb680a44a0c0c66148f81177d8e9bcfdbfb64346c9179bf45390ac550db7af5d9a9b43bcc168ad29546e0b168cf9a5b44747a36b9c4e1f630c832883f9e6d10e2f89fc436de0c59f3b8e23ee0c156cc395de1c135a9de0e24568cac9c2911b21a0a9cff405a8ac222a3ffdc0d9ffc47aff2a3e89ddfdc6a8cf60cf28b3c7cae78b6bebea7bff5a8a47a3b707f24b8b6c4441718ef88108ccc26034ece28f80517991530273a5888eb1e36352d45e917b0283534830e914c5f083704e87e3c4c4f2205d99e1480d3ccc44f66a5dfb0607ec052a5a114c73d7bace17576b9345149325614c0076d7f044ab3f34482091be999a269a266f86a95d11baeb907e636f85fda7439cbe8d31839816ad20fa2fbac9b9ed2414a28d7e70cbcfa80f8e4e059ed003add7553056f7b94cdb4459f3ac54cc2c003fe60d6a44a7fb6fd0520c50f5c226a2bdae8b6e8eb7f18f94ee1b2692675f1b52c8da3141e5f859f7468b88e25a7d556fe1598137e893ba1c07ddd1af840e7f568db4b139f1d9f791451f76261f3948ba69354b16187cb77996848b629fade50a4d33e5760673e7b7466633f5426b17157e7165933de8547163903aa002df55a20a1a90a5c7c93c25bfb53f3f57e0045dbca341b9f14fbe2710532947e3e1bbf9d98a2f46bc526db5455189fd359f4a9c52dd5e5350650b010cc58b6ba0d5d11bebcd9b6e512d3c2faa728456b7053485f24fb351de898dae7893f08aa5509f808e6d0cf2b3bc46d3a9d3fb73633de694a0ec1d73dcd22e818b61558be653590663c3c66cf008ce3f74f0cdb241a9b54d59e426ec1a0436ed7e7fef471fc927432c09c8a65591531726723e0a46527cbd28527ca0bde9165860839dfa2e405b71728a8d96a1c3eaf516327895fd14476265777e828792a4b2f230638790afdc0312214448b1bac8000000000000000000000000000000050b111d222e343c""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -846d5071be9f3c8a2a99cb9490b9aa8c794e568b4c2da75439df54fb42f618280fc24c2b6d37d4a841f700c29115645a056aacd102a508bf68446b00ca392f0da08bd805296edfb26d8b885fbeb00743923c30b75f74a6af4be86b02e83c7a5fac80ec7fff129e338d766a4c75f8d35a18819b860306c6d44ddf230cb26718e942308810322d90263120890504422a5890242004850b3648c9465090b06053a40d48c48483920009a23124c20921307262103201a4304c248d520231e24630da262dda382962446d21484d8132885aa8405c326001c74104004684a86da3c41141b60c82002894184011114d51983019234118b3001c356994282261a688d83450121608033705001506220746cb467262a46c12212410478ec130710106725a1640d3482ea3a289c9a40d5b340c484426c3980443b24444124092c290544251c924300c1705cc06849bb26914234dc90611948669934092814421c9c0019918861cc5618a802ca0922c5aa04463808822156409b69082c02cda2606428261e3426491c21113157221196ad2067091164adc3085c49091500440200611d404121a862d041672e1b4052101320129611b991064880c51c281531408d0c80c2344010c45511c126921c171db820040108a9c48620303299b060a01078e0820919b304cd1a2054ac2286240865900641417411a836943a46d00473114424092c88140044a13a951c0264801058c24b80d9246109294684928241ca3289a9209c4389259c6908a3652da089100390458c290d0129160846184a4856120021195891b941150a209d4140194402e94102153329108032c830022539004230386c816254ac04588b81094403299a2681a3672d04240a20285482864ca20100135520bc36410176c04c02d81985114100a03c370cc30041b421154b60903a4405116891aa0405b044a42a63099208c10074503962882868508273003a4110c4431cc846c132570611448a326621b206ecb4664420228a12290991646a282811b95319c122451b8319c46319842284c284cc0b0210c990991002da1a86958348d22168114318a1c8691a4240a24256a50089104284ad236019008045348800cb58c51166618c689a2226419094a1a4385c3c44dc3b82813130a04c7290ac74124894194c86943b86808a30c4ca4299b243211b9880c9228804449099431c2a840189630d8368d54a64c21498c04b82c03174acc063243466899320a51866043284c00461124246662a48dda044c132985a1264e18b044182188834009c4a8500321469012910848444a1669400845c4306d81222c19283110a6059a9069d0a88de1340cdcb664020146ca2286e132911b1702cb167222a650809601143531a1a600d2242801845198368501062e0b0105e3008822b7850235414434891b333022374a800885c8142554368a9020055a442682c244c8241100262e0114648a064ecb8811d38205a008401c348d94a06900386022424c1240020ca8699440821a140083326ac0284622c3501bb740a100505b9069e2040409924d19436a43165224174d9bc0904802055aa20489b42d9308911248298210500a432d13326a9b341224246e828604022862143184d4b281502689dcc8009b02700bc344a4840120436583b23108134a1021680037255b207013a20882324823414ce04240598481e4346902198da4440c60b0515b2431d82825634808829268d0044c638631cb4630244021421260848288d200024aa0218c242a0a022d82026c9a144c9396914ca88823143222a5655a920c4a24319b324c19c60023a341ca96611c112920408e54066c21260521918902160d4996510ac590a0328d9210259b94441ba69009884509156dc100509938091b33501c460c1c909152304424c440ca8205023426a3284802394e62000a8c04900c021220046ce1004418a06418a951a10645132546c03461c48431118524da166913934409474d81c04c49a660c8066d9214701a0291e1221283022e22b389ca022801a0019bc8450b446d13486609c28c192090100128e1b84c1129820404444234310c4428a04609420649d4c48dc914221c264e54164e641230611292e496094bb8840b098cc80808a21630809490a3104e22350044103040146809a9852317225a480c22120ca112645b1630128440543066193006210926e6c23cad48453c6e03f5c98d6c20db81181b02581e8410ab820fe98d518d35181824493ec940daad34d09bb90374b3763a57cb813ba4caa9b3696d793f6515dcaa31a1f58fb85c931c8ded334a20950bc9a82b3a6df9052970c09033ca0b5c3fb95410b28fcceddd5cc4ddaf0f313c5db025077856a4bb9d04b3459171c68b1e3f7a233ead36f40f1f20c8d8f4c478a5c73e26aac5e9aeb0aba57147031df73106b05ae4159a5e9ff514620a7919f360c3c94e4965e48d350f4492675d6c86bd5eec098895f657c036182f8e3ab3dd467a23fa4a5d6aa775319f86d38945a415bbd2ae6166fd619e5461560af8241c585beb7f15564d0503adaf4ad6b6242f698768b70f306d66487959ec26c3eb7d2bf074533ba3f99ea291b51d72fa15302c74c03c2ef2d58cd241bafcfdc081398bf85c6f9754f699d602bdcbd789d415631cbced0b54c35d19f79a71410c828d3840de9131b607000f1516420caf078dc85fcfd087c8047235c878440a07668996c149a5980974bbbf4dc32f82139900c5246e002d5a211c63e5c3d873dcc966bcbb48ca6bcfc8d8f54e3a7055f5efb3cd8af0b46b3dd5dc26d5b70d249e0073647f3ae84d835675e871c5222f317b5c243e3fce32017ca9a03891acd4c986898e174f80a9436be2d4b0a99ba4511f8ee21dbdf44689d085846f8d8c2ee48faf14d8cfe6cd7ceb6fa1bd61721492f1ba5ad52dec7b49dc9a23d939152e4042a0096c5556174da9a589a226b6f5dfe5448b73555b2110cdb09cca3edea2c7afb6f38c6432ad7c6a0405a41bb570f0570e5a056820b5dc16e80ff419ad7160b98a386a7427dbd4b1e26ad0839f542c5e71534b6c5285fa5f4b12f75ea94b9272eea21e163bea4c0651fd59b0c54262f70ee81303e3b3df93a8bfd1243f1a1b692110de4a5e2cc5e75dc201c491d8a1336f1e21edd5b9d20a59fbb89cd6d4715a04a0b923155ad110771c0ce326fa4c9e3d2e62e3baf9ddea1d3f0c2d0432b8073611058ca545dd387267bd3fae1ab362ecbb952625a9cb2038c7feb192aea08c6a92d141f06e888206330bfdfdb552ac5ebc6c2fb7ad2619fd1f149a93cad33615958e064f0eb89353b82cd26e4a34c518983e882f171d91aa75c62a6b4b318d732b063e8ab3862c97e40ffe20571f065901bea3e2d9e89c08e22a000b76b788cf5442add8495b63545d939a18de4e1b49821ead033c7479602b0c2388e3434209b00db520a7b16f22af9d3e5508d6d848aacf6b3055f82384e637a0981b4fdb68a61d1a845154a65c4287cf8da9159a2650bba6ebc853e2b6b32df16d1588d8f5b48732c6154efc55295cd8a5b765e35f88a9b4025156963aa7ff2e414af1305af3ab9aa9723881005ecb1188f36d21d2f7074c74f17c4c37eeb959a602362443c62e40d628a5c47682a4ca3346ad90a8499dd28d7d10f72872b7e0b73eb3041fc2de354bd3fcf962f0589a2859c8ff71b0146af27bb66d3757a6dc26ba7c5bb7eca491bee443c8d48d6df9f24d40e81fe168b545a34dc298271920fc97546f6f304c505fe43d6c8e75487c04640474e3943e34945f30f7ed533855c716c5ecfe6481167e50114b784ac3860fd606ae4e7fcf4b01f11f7b48523c81071e7c9c234a4eec5c329d83d38e82deb37f1f18dc7cab2241507795674f830e00681ed9cfb2765a6e81193be5a8cd5b832765eb814539f8522fd9b4802e26049aad26ec3c5feaf9203e65d5c4f544b8f214cc5831180fbc2c096499edc37ff51c44b3dbd826777596ef0da35bcb38daf077e2fb717910e5b68ca8a7c5e70c400c107a972ab3cd13694c5c21f7ff2e4293e5cd8278e37806a19c053947df531d843aae717dd2f5f7268e9b642900324993cccec5fea04db7778cfa203e6e9781daf9f53582f80c8ccfd5f0d32bb627a12585c98b57ecafaf7f00217dc99bc9a0148009e0fdcf9c2cacba1c1a7d3aaad3f6dc969f7363ebcba222fb3def7ab17d3a28dd4a16235e64bfd4843956faf04732c4b226f25fd831865b3f17cb1aea0fd409feac59ad100a37020d91f7176c8b6e11c3957c6b8835c4c0ef25280d321c8621e72100248bde7bb9c1b8d1eab666414aaf9a19ad34f97fb68e68f3b0e58d29cc01ab09b8b73ef51813427ae84662bbd753d6864f0902f02b1f2f52abcbc0d580d971d13feb60b949befc22889aaf7223b09b22883884ed491b527a6dd7c420d8990bff759ad5ba9dff47631abcda7396c75e3f420a295ce38a1d3109c85571a69fa5ef7488f21fcb02cc20765e09a9cc2928925affcfb997111da0fec5d5e3f540822afe153b1c55687f7b6463e690ef816160707effdf743de401494504d28c8706fa70aab284e235e6b576f84c9f8ef70f0cdcc1a21f091871f146c6dcbef0f90baed20096c1d94ebdd6ad568fb97fe122df75b80fc3180b76c25e9852e94ae7394cdec927ac17011d43959d0dd0c5cf4c8d3b7a69f2bd311ddd7cfa202d39524b087b10a7e6c970f3698c21c0a18d639a56ade76f22e192f3ba2a50e415df716a3436f82de8318ab7d82f3ed86e3e9138a53b82da653f768183d653352436df927ac92a5e21adfc3647d6a3ed7ba9e238f52b5510b31f61591d89b2cf468c9d1594589ad2e7922424fea97b04b012153bdaae7f0e5ac84f2277a822a0e509d0e5f05eee5b5454b76288537c348003a9ae12bf01a4d747bad04b3f25cc776edce8e0d96ce9cb6082d7ae639ccfae14872d76710a9559f478e876bf0c3e1081bc64881287441eb3b79eb2354cc8703802267d5fe37c68e9410fcef8072a73ab8b9fc2e8c088a1de7c6534a38d7ba422fe79966b4bf222d9387d01e83856a02b6d0a985b0c496941e78a9e6f49e27590105ec1390a0eacd09eb3c8b828dec970c9a060c7031693dfb8a3fc3b44756d780f3399b806a8b0a5802f553b6085916fe619490a8158dd8b0b4d02af33d9d831915b5245d41c0474c4113a053860c75e8b36d9f84d5e5341d8361efafa2b0acc8976d74a568443f70a87d00ff488437f5f76d15d3bda26ee3d271a5178e0baa0f2ccd2927fea5e351aad15f71da838d210bcbec73f70f084887f4e013af4bd0cfd44d775b0f02421dba1356e6c83bc88f1c917c5f4dcb8f637ae36e425062a0f7b5b4a31c5a16a366c8fbe1da0a2e5b6d83379db1e8d1cebd9749bbff7d66806c0982878bd9b54b29ff158d4a1f36f515f27322f9ac4119b88d723cd37a66901e4f45a64cf3272169f8dba8a57f83d1ab0762d3b7e679432572dbba5946f9014a803f8dc823781a72334933a10d59cdde09e1248ffdd493dde94f9b07e933ebc6732c0a84ce233127ffbd4e6d136adbcb45ee02beaa6c0952d364ee33a4a0724db751f99719d1d52195d78e363aaead6e2addd8b04c174c3aa5ebba2a2ea395a314d6b85be9f391e4d13c586ffc63f9f4532c003de1b6fd07a549cc3b72220ca39ca73fc447d0fba82c42948b42cef9e88762fa5d5f00d7c3f41789640f1a70f57a9f8313e0085af505272098630b0e6d7ffd601d887e48220f323acd9b6f6c71d49ae9d7d325424f94a7f537e775b8c6b3957a1feeeaa2c4977477b12752b21a219504f9c7cd030ea7475422c810049a9eaf9e2e838881d67aa8491f41334640f941ee966f370d0245b7d7c90b15107c9a2ca9b5cc4df050f57ad3b9ecc10f41b501f6041c52c1b2d82b65ed49f4cf69df483e62ecdb8d33c14d9736ab11e560b443a5704bb023a71a814bf3711562362af9b89babc229181ff804e5d0d0315b198939377574aff8054ad079e4ffc18d77c4b93071842a2907b0dd8f6d7c3910403b34848bb030b16e6e57ac801f2cddd7202cc99192f810dbd41428847a93b18c2a5cb72f1207a2caf341e9e175162575f3649cc2f64f7d86367b87177c7317f86af8d14eb411272feec8693cb1745c94a1850d726525b563b2625430e9545e6ebc5df8a7bc44c5d11ec4e7c8af86e12e0dbf9a6dfb23efa2f74f612cddf04d3e696fb0e15b606694bb5412472cc2f29cc9c2ad22f48d6c3f270fb94116278f6f6f37525752f942f71060d41622970dae6b7f2b355f619c509b62a17f61007495e1e33053fe776a3022b34710ad48e81eb1a7aee5c8acbcb9e97c9fc1469973fe5a0a5b119fdd39658a56e8397f358898c41e44638362829f5106557ab81b0504f9751a2d3dcf2da9a88869fc04278cdbd68e6e5c0c8135ffaa114f16c68245ecaa9a1a105fb5c9630579016b975fbde1d6a0567224da9c32b3e1b42f2bfbe4828d1c3c2bbcb3eaea5fbf19ea55d86a58948150bc0a8c126487adae8906432369d93412481501bf32b423d5db70cb3413b52bc5a586faf82622d5331d1e1138045849bc8e1eb9fd02d3e713bb9f7e2a2a25c5cbecaf7b2463b9f42d33d52e17521364178c046741a408265ff0c95a2a1a61fef9667b17225c90169e991a101eb71e428bbfe730a8b3fd83370e7436dac68a81e5c4c42e8474fde53fd98db57ef79bdd13721b6c7b4e8ff982729c14b04a653808ce18077bdf210bbfbb7fd07fc39b8919500da55c0ba13c21725c7edc69c3f4abcf07b047f63397f3afab2b1c4d5918bb6328c3b522eb19a83af43fdacee087955b734c45266eed1cdb112ff8612db42a2da0ccf3abb22f198fd38f234ace12e80c0dc3edcf3d98323d0cef04e91987c"""), - TestUtils.hexDecode(""" -B5CD00AE06396DEB95C9BE213BEA279AF0D10F1423B5A71854413E99F7216D9EAE76C8AB884545496559B14AC9A69801EE3FD2EEECCC557D7988F34B82D244461388C7D4EB16DAC3C0FCE0783321A1488DC16C3C688126754BB4C26308054545D2E46C6BEE26C25A7C3B701341A0323BEBFC50C718162B7FF3B6FAAE7156FE300F2219655D8D44DE89845393011A2B466233B907355467EC49C9F832044BDFCFCF722D6DE7946FA503861C80037549ECE8FFF95026CDA33C9000FACC334765A60456084A0614455C83E0D5D991F7ED43952B7A69F1E326D7BD33822CF1F286D85FAE78F0B8DE186368EB334CA56070122DEBBEB920C5547C46C1291E78AE48B72C7A39020A1A2E54E59A2E46606C99E652FADB39AAB25399B0830AE733FDFD973294B93F47C30D0824686C735E05FF51A95C1C76467A4BE6BA80C5182353BD510E8D4B60BD43436F7021B3F5980D1A769B2E3BF04E0C257EF577828B327E2AD85E0581787B9B7FE44D6B826BF8405D3D0BF8974D2B1C569006C7FC3D2891DAF38DAC36F64A256E337B660CA59D2B45F1B4AA1C0C72B78495FBCC9EE9CFFA4B5A101F973E3211E728040904B0B2515DA4B1CB3774EBEA1324EB6907324E733C7F17BEF6FAD0F6BCEC1F08F785DC6FFE02FFED5C0B7A631907196835EFFD0730FC8FE020B0545C920DD7B2D705F22D8D205804397F6FCC60386F4A576204949EF60DEAB269905707396CCCD8DA9B895270CB39839BFD3EE64149B0085B96FEDAAF8C738E449E585ADBA037BD560EAAE978A6ED61DF432B6A9C2E50C2EA33A8702A23E6848401F85E2C18C7C767DB15920C9B3B030728FD9511F8903DFC8572A3679F986CA1B684B3AAF489DCD93C622C6C4D475DD60F10C390873B09B5A352B6F5A104C90782E053F8121317EB8D1D4C0145E04E3B68446B69A0EF81097CC6BD0B756AF78963724D9C83C61B7B79647F0844867B605E2B60988D2D7AD07CD6BE2D8F904F0D269187C141AC67C9DCF9961BBFFDDF3BF34D9CC5781D1BEA348F49EA8FF7750F7F3E0624C16FAEFAF1D8B6A818AF5FC5C04E2504A0CF4C2DB54930EFA759A292A2AECA1EC3A08918513D95C44BD133657FF043318A17BE4A5DCAC54B87FF38869D017A4B14DEB60480AF1C5F19A9F87B94B8EFE0DF3F931CFADFFD7AA50AC86D9CAF6D434CC81E6ED123711E34B8295A446B554F6DD5350B44C614324D8727F1CE501743043DE6EA085DB5154AD8E30E114A02CDFC96BEB4F2718033B227CB8638BCF617C73BA4473851E62C8A287CC4F9C659190E60AEC468DE7EA8841E3CEF893F3DC79DDDD56B63102EAA5B2793711A0451EE1655C6768393F59CA6085866FB41541D9997C94BB56F6ED5D731585E7B25B1DC853830DE5DD75F66298BDBD2E505DCB3850F96CCE0D7274633234EE2FA1E2782DA3D6CD8F5DA2C3063A923DCB6A2F82614527CA2A88C1AF21025B88A08C3104C679175DE2CF00602B13E58FAC9376BECAE56A60A6A8F144F1C98C8FBDCDE6FBCA4ED13228FA77CBA5CE631BCDB368AD9219568777FB4397BB40485A9AB63E9E3FB343154108D8117CE25BEA30BC854A241745FC6C26AF0D64124AF10BE4BE01B8A3D842FD9CC4D805B2BE26F8B7BA0631443F48C7F74207F640B215E0DDC42B1954A1EAB2C68E63601DE3AE3EA54E16282BDED00FC7665A9E8B098BF034F5E950ECDC46CDD22210244F102E41E0930FDCB24AD6C72507E5AB6FCCD4D6B2A2703C358EC1B51AC87302A5F507BD01CA6B5FE04EA2A5322EDFAE8161965524C61956CD201C4BF2F01B54F008F5F4B6770D0622099CDBF94D6C41DAB4A5362D630B9BF9CE240ED08D698D1AABF29E60BA533697C3C830521314F13EECD95C7D2600E2A756AF19AD94D9EA39FEEF0E3EAB3EB401225C2E55B2F2A8D7D1A3AA77A38BF9BA31399F6E6458F3F21DE354BBECC2E29740FFF91FBB23E0F61D7E0698CBF82D439AFB018DC5F5011B7BE98993E8B655D83C666FC0CF84A532C7655365746FDB97874D62329B1EFDB0B0C8A46056A85B60E38AF8979FA4910D2D9CACC3B5C1E42049D04C44273953350E0F756081D2DF6429193768802577C381897BFE540BC036293643360C848A1AE388CD17781296A99AF0CF75F81D568D0648C8A15436BDCB16FD83287C6A54F88F2F75E6B28E1C5A3AC03501D6D723AC5EBF90517D194A596F7F95947CC169CFF2A65D2BC9B54CA6AA45BA9E901D4AAC81FFE9E62A479EEC5B3F9BFF24C69FF56EC52F1183B5AC48A5BAA90BF595990B6EBA5B1CB6D88511C7D0D165FDF2615351B0343918B966ED1CA0CEBF6956BD2CA599E18619E1A5930E47CAEA92B8E9647A0262A2B24E955040750E6C7B935982CB742EE756DB65B462F677AE09A7521B0D3A42C2E97890C47148618FA6089975F5D491F4D3F69EBCD54C2B53130698A1F4A47505194F675D68F2DDF5983B008E498AB4A25956CF724F5C1250D5F9C75F3DF9BAA696E300AA86FB4B9378EE18E79D015CDA55D6ABBF5B0BE819F9EE58B49656D3B112AD8FA6651A8905061A8E37760C3F2EBE6DA611BADD44268975B5000051BDF7158EE3DC200B47FBF8568C9F22719FBEFE5906444DE9300689BFA1AD167"""), - TestUtils.hexDecode(""" -fca242816e6b98578837b5592bcd66732c06ac3794932640ca3b71112407c8a4c0989723966ef76b5409a893b8c2981d6b72a1f5cd92d81c12b9cccfc75547f44c27a56431f324a4f73ce4f91da398fdbe6a97ce171f4483fd0c1cbab53fb80c41963798eb10dc422ea82719a0770ba82e1491512bc40d726b83b3cc1887b5648204b00e8231a654b4a796d7c1c0304e93579ae6ba4f0945afcc0812b86cb8872842ee8782ede142087a46dccc78275aa2e52f2e9344a81c4a0ee65d4a9b8ce1ad020ef6fd1e6cbdf8d5e56b1751e67be662b90fba01a983df891eb2eef4886a1da0b6bc0cedc4b44f33df8ad946b68e5389104b46e213690ebad5b50fef7dbf2aa6f51b125657e779d9718244aaeaa55ad0bbacdb76dc66973e331be8aa3e6a13dad7d227121e5fd1edffdaadc6bb667e40d49c1d95c6db663b4cf374a3b93e5f270139c28e98fee799a3ea015ceaafb881807058b199dcf0b447f46d263bd43d02cf232ad1c27c3ca8e0cfc1c07541aece1980c9240e77b9f134694be94bbf05eb6710797a2ea2436cd6c10b18a260bdef24530eafc2618d17f86922e91c9fefe7528de98bcfca9194e53affc13da5787124dfdaa0e95f3924fcf6fdbca78a61aed2b5125c6b94733eab6a215856185ab31106fb293d996c9a8e80f9bd1bb2287a88df24f7f127c371d5c8503622b3986206acd99395bed7633e5f73a918a45362d58c921362053a0d2133a1989516cbb8bc29dd2fdae2dbb94669a122e81ddeec46fd04ba600d149cd728285f2836a3023521ab1362736a8d33635a6fceaf6f9684af304a557225e4a80ca403583b637c4db7e9185df6bb77dbb3b09ff915400bca75a645a8ebe36b99948369cad683c56f0030f4f8b8f6610d20c7662f538c855bd1d08b719df8b34873c4dfed8046372063ef58800ee7abd99ba66b60098e0004395c2646ffb158411526dede3d9c9e1b481a2dc5298f27538c6ed535fd0e7374ebf2ebf214eb14bc3c674f61c1baddef4435344ddbb08d6fc8240ff5e41b817e9795670f399965cee0d8a4540b795580ceeea3a31c61c81e3613331f21b496e8dc833ff7494f50e81f0366718622602759d598f1831042a5779ffa9ada2a00c79b0419ecb05d3ceed113160653bb7db0d06a40fd272afcf7f20fa18dcef490387b84dff70e761dd1bbec5e1b25eb30fe2c4d18135b3c5f315da29a98855f81f9b1e01450557ce6fde5b2471dfc90da07207a6f6d181cd71e33af713c0dc353f7166bd6aa7b90f82eba2c03423144fd12883e80538de76f02a0e12cc65051b981eff9d25a36ff79b4c6c84ea537075886e9be23f700570e43e76e8d61f54b49a576a99a57b464f2be6dc8c993c78a1330ff3580138964a6cc2cd46006ee1a72a268ababe373646674dfb4bf33126fbb8f5dd24f4c79596c783fc88b393a75355ccaaaf698a45d678b01f175bb31bf7d28bd44a766a60dd8d2510f55bed7fed53f6718578fde622c49d17fa64926be1a084dbdff206c025ff726ddd2adeea11a021680f3e75b865bc364dd7d752d3b62b7b240838c5645f5338326897e751e968fca1b99c0baec1c9fb227d6f1fe61abddbe26613e5abdf6bac54d658b22cbf8cd498114019f712027aac6e7b1fab7016aa96ff61bde12a44d540e33c30bcec417f11fec1a0536f61eeba565d4faf3b624eb1205143e3b6e6d22b8a0ab3767739206a89eab990bef3f3d763a816cba5aba2b2d8390235a197362382c2487d80f9f47f0714206b1aa9f40840098c6f94d920fe21950274f7ca9d22a506a76a328cb28a50ba569909897b15ac2964a111ce48ffe137d86c5aac313050e25f43b9c041c93dac0293a8694f76845a7a83b8e14db7fb2a724df1f4e64a772e6c3078e465565e1eacd56c0c4f13a3a90b53bcaa0451b44ee94be4d6d23707057b4eaa6879203ba81ea953090eb450408eb6a9dab8c5bca27c87cc302f286e703be7022044e0ac4559d4e861f4e31f8915831cc9b81dbe937c8b0abc02b61c57debcfd0f5f8ab3d7bf0b05a5eb7fb0bb587de8c2bdc41299e744db3c6f92aaae2008a14f965023f17ea55fb0a5ec6c884c478cb3a95722844dd823be55f15a363354634a1b3171e349ad6c69f1342bb3dcbf0cb44efaa6d06932e064311057a97fccbb1430aff5509d0f34aa57a7cebcd5eb5e9fd373960065c79f52a414d16ce959c97c1fe0101e4bea038dc6b27ee847335073f62a91d1d74ebcdab4965e1cc501c07cf4a6050c406028f6250d24796fd4736144ff84616a63a2136fe4b8ac9652d95965659d55b67355f5de40f6f11e08fbfbc2ef005b3937204345e03c07e67803a8c378368a7cea377f53318bb140e0760bf79fae16f4132bbc88d8af335c07496fdff21e36ca375889ed56faf2622377126d399fd76ef9b2746e1ab666461a949c06727d1ed191e197418ab7574bfe292b92ca61e7972e4d0fbc6001dfc5438f95b54c9f226bda6968fe5e5df06e915fbb58c6123799f6c8624a40b18542c18cf82b89b606ba532584b1542f0b0684be46457fd6f295f0a3e79ab8634b8fd747d5bb87ac0b33902804f691c16874f881a3acc4b1f88183dfc3defe276968bf7f7ed53e59e2e5fc0db0f13dbc772286f6d83cbd47617bd067035c93259ba9daad2f229835f7c9ce8759109bd1db0e71b9d015c55ea94325cae586fb1b50f4792bc4c57569c83c26ba4cd7a809e799b5a45961ffa5387f91d9d653fe2cef5783312e12fb695a1b9d2004bf5d73819dfb406a7d3243613356b851370fa34bc32aec270984c77cb373cbf6c65d1774ef95539d4b4142d50f3cdfc9695e96cd1a0a3844ff8507ece66c2ea7bf27bdf020ea8fa95c6a7cd0dcf37a591f2cdf7a6d7a04de5a89583a094a53f68636bb57fc83968ceb47a53d37aa7099c76633e23b5eb1b828d2efa427fde9cfa24df7518886af10ed7734aa278bec197a60dd8279df60fd5012852167e9038ffd1388f6753af0b75800aec92ccdc0feb08684c28d51ad1ba8a14b33eb0a13ed08020f8416c9817a63dae74a2ad51bd9c9db0c187ba1df3deda995727ee0e8d78c9a3d70d2bbaf759fbde9226646a412500865e2391189e46a671f7a9b2281509c412e5ae2cd89ef17a42414fdaa90d12e39b07ed4744217e4a461a48aab8e427eb7cd1d07cae97886ca0f4b8d2c88c397c96436b0540aad3e6962c78914b3ad092b1a46cd1aea2cadf236c9d0d1e7669bb3035bf8354ccfe5ca70e7e6e6acea47396800a8407017d64c4199cf13155bdf44b06e01b92628836712d34e2ce4c8d635cdf1c3ce21b7a2ff1268c9ee9df0792b79d35e466242f25209bcda6f68f07d80db030e244c479c66cfe823220075e9c08c2f8406ef7a5600677f4a0673b0b5bac9d5e388dda323cf3e2d967cc0b3a705a456cd194c1833855af620952dfa2fd1f147d6a58ac35231377956e4b91ac100e3f9d8b966db4861ca45ccaccc6ea63b0d2d71d4367bfc0911e106ce7cd73f31887536754c880b54b5a6abcd3913c505c2145fbed44a23dd7b04280410cd648b59e7ae00b10099ce56a3d615f031f9091ff00c2248ce6cff217fac3158aef781b88603ce37e9aeb4efabafdd59f0a460859b1f1a1b4369043869a27cbde6a8914d1d3d88e440927af82083950eeb3bab126e9507c8baadc1fe98353f01022df09d8848142ccb7429a5b4a7669c1008d61ac50d6373b258f8afee8d830990853b9cd18b869544bff788f5cef93a9e3debae6afb138bce6ecdd9b071dffb5d629e0fc544bd909bb7bbeb3597d0a285e447eb49f7ddadb510dcad32807d3d0a571a731069e22aab4e730f50e295357813cd46ac3f34c4fe2d5029fc19a772f7e647cb18635fabe67f1588b18a7cd0ebcb6994cf4334316f6a538370887a0f009adf3348257fe9668b7d784ea64e8e9931fba22bf2f673b222196eb5df852ae2715b58cb9b737583c4b8c1003178093fc288736c246fa0357daa68e89150cf7876928b9525a264625991fc403b1b5edcf4f9a58a570925044c669a3f1960c06f35a21b826603086e7e889adae25db3eff02f990af85efb01e1bcfce2eb1520d2846c5de1ad3caa65c968dbcd8af5b925a13871f19524f1db6c914827c818d76b1e05df95ba322ed03061eab164cd501545d3b4ad2c4f9b5d7abe1dfd3d92a422a114ef56a4b2b47d31f5df38fa7e3853ba5b1c1e9e955dd4a294119c3c314fbe4ae14362a6522e34b7fd467d22aef1a31bc8bfda12025701df52ebe6fcc52c1fcfb8ff94d62d2a7b0f1b8db243391320e7fdcc0ec40576caedd0f327c5a0a950ddb2994fc389fa77e54f569217f4139b91e545432cb7ed0d11e1d27e9c4536a9012509d9043557051c01911393c592f36a4f162f131af522f978e940774aebc0b672fe88c590ea572f39dd5c87828d3d9d16e78b9433e54da904418c5ab6e8db7851f4807d4c93c60503ceecd837bc068aad6813206e382e84b6e64510f64f1346b9fad25c37d77be5292f1fd9d5463c640baa331ccd636e7485b752db11ebdebefab0cd9d8b9ae11f724439525661fbce8341badfc03ec2375536876a954a0c553e274027f9f53582bfb7d20520e1b8ea9322fe0abc9179711768bb2e78554eaa5b0be9023e6acd94f5eaa7b74a98adafcfac88fb21d810feb9f38dbc0c8cc006618c771c31fc82aeffd693497bbbcdfba2028cbc73e49ce074f425ca33585c891bde72455606aaa252ed42e2edc7ad7aefbd9ede2a51217f2c6e1ac300f6868cb8d0fb6bb5ebcdab839d4f63255b7079ad483a6fb383c4f0acb7128c500da9fcf7ce9e28068f265d3e266dfeca0e808c0cf8e98de0f61fe495eb160888df53bd872bdd9a7b8c89ba1a5517ae69c2b49753dce1fa1c215d6c1efca5d241cab5229ca657d28a57d34aa16c6fbd829b0aabb4099e472b922387022885de324ca45a8eb9245ad53923beec04f245e4fc6147895e7e0fcd457a3786db95174d8480701e2d659a2131d89ac98c627357851bf57dace645a1d00b3636c45374a5c2229b002a0ad8c9aa148fb6521fe35dc4ed09e3e0d5cc6bcda45925ef6f5df442f1ec4da7583f63bb2381fce6a7a9da4fb79d0ccaf2a4bdceb6cfe584a33b9cdfd6c9f3c4a8b71d4b3da17f174d6fb3b8c48a6a6f6cb78289f3f217bb377d7d210845e09ba7543fae4de9d397bc76b3a46bd7aa47a93a891775898cf4e865c5587746b353ddf1edbd0b6384512e558a9f346ceb265cc3c4d7d37ff83e6f60899f3768c495f49919ae6e80aeba85c4cd34b7d90d311f03a1f4356188df30d402031b916530e0e9da31b17ce87537f0b0b8d918fdabe536ae6bb6b903173f834921f5c998b39dc5cbb74a7ef677d72aa4cbe88a8823a8a0efc7de88713ea127c7e8fd10bfeff3e19334c7fecef45876f89a6800de74276920fcb6c248263b850b5c7a945e1a3a5129e774309c606f6585d037c15e5f824dab8fb74a9cfd49b659c98fb1c66c2484761cbed75343db437eab18ed7b56e5a3c0cc150ea98447c3b5c08c9f9d1801bd6b6ba15fc3be608aacb92c4abe8f3f506e75714b6876f5b2ec036a1456627e567c6e488cb6ace2cf54e42ddd41b6810bc93f83270b40fdbb79be84ce8e60cf527a1d04f89f22c4b936353015a8e05c23799cfbfc7fa58405c07ced8fc16d50004e364a6db3d3d11afec9f6f6037bb7061ae0b0f4f4ba3157728d24f819a3d12e237421a22c0efd8ae99651437bfa486c033e833e360935dd433a1d5aeafef73c71b5326b65d6df9994f988d00a03898d2354f58e3308b3c73b149c8a2b0165309d64ffe190a4bbf89a8633f30d674d73b1910811951b25aef8313e510cebc2f8e4a5c4286e2dd4db0dcb40b1745358f511c29645a0cae474954fbd907345b30203a32ed6848f10b5489f58914397046796e143bd412a2ea5feaa811e0a7ac8a756ce752d75eab8b6606d8d3da0900d621fb42b90e94e3aad05e0c42f9daed64af510f4846a4f66b1782d9d76dce9ac84fa2912808851c9bd23656465a64c5fa582e7bd1fed8c38e7200b601d0504f2578497be90818e69d1dae9a86fb5c2772e891d699f002bb4d579d3023df87651ec9dbb06ee3bd4a9ced0451a1c5e0a658712d704a92c2bf21527417278c8c105671e68b06aa838ead92c6a8566ee5912a18b995e9d1b6f9978fb6e378eb0924143da6fa15198686b8f5620b607e25e0540827f3454ca9dd085adc6e2c10763a20d6c70c5bfe0bb1d1b773bd267ce33a2b9c08a04a254d9c844475cc013c4276f947ceacad1c31976898d198c91e5ebf2623ba825e762665caedf1674775d15310972ddded3c75178dc3fb715d75ed071a292040223fcddf82a3e29af547a18633434534b15bc10334bd1c8504e210b104100c3a4e596573b2c8f11c304eb88ebebfcad0df1b2f5361676f899eddf0233b5d6f80828410172c36397f9495aff2001f4667a209394a585f607bb8e0000000000000000000000000000000090d131d242e333c""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -a163f0cce9b86d8807e6ed09b486e1aa12807f2370f2cb6d886eb2ba3978ee8462f903c8c43e7c35ab95413dc49c9cf6598e255ac8a4226e38764e3ef4cd04fd408ef017e7b8d3f418422c71e12a228cf65ecff31d2ac2334c9848425f63c9594b6644a26861997faf2b82aaef2a804d3c9114b4c64db479c8041cdee8c8fe1d63164c081221923408db142684084183062212076148c2906082898a1410d0b62d61104180488da3800501004080c648d9844d63466d0999111c440493448ec82482523068901862222686a2368a1c424840800459b82d9b448dc8a68004c12092a88c4a3869c202715c324d2415646404109208050cb26cc11062011689dbc4459ac0901ba8494328080a10619a462654026910432e4c8660d2300543c6459b127123490419285084882104b74523279114b9098120305a8484e22464994262c8c00de2a28564c4680b0251501691a0224054402c12a689248321c216610ab95013b285da306922482c19c90d10c6918a46818a260000986809c10014b9710cb368c812081a285019808410102050328d8092081132520b033211a32918156e042629a0a011cb124a1922801a042419154591384424230411346288a66de4141150328c09c6205bb2290446089a945143042e1bc18ddc828d48c04512039253986820182a82102243464589a444123402213162a03264a4b2718aa40181900dd1869014930010c865140570103544d2a44983462123b605d1440e0b36281816329c2850a3084221a56d1b148249908c8c0889cb444213310e0ca16da18890800202d31404c926501a14429a0671cb4685501488d30412090865c2c6440b3622dc022648305281986dc8a4880b286a50348a0ab7451ac969201726122588101384102061a0120521a1880b410082048a5c042e233984db224ae3060c20877012a0210042718c888d889449890620614064e148480495811a2132492801a1402c09b03102811192122491c22950188813174a11a06122a601042492883668d1024204236482246a0b07869440051b3862d88090500209a4243281b440a2420940b291883232c29805c93086a028694a40204a008540362dca44450a207224c58cc4204cd18240d1a6609934220c35820a2405128251db220903438ce4122a02912c14186d62184c82069241062a43388500b48899168624a784241349882870d4181143c6258aa284e2366a024261c8c26088b66d5a844d931246c84449a326108c484c219928e4b84540b04d9b020919908102142d424040c2848d0cc41192b84dc94824c30846430664d9342e203849cc2050c0202d08940d5c369263b02009b551828440642665542264c20411631401c2422611974959340c9cc4704a246619066510113249284ce4c884048945c42021d9b660d21069c9a64c5aa62c5ac0840c346e18104500289124822821442c91486ddc34649c9610d902440b142149444c12c10c881408c9244a1c034d53062112166024185063c288d382054b004188a6680b176ad9382823100d93186a49082ccac028234328d91262e2400583460dc43071a33620108421d2c891a4466c0986049b1280180511e48031c400320b9849141688818400c3c62c1b462641080901050003428090882d9086642016411820699b2225cbb2504b028084882c639605db2028188540013282e046608b2291219605409884a1880419086110055110264e00308d20a74d0c884c033080030825a2087208284d18324a1a96850c80710447484ca86994406da3843189228101405143226d9aa84c02b364c9986418062921320d204861d2987023138c43a8244b82908246205396910a380ed0a02411996822b7718b368d0a806902c67144a02912350282b4040a91314b2404182228199640a2426e904809020160083041092352643621d1064504b70114b04d4b424902086ad0b4305a00311b438458b80552142e1c2301229684989625501602e0242e014162149440633829a4b64c01354aa4106a0413111b854050969101132214b88520810d21856913202c8494010a3812482842c3142684162581927151c8051a9008d8442c01186e13034423b73050843091344d5bc65122a700820222112720141404c31864c3180483962c222132dc848c04a76819164c41228a4316518b840000b0705b424920b5815036108286941d2c20b22a5d79c004deb5dc374c0bdb539556c4b634d40da50855be06d8d36b11059aa84db6ae3f4d1c2167d07081a11a7f53a15c35494cf79319c17d6d9299cd94bdf976b0c944cfcce53d853bf421e2384c1b613d49da392012b100c05a190450877f0721f5cf930a81736eaa2098ffaba84c274b2a3e8abb8b5091342963674d95c46911db81fed0db546c97252415bc8e4d180749bec73dbc34f819dec3544b0b64e44070c225a6171342a7f3d9c35c4a2cf01f6f4a46fbdcaae316e9b946093058b7217f5da366c6ee69db19168bcb2f485370e0e80ad094d81c2061bda7362473c99e26dd4b7213c58e8a66bf6378aef003d90e0f74999fe0ed315f61318e2f09cfa31c3b77962cd3a98e65c1a39d703849d719ce1085c99e0df37d215227da4c2987d63cbe5cab98b1bffe0c6f0c6402fd44b27586ca19a4cc594fd9f3faa1e0aa8fec1b790cf8ed6cca095c457ebd57d0a89071b8371b7a6f65ed35f6e90b51731c09c5ee8760fce61b81cb37e7f82fb8ea45682d065aa6fbd17eb7f119a8bc3342cef4b9afcd225437b8bd9110dfa7a5ceeda7657f651211c09cd314ea63f3c8ef8624429fc4caeb94cde59ac6f63528d4990af5c4d6238aeba9b933aefc6911cbaa5c352fc2e0a31771b8479462ef3011865da42521da4f28b5cd3b564c52d5110382199f149af1d0968ef6d009ac528eded9b75f05e1c1fab84793cc5fb8eb734e8f25ca337676b8ecdaefc7f828a41a71691f701cdfd4b0c24d19b9a8a2ac7195af559e0b19a18e25a4f369e442a7104169473a7eece2b82cf061a45dd73b6857faa70d98739369e64ced1abbc600f63074b6270ea2025abd90844f4aaa226c92871a6e47a2ade36f700b5c56e1899f27076eb37406a39f4c5fcc8253e9777f84f847211f6a665fbfb7659fe160287342074b9de16542c1d1cea4fb6f2e8e53e7a097b384a4281e48dccf3a9c34ca5a18bcdd67f046b703b144ab3f95a18498da217fb0fbe38c429a04d92032dc5d1f70559198604a1ab55986d5736f36c9e6a5e0afc487bed3fea09d580ed55f3ae240f4c914ebecdd866e839401da3450547da22b3706a626570d2cb13fa68c7f248b635aa6a87b819b2c56f3ef34f2f8cb786e3d7a07d53cdc3396611961c289b52c4fb7b1b3802d0efcb20bffad9c11b3015a23f8145015b2905f83435e9570a123bc37e8298ea12f1e23c4ff4f4eb9f07bd3e1fb6b33233656ca4745086af7578cbe377e87eb8265e80b12eac8c142230d040a373f58d758626e3d7db31f40c81c974e82f806f81d320539d1c26c22dcef85e143cbc22f0ddec442464e1d5b68fcf18b32b8980ddad469fbaa75c9f57f51c7ec36f7f641a3dffa45477e28ac254b414030e8efb55984d94d747cbd8c6f5613e814449c5c41d1b816dde3fc0a8f298aaefd6c3f26eb1406d57d8b644461bcc7f108fcee5ecad8c0e554a5178d68bba842e1042648e76f5ba7e70d44acdf6c1ed0e993552ec8b83dd0885e3a747500eb5a23bd9577c418b2fd572becd5af7b6cff842b38936f8350db784b34e601f9a548be49bb79a700f858bc1b8f06bc50c288e81df024aa93337e0f0dc1316b23779a84a3443b47985c118792950b1161d4c498317b6a84b339462c3b01b504fe093063771171027c37c5501f78d01a291a3d4c3bfe2b8a4e375c5586b2d25650f54305bb00fb9e950c2f18fefa95ce61aa70eb9657ce6e003f679e274035a2c61c8f2e9f33cbaaa86f5aa619c35e3398babd960d4fcc0c8513deab5860be248bf171080187ed76a420417223544475c8941e9b040baa988e1a9a327130eb281d1a7c06bb9eb5de26b166a3eaae1c226dcf781cc86c717ef334d74ec79de525bd97eb9f9558c652b758c38b4fcaf1ba0c3d15f9d3da495dedae25b8e9e059ae4c347238b9ba355ad4fd5bae85b85cd47d0a67e13f986700b1e5ca919350364a2d8c72f97be3b0493d02a0266c1fe806d520da5753585abb0f3d39ef5d464042d39119de9a7f3ffef132611e47b69e6c1250b8214a40c8b701e2bd5bde16651b550ef0e75a13598a47d2a33be3ead32394d88c3d799785fc70dfbea2dc42e5e77534250410558d3a8f5592164e78accfabe2e040967c21d3d8d30490133d4a9d3981df7c0777f49fa8671e449ce5dc445c2def7d7c2704067d28e5d85b5d39ddfcdbe6abfa4b19e7f7582863b2e636b0c9451dceb0b959ed38c8f85571e567278cb872abf78ce645769308b2df27d13533912c969757a1e540f90dd3f6c9a5e768cbf2dcb6ae6eeb4d7fc0a82e8db38f4b8283f0649fd00d1891b28c79f0df11d749bebb6fa0b1c084286a2c74add86d82b1513237e134dc1b44b2a12323d84a11799dd980c87e18a54f223c476527345b55b8fab4485fb5522a98ef8c8f3e5339670e836c8d54631f741fc4b3d4cc30d646a4983c45d5b3bfa09bbc87e5b3c22a0332886ebeba1453b4c002b1b8be06a8be16be13b440eae017cb90a61bab9e3d3dfcdf5a0836e47669832d827b88881c99c1b1ecf8085344522a4fdb5ca7c3393e7df89ac3c89f3b9757cd476fe15af14341c2bccf47014cfcdc42a5b72222f466ca2b324a7c3b2c9ce0c1abe933ee39159e3f4b502ebde7c1dbded5077cbd69f66e3d23d358e0b207150526f42ff0862058d928ca604db982f4e41092bed105f7d288617d55bae32e96c44f50c9955af0247eb3844269f95834e28d4e0a37ef5b03b79455c0ae660e32941ac675cc8d7e2e036353cf615b45be3fd0029121f72c68280f5353d1286bf10cc0cd378db30e7f8c0bd0fbde1cfdee548ec7faa55251f07d8551432cf572569836baeca30db5bd194be89160f449857799ae7e765a99bb8e468127f65c7e9a1f7de9cb961bec1026455f503ce5d199dd07a6012d74efd44403fcfb246eee1fc6f2945867f37507feff0b641eba4e94c532a4bce063503add362874523d88cf1502ec6b1f7b64fd267e754018152275f3465acdac0c94ce28ee844d93dca47686675deaa3e0492870d3c7e2c5271f843a7c29b952d0536ca961ee0d69a2a4fe5a23f672e5aa920112cac08b771078348197d381ccb4d2b9c2001fd3bf042a44bf8de877ef7c0ebea6933f23657cedc368f9a51ea8c1e33f4b52850162bab8ed40d6e01e0ce3258cc28504f1a594aba83969230a3e4655f85756b4d835867d7cd6c0b73794fc894bdb0e77d4397cf46bd81050fba18ff6f168b7cf09435243fc635727bd5f600e45cc157c7ac9a328861bf8e9c49cba350147e1b861948800300710abd5ab3af61f1303bc46243656a64f4ecb655be8614b5e4d6ac5da50472a3661891eabb731524a31b646e6998317ec4e46f62c3c946a610905cbd83926c907be48a15d7f5614b0f7730aed5cba25a684c3178caf93fed05baab1107f0512f63f9636fb001026bd2e7eda3cc1dc31a7eec5c5d14e206bfa68e1ce5fcc956a65f98878e09e5304b481d2db018873dee5aa6d2855e596c8e8c388c64fd7ee42435894c5bf62e7c05f554d471b8fd10184d7cf2b4a8abe84942915b3eefdbb38bba5a92b2a5495bdb612c31770e5ae46c745e609263dade6a873346577f9c3a70a1813f57e35ae2fc248d563229ab03b81f3ff5e4b0c93ad944851e99daf551e2c1f685a0d034b198a7a89d75c05399443c5c46f1c1158da88132a1f116b387eaec5bc7d6e5bc55657a7dcb7312129e1f2f78173771e58349501b63c7f9e5a41b51cfb10765190a3c0d328fa7a205dc7fecd8544cc14fa1a0f26bbd12560710369ca3fc995b4524393d700e42203f3c33731cfc71a77a22e197cb595a6e2a3d197fd299a2bbb32fadb8b694df8bf11510764b9ab7df1e1a3c398de2b49683b84cfe0ed9e615d8ff07b55762c495bbb784af37f737762b952eac37d9d894861b33c9ae075d0c1e8e8d9d85e4f1d99247727edb6c31a0202ab85be0a3bc550d59d699961fee34d2fef1c975256366f99429a60dc411eab31ea5d531769241d4241a7e482899745a3910ed84baa3e58d1e0ccc311eac6ac45a5d96034fbb4589ddc4035b8911472bc579473d9091b15fad1b5112887b32e8d2287f82d2c6fe6a2d37931244cc25d33fba2e3e00b47f5c8d5ae2aa53535183b72147c65e0dc4052c6a38466b777aaf404a6c8a5522427afda01b4d7140c9f7f057b47491af06a557b9b4443ed9c4625d4c817d7a128c97289349f9cdf14371f7bf933c4654f0968df4f5dc0cceced0f305a5efc0d8778977a9e549d09a6efeb3034aca5d5f1d1f04170c8da622826ce9fde2b05e1063cfe1b0063af1bde69034dfdc7c1a912972a35b4b3def486ff1546fca7193ecaa8c9aaf1355368e9c143f59674211fa7cbbc64ee2a7a51ca3c3e9d8035e0ff0c5889453777538066e6d122fee1d332f6a41ba0130400c531952f23256f5443d75d718355d1497bc522f5b0b671185ed21b4dd6bbf7e91c27a0384a4d7216ab6a29675cf07de1c67eebdf31b491251591960d28570f00abe45353c26c61ebd9cc30036f4297d9a1cbc4c45a8f71f0a860179270beb3707bcff3ed7d86a7713b9e4a1259cf4f351dad881d1a40f897d661c32721ab409fd87ef2144c2bf03b763267d137224d11ccc9c5b94fbc4118732d1df1c1a5729ba934a5e9181f5c6778f33a7a72ab931647c40d8f788ddd3259"""), - TestUtils.hexDecode(""" -506462786389055DE2E4AA2A7C80388315711A7B5DCC73F2039DB99380D48D9A3DD8CC8B929B0AB224DAE74EA90808C302197EE9D847261DEFF4136D3B2A37CA32533384443B9D935AF2C384EA63E7160BF4BEB89EC0EE705D10C72F2F65A4E75ED2B1901F14B8C1D21DA9C6B8842DB62443D3DF12969CE4E45298FCFD6FB103B87B0817190C5ADED4D04E3BA4D2C3F60CC49FE0695D6366EACB9C79F28C9121584D997B7A3A7AC3243C3C75FC86AF81CC8B888E90095051F7825294CF7E1A11464BC153548F8195522FEAB9AF5AE93C5F6CF80D9ED76C19A0ED0BFBCFCDF30FF6EBD0E5C20EEEC4992765FD23F13F027E2261C38D11FD1631846142541ABCB82C0EABEE5D675EC130861F9BEE9D9E02305F168C85201DA1DA2E4D21CF1E4BB8C2539BC1F3706194AEE7E3ABB2D7447EA531619FD27F0CC7D09E5FBFFB0DA81432D173321C433391FEE90B92E8EE3F39ED492E78327D8A3586B7052602607EBA79CC9AF21132C7D3A9931D5DB4937FD5C5611F79C722E0CDC48564E416DD251C46C02567C4059A0DC2F59A124A4EBAEB9B1B04277CC47A9F345FF8AC3F8AC844A668AC6F7E1BF1C9889C3E42C1142CBC31A46EDE21CC84F230A483B5CE23A901375B27770BEC8F0AFA25F301B7AB43B714C6D0E98B009FCDDFB75C0E26EBEF7C9DF5ED04CB4183028DFADFC09963AA8CB3A9A1BDA047F62460F2B88FEE1C05D9E68D646137F660B68470308225FFC097474B2B2BC5D50A025724FB2CF70873BE7D04C05AFBF1D7DED56693AA4A4E495B1FAF9762DB83DDA6E75F530ED5351D171B7BD06E5ADF46DEAD06AEA37CF262AA33D062141F8E394E731B3942D084E583090F9CADF87C2B81C4B7F114D150C221A12393BAB92727B828C9EB86600B969E1B80F33E1304CEC68A1B3B474762175EA19A4D67220004FD4EB0B2C643B69C00FF3876E9AF63BBEF8AB6BBBE247668DA8F2E3CFD0B95D6926AA3A2CFF4587C45DA60BDB03DA78DDD9758FCF9926FA1F080A61FC0FC7660BDE9B4913C40534887B04E2DC666E981AEEE38746C52BF46FCE0E2233CE02C9307262499BE567C150CC54FB9D96B81D3A3E200EC8F7E87E28272E7B956600DD7692799473A8C63AEDBC8F3F43542B9E399398349B896BBA16E5F26210558DDFFB984FC924E1B0D272CB8834B1FF641A894EC113460C65C66BAE86248B48F675F1313EA76EB4DD0AB6EE41014FD7589D1A7DAB16CB8F113A3FBE7E01EC67B0B3CCD81C0A8C7E9824658C926736A574E9A0729C3BFCC34E0D4BCB1606E93287494577A6C4B1090FA6B997DA098C6CF555B5574473B1063B739CCD139C2541CC3F962EC42BFB3A40F4E64D322836EADA5F574B48B5722D7809A3A20EF1FDF5F3EBC000E466BC4CA10E0CC6A1390FDF159BCF0182293D9C408A8570789C485DBB977642074C869960E9648641C2A80D8A1C4E474FB98D7A3DD75D7AF01D2605945E89493699EB53E30EBB0F936B63ADF5859D9EA1DCAC44D0BCDBF2A069982BE907F1B560AD8327BAE013FBFE6E2709C9FDD498491F1D8603F9F6C9B1A643F6FAB97DCA752D9BDA1DD6BDBF52B03ED7768D98E46092D556C266E30C77A10E68AF76AC3D359D8752E2453B2E75DFECE6F66E6AB00EF37DA6E6A367FC808E1F4905339F4FA73545D13DA7E7DE49CC0A2A63639A96EA039C4EB643627B7EC4FACA1374EA800A505A80F554B3AB3233FA492ED6C17B5832BDEFB3A99FF1C64B35F1531A023415290124EEE2C9A7E34FE8563528B6A4B64DE425A8FFA91B753973CF0C96FB2A8A3F71D58B77C93C5866DF5CB5152B3A0A32884E349C63870E9CACA82F121EC2ACAD7B6052B0D74E9C28B20C76A7A821D192E11B59A7C8059FC49662C655551A7356046D46FCCCEB4DE1F5FC91F35B950F630D743C8218A10AB25D2FAC25308225540FC24CA794EF171DAD7258C2B7FCF43297F6E77A6E83184114DBDBE408EB644ECF49E04FD79769E4FE9B0530F21F8E3913A51094D0E49DF012144EFEC415B8B2A34AE2462607E7B89BB86F0C733A5553CAAFF9B19E0799A1901657BF4FF5AD6DA7886B477358E90D56BEAC6A963E0669C38EF47173503B0E9255AF1F153E673813053A899418E2BF217D01D9162C073F256CEDB73DC062D201FF6056180A8A6887B286AD6D3BD6B1462231D6223D0DF2BBB7299FA6FEFAA9A297C56ACA28E163533406141EB2E65F0C94A6286A0579C76A3A8EF96DDDAC9DC6A550538AD345FC4AABEBAC04682D4AB0977D439CB14F02FB504E10252C1F3ED01A7C4BFDA6E689D842D9B9086517A84AA4257D1C8CB842E15DFA615D2E3F2464E4012C0067EEE60489C044F43050E5B1AB3E54507422E1368CB3EC8CFB03A887DDF9695AD95378F875F14F7DEECFA54A775C60C6B7025E5D6C0563E0E76C05C93E33C3E5AB6D1E1C051B52D2805D3BE0A4D3E8F0DCE6BBA1DF04C7F76F7E13D8C3CFCB2AB04A1E605D4DAD72A43D5223FCC36EFB34D999095E742FB9DD7B69A28E070FD28138B403DF1DCA75E00A160ECE9562C92091DFD3A24C53645DED8E17B39D8CCA4C20C96F9C9F9D14AD3B45A1E87DA75B831D400AC14BF34A9840936C3277A135BC0E8C65E0F5E670AC912FA586FBB4E149B09F64D338C8C886BA65730039B5DCD0DCAD9D6EF11C228213438A1489F4FDC39395E8447212599BEB570D186883E02B442F8BF97884EF98D3D6E59254B3DDB77DEB8429D110F0689715F3E0A4F65908E5EEC867AC7BBF27CFB965727AF0A1EF37B21EC18CD60A1C87287527BCBF5249596083069315699CAD10FFEB2D87810C4DA090074FB26978E56B7D06186C48BFA4830A0BFCEF8FC7B95E73F64EFF78043E8D93F57EF6DC636C8FF612ED22FB21174EDAA59BCF89D1A60F0E1C15C5F8EB8E6A39139D500E8F28A5DB86C125C6C76A99BC47DAF66E679121557D85F5093806B748B3EA65CAC386B59C0A372AF2FB7C84111F0E0FA2C71E137958239534C4A012B1B421435B7BB8CA577DCD8C8B0A798902BAC9B95AB87B6A0735D1839DEE336996C2357C748F4EDAD858C81E2115595ADBC173782E36D4E720A5D29A5681231F9BEE91D455554A8632F7F02FAFAC0FD9D03804B10DDF4828A69AC1CF0581D2C88877BA30EF2982E0827147766F8B71E264E82C3949BB87562F810DE835CCF78A7E5FAB219E64B1FC615E7C952577B9B482F78C0D0C512833994895A125F43EFF066CEE293004E9E0E5288A61EF209EC52233EC64BC0DE76C78EB2678559724FBC05BB5B43CDBE86F6C481AF3BDA11EBFC0FB384AE00F4ABC212B0518644638F01C38030DD05FB06A7EDC6406CA18878DF38ACE8E974123D3699613ED46673BD04ED51C352F124A8F89DF8C13D2B44245084B7FA02677D5287D22102AEF4A4A0AE046BB1C6D9FC9733AE5066C69A10589B0F33780622C1709F179D4E8857564804BF5C4D83E03484FDBD1CC4D71C6A2421AA59043DA85F0B51EF91FA5DF9555072278331BF3102F5147021662D135F3011FA48DDA7C97087F01B7F86D549F41E244AD7374C7C1F698801CEAD305026D17666435217799A4A5FD0ADDF9B8BF6E31E51B654E4D697554D5F574213CF579EFB1B11CB2C136FDB9EBC0DE4D16DC9DF43E17D88EE22EC88326F65875439066CB47E4C656A3AC59BD9A576D05ECAC5B3E7AB7B1A3C0C1C48807C06F1AE4881158D6BAE9620B08BBFFCB9940B6A6D04396014CFD54E93D863156D16F6F9C1556DB1E13E630326C8B681CAAD146F32B6977200B204B632F6CBCFB2BCE9670D89A9CE043E2004773913188608455FA715D1577E03826A2471EF0143DB3C39E03D890F0CBC85040D1675821D282822F80EAAEFF5CAA49699B68B89422D1BEDBC3041AE2A3D6D5205C72123991B21AFFB312F5EC8F96922EBB44D7A0F8ACC2E390F9E3FD82353276D73E85FEC904AE6319B140E5C54FD5B6F19D17E65DAC5EE270DB3E402534B0F408BB3C554D93BBD32B255D478F33BEDF4A192233294B320393D38284D7D9987708C019742F2FC023C041219FBFE2B603501629BDABB9C4223F5B751DB78C144CC50D3A35370EE563D6DDECFD6D715F08E14A00FC265D8433055083048396F1BD4E9F010EFB974D6102401B2FECD972C26008A4B94952EBC61C35DC846FF7B3E20DD9C6E033BF1185F35A5F02139068E1D4F30C4778FF87057F34CE1D2D40BB61423EC055BB57B56C502DB8D0685B0ADA42F9C52B590610CE2F8237F92B71B3AC2AB75D2E6ABBDBAA1E554D99CDB687B72DE98ED0FCD618AF5D2B0196F1D3C19DB77686F01228C3D1DAB1F171A56DF9311939CCED0F7B22A1B77F473E8DB65C0FD6E307B6F7A0F0FAD69E5C1F87D01EA4699F4D5DE39880CF2D8E910313AA6026C17941C41252C06687A085903A502048726AE8EDDD2D8918B71A19B807889B6C2E866FB818810F427D2A7B6CB137D94746A88BBF068EAD31216A5511A54D81031D36C8139776E0FE29EF7C8A5EAA730C3BBF05988BB892F699F72F098F2931F9B4DA17243404F64C311767A98547284063D44AE74735DD246B0C189DB322058198F1D176EAE6E076965CDE68DD0DF2B284D23B94BADAFB8650F21B148B9C990F7044A777F9BD229F7905B242CC2E267610A42A5C3185C64079DB340D86598C589F9A96F3741356BF3E6D2A811B6551850F917E07E5289A07382B8B506C510C9396DDA81DB336179EAC1F84DB9D0E7BF52B906E82FD132647A84A299BA202DEB338B79F976A8D257E246B2B1B60425161C72D534B04355B2665129AD8A44C09D73AF51DEE7043228EDB62B858399B5A4312DDD7ABDA09A846A60FDA8D0C00E0ECC364A6CA95643FAED93D44BC8BF1264FAFA6D98528CD3BD1BFA352BFE1FBCC202F44496FDAF9F9EC53007915EB67F9F8BFBC88D82100210CD471C48F5092AF4253302475F9E60C287F0A8549DA00538432A342814E1F6043BA4355D72268F6E84A43264EEC3CAC024DD6E79143EB502A58E6F8478AE985797F00A295E84A0F669BD9252A3AAC6B2AFACD7AD398DF546"""), - TestUtils.hexDecode(""" -fdec4bc58e167745f07a2c4e30f8d8ecf9c7a6eeee6793f77c27353dab270398dd811c611b6191d597edf44df73fdc14bdc440529b77ffeaf18ed94a613fc3f340c55dd156e8d56769d509416beb75167dedc3fa35281ba7913e94ff5a374e0647a7f6bc99ea6ac30c3e477e69823f663e8748e8b5fc43f1728612d109a2947019331c718ac31e663d44041f88b7861e074f4e1c12ab2077dc59587fbc451aafd29e9a7d584b744d83d36f794ad034c014bcee229b847e8bdb120407201121f9f58fbd0e17ae318dc1674f1c7d9d3481629cdf02fe819de516854b2819cd6a9e97bb92662757a9861c113f67ffb191a086cc6cf612d13f0147bcda5fea3c05fd29115359bbe08a25c33a58a3b38c3214f8e4379b64fbabb00a7221fb01181c7cc2dac81e6271550bce192958a93f2f5a11035b411a00b610728f704d59d7a7e51ef2b06a2000fce618a6f82a06d18a899f7c59a3d12141979e8ba62aa4485caedbd6b8ae8f2dadfe21b7e27f911daaa80b6e22b91012ee5fa16164c5a734265b81aedcbd820b8fc5c8802a5e7cee4f50adc824dc0f0ffd626aed8fc5173b51ec373dfde19973df541b031dcc238a7fff8c01b36f8df74a0a5705a13880f1b49bb82cda0faebcdb8445048ed05cec1fd95011316a53712241f837f7a544c99c631422072ff58f579e5148885f5df4172044aa9ac4bef20e852b46ebba4410b05a5a8cd5993203f44075b0b96901fb73e1e561fe40b0decdc4b719c16391891957f97bd0eed0ce3c3b82f83d0afc9658d84d5e64bc83b2b68762b00eb2a0a474c2386fbbc87ec8b2dd03432506169f3f58f69f0dc62f140d437ef524700ff0e55e39264aaeeb3fc62940bbddc9fd1a13b9d291d82705ec87507e28c1ea90e15c8d3d6e94a66adc386b10a07c81daffb2b8d1176b958f61370ef1f0189285a49058a31c2257939df230e1218693f3dfdd9820407b509f7307cbf02b1dc1f182f9b3aadebfa7c73a6d6fe4aeffd3aaad272443df14939dd94af7543aae1212bb24dc7962e9e96d70f85a17464639f2e89344cc9b6867a6bdcd4191c91da327a003e62c1117af999f2f027ae14522bfb753bb93def9153c2d6c2a6fb8ffbe7923701e516c6a9c67ca2b2b5f66cee09864b6414716a0684fd2e3c2ff1f1d09731237dddad175b9debb722728049ae1a78401b7dcce662fa33fefc2c647b116467f25a42a932abe1742b1f486df764075ee8e765dd139f58762f3c61564b5fd52d4e511c900eec222116d27ad9dca25517449bda55b1509569677b2f0bc99c4d22de9114a8469a4e401f33e7576057d4f735e1c7661a8e986a5aad28026f6af030242535fb87372ef76023761a2b46fe30002e947a0b208f95663b34f8e92f72f8c6b58a9df690426c3c7352b8100c87b48639c072f0ad37f66d2b0e6c84fdbcb7ff506b911425a260f2a4e3ce3d6abf5d42af4fda4f37d0d4d511efd204c09fdc42d868cb8e036ef79b2425780df904fbef6e22f5117434da776e99253f0d444d1ef9cfb10f4e0782d3a5ae10b1627f7b71b040f081c6f5377dc927e65965bec75a5cbaf4eabe36c65ce71c75476c0b962a278077bd765600330570474fb68a30e9e427030825674408c0534eb2db8dfa2e986d45f06072cbbce4b3a2e03a1209fa8a9eca591128166b40bbb20419d31bb82e30b2ee7962c9fef7e788b55be7b9bac11cfbce39259ec32bf200d0b490fb540e1d218b52d04dbed8c3f650c8310e257d887c472e24ea02d3108712fc88de316657cadaa0d8ebc417da228dbda1ec98a61d1d1989dc7f10a0b4fca9f6dd2c614755bfbfe26586fdf8046bde39a2f8130d5bb9f55f67db1c9d9c7e626641a97b09d4dbc3178039d78e92b5049b7a5cd637cfe35d6c6b86771db2442040d15667c256c6beca875675a5106ca68ec6f7a01257c9c7b3464e01e8146085cc3a9aded04711d2c363cf7f262ef90f17c8ea28a0c15fc2eca9d970b33ab22fc43619cd42839f7ef53660e9aa88a32fbdcc5a74f370c6696922c4981048cde02342bcd5182f0d633cdc90b383068178de2499d41159d32f6c22989d230e0802ef40823a64625003c29b0b6c1d9eb39d15baa69947508c141dd169caf1c617a2ef16149876a56c6b2c4a92be4d48b3d277bb5967fa9931611a57893486fe3b8e8b92a8cae0496b0808b49b712cc6473ad44216ce3d1855d704561abf8988ca52cbcf7cf95d6b071acb061f03aadf2c50c4159380262edda1827050675cc375a82010e3e3299911db2d93727497ca0d75f5e539cf75d412177469afd91b1a8c8f36a2e4ac5484020eb0c7124ec570f94778e8a43e80d8fe145205ade385ea279d4bf6c4ce8998b118147edf888391488596f2737bb381cf46c939db876de724e141dbe7066f4a13c35cde58c718bea1e2b75f6b6d9600fa08835abd0863f2e3fb8f7d776b1604fb068f0c8260672fda6062e5585c595b087e399f6a6d1d26857425f600ab13113528bd2de7b8b78e933aaf344880e0aa06facaa7090627b4bce3b193308f8c152eb82e13573770e3a9171b2177e9593911ef00efee1237166261a38111f07cacd74f6a0c2283757f182a508ff531568cb05572eedc6e5b706c5ee3b3e8139b7ff6fb42a9b87cde81b21ff2e6e48d0f89a8adb77aa4be8db46ebad82b4033e857f6575c1bfc0500ae6b95c4c43843cbe7d83e8684a1275ee586e50b7241ddc72c017bd7d4aad25e468b824a043504ce3950b79a5dd2919fe3411dd250ea82ce01477306b09d0cb9a789bf24d22288e73909a57ffb7a1a395be080518d4bdb46e8648486ca8af29cf0311548690a2800648cff58534afbb5226c2e860178308236beee319c14811354b6b05a324115dbe53ea9bf37b7f8284f4b39dad5ffa4ea97ebd9bdf35d593d63026667da30e0df76941822908f6df732a8dc018bd2a93be0a21d64e33da01292fe3fdb5370a0fcae68f860af88dd8a4055960621524ceffc2391dfc237205efadb78f1df769e070b09431fb7206c2cbe3319312668eedbfdadd9cd246d3d5dd648d20758882ff7f3f156412394b7568dba0150e27fd442b6217495d2c42108e9f16e9167684caa81366cc25a31766e4743c49eeabe051cbccf225016f067939b238fa3e9330e4a7443d36134d7df29f8b260d0b7a3e14345b497de4816cba4921e18dc9dde508075da67ab8c210c730abeaddb040cf4e673ec03bd8d803fded05e1256d90d3c050aea4c223c174dc9242de76e95fe9ad0970c3ef6eb5e7afc8725c77c5fb8d265699779f9cb2bf8bb26a095472c939bb3356bdd218f0b2d99b29f0475a4858dba236123ed647e94ed485a1aaac64b7c2ed19d98f2d24019055c5c7ecc88ed2cca17019388419b3f9819b489eb837bd3c7daccff555c7daf5e5fb5c75694c96f566aebc5ad5a48c6f272f812b4606e21473e295c006c190a6430f7137c9ac20727e68b0eb6fbc8255cbab5cf3832938b7d85e6a4c46e7f7051571981bc3f6f86b9a6b149ae260360d21587485ca40dffc6e93c78e15b875bc82d31e04538863ad8bb8f736c23bed9a9698b51550f91caaab6731bd6feef0226fd3e08b3dcccd33cc6f7c8d8d36e8ac344f851c3596fe6f432017653df0030a64e73b1758322786694613bfe06cf75586e12b92ab563b583161292f328b56ef3648b050f75fb108102f0e28be8c4cb7dfc4283f68eb6bede47696b1c9156194c7152b79a96cd36639488215ec9d49f8abcd5264d89b51d72c447e31ac2011f7223789a82c702340a4ce59a298713aa95e17c6a3e92011f5ec81a3a9b6537f1331ae446965e58c2e1aff4931824fba76940c5f0abdb079f4ba8b32e169e3947594173832dc34e824f296e93099ae8e20437ef564da9fd48d6b6a2cb938a9cf884fcf3327e1ad935257157d0e8e379971cee3d5df59135207930ec1212b7f38b324aab2f172726712a9d60e40a0054f26586d5b3a794edf8f33819da983c209f9f4b514875975e40f72cf9ac1ec28811cca5896e9b4cccff414650d00e71ae2e37c4bb03274df43ea5edb923e157ed3adbfb79b2410b088c6ae9f78b10eb87b0d336c5adb19db50093a7b26fe1f39cb7c6b19001e4baccce386684acd8850cfc64aa0e16ac6cd15625e73b798651fd44828f2d6c4179b21af6dda2262c79322f41a49b9327f8ff0381fddcacc5d1444f449b54d8cd0103140c292aa49bd3a807e5af3fcf33a0176a3bf32ae337c4e187cff519a2589ec5a75bc531ae8092b72fc906f1d82735070b76818d0d5ca9266e7c0f4b9506f8adad55bd8f04f5b9baab4662d20eb3cfab00ab81bca5926b6909b5fd30b14c5581152aa37a3a275642f790913aa9f44f95161bb00c736eae908f7b3c0745514b595d947f97e67758cca97f754cd359d5a4cafe7884c10f379c9233e8f9de5e1a4688dbf92d92a256eccdf06819d7badfadc0f5235b3fb9c66cf65c6d755c5aed48610cea135d8e1bd748fcce6fe74cbea0cde943ef57d26cb7d0699f9069ea14ce1a66a5b57fc442c123409b896535283cc724c27240850ea8b9014d01d4ab2d8d151719f3b2421b60e2ce0792345f88bc26f2e3d4f9cd3a69777a114014ab481459d5c5d74278cf1c0ebbbac2919fc1a77e0997aee5ed24560563448b471e5679b13adf445634742ac1acab6fa5a0b6a0e8e285714c12fc05031c0ee83ed821bfeb0bafe978f785ba36392aedeed53e4cdefca5f4026b535d7a1a1c4ec9155b42f79c8224d286927c8af6b24c0d87e9089d2becaa48f11365e40df4810dc90e12ea6288cbc3cb2b84ac36af1867843be343c3c734eea10a54519d9c6bc0f04cd978360d5eef8c5fff75a3e4748d4dd37735919a1d6c7c4c48f5aa34567737d3084686b1fbe2f23e4a639542cbbe7f99c18a80f97033795a81c9ea029d51e2111e59c7b66a2c78629a1594db70c5ca13f3a55cbddf56f1e66fc9f3176bd073532db09afdea26530bbba27ecac9d5c164ac88f7fc3fd71781dee0612ec04b790d66bef2f748e93a6215408bfab48c4932277e3052dacb3384588456dbf15fde73c3a2036123e99d698ac5785f7027bdc21a130e875870513c1acd7802959f29cc2c3a27c1d9b97256e48666efe178bf7a1b6764cd25a4e8e97f0f55089af7fcc40ac1c3174f9e9d7c2601c8ccdb7c62930ea25e3ad4b63af9c2dcfed98ec7360e85327622f01fdb3617aa4c47ceae1dcb3b64471cd1d810d03540685d2a34cdf58ebed79b81aa1b0d2157f68ffbccbd4e617d61eb23c4c77c5bab60c1bc66e021c67a26e383aa01d3b9f53f20b9ca367d1e571dbff0bc8baf1baf9a934f7cfd06103aff1db525bcabb83b254460909151355d60303b86bce2a5d0642e951a5f1b356fedc9f6cb84fdc9c30e39231b15ca1d5e26730cb175803f4f9df3521e1f15ec7ad77fad4664cc1f96813c119874e5390b2b3b04682bc5ae2a81788426b185f57b308e3b061df87c9e69b1629dcff9b4104146c063143a40219e4c0844a58d2f91cc58dc9012de1b4c7ad6afa9ad0741fa13c651be4f27b09ec40d8bb47196068ce43e9585b1813ac01825dba7b02aded59d3df27ab5a18a7100b5df7f68b51d0557a5c26d794cbe0a63539a16e1c3f612d8a30965271ffc16a088c9b70967ee3229e2404d793086ca6f378cfc5d0c560f9de81493cfebd6349b7923e16980d2f04c5c48f7f85e56853b11f78e21900b9d9dfdba973b87c1db5c860a4c890292c4aa4760cf5aa9972a1db9ebae714c93e29af2d9b3ecea7e9777e6d4fb2550f3f952666686cad6282e0dee72b88d1b68bb1ac9021d89dac8a56a01c0c2138fd71883c7654f30117019dc70c85fe42cb57c23a2a37060402a37f8fae690abd43221fdcc23d992150de4ab217d35aa5752c3bdf2fa3fdca3202f7b0edfa83d6a0938a3e2349c51d6ce1680654c38c8d6bf2659c1885f8ead0bd687cf56144f1fa6f32e90e08f059bcf34e3493f42a85814c24cd68103230430567a960618dc99cda88cadf09e854acd79a2a54dd70dcaa5510e0cc3e4bd32b86bba8f8cef4e08867fea37a14d3412ab5f2c36c61e6e96eae2a00ae94dd5f27d7a914fcc2eb6f88b8a73fb0ecdbef7a4e2d15b7e9263a37880d242f8c230afafda5a7e919260b6e14a8d65381d73878858b0001a581e7add55c06ce1d8e30caf6802b33805e2b78d4b8eeeb20c747f7cef3a27cf17e3c1be070e8fa1adf20ddadf2e46e53d8702d75c637c2e9d9b244e12faa41f1ecabc5d98979dbaf2f0a00d061f1bbd0231c94fa5ca97a75b93a48bb3d2babc9cb0a589df0f8cc72265971e49172b588490752854f599ea4a97e71b0a6d415d058dcc875ef3f09c37fa7e4c0f45045a7bfea8fc0bd9e0c1eb36a0d3e7e03240baed7cb5d3e6aa8ceda0a0b394584bde43190bbd0ec6ea5fb3973799db1f0fc11232c3e588ca4aadaf4f7141831468183a3aed6fa4caceced00000000000000000000000000000000000000000000000000030a0f1219242e32""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -89ad3b5244d66fc84f3dbb02bb51be6fa25bd2ea3deb3bb6d964448351d9821ff3350a0923768e299160662ec5f29db9d9591e3b6730565c74af37804e43d888b6ce506ec5390c18b510f7f40702ba377ecd3e482c23f10ddd8e2dcf132ff6caaa6cbbe799d88e81dc0465de420f7dee501868661eee9c9a2113091bbabd22a2d10692099725cb201163862d88c4845944051a414010460912c764a0066a081666e3484cc4c440d8a408c4466ea3460509170909844ccc2822da9481901449880831c0c20c9b106082c6601c9871d8320ed1942161246c91068201386dd21811183131c108282091450a248d09329219277222042891020ec80228e022429b2011e1922004b92c204440044329e3983110435118232d19b761448425d918901347614ab6084c8428083229c4206403b364d246856230721283000ab94409086188c64d24164012c281182186144632143825c48281cb9230dc162219414820432e1124221023124c1068e086640883811884210446525810725348485a142024119101166c1a8011d0244900934dd13891828470e4260919b06183b649d3b488819285123692d1b685d08261c1080e21b78c0a305013408d0a101098208a81c24d44102143202d0845280208264ac8700b342cc2186102394423280c40369208047020b948199951e420204b464e124066e2c06522202d10236dcc246a89926040281008c1119cb28898a630cb0464428045d006909b8211192646da90241b824c2212892005861b9451013165e21604c8347200448952124c1a290d21a74581942812268048382240400d0007301a056ec1244c1219822088480c4829d930828488048c40489a064c4aa40061308d1a25314c348e58822093a204212268800684d2328211244a1ab96512092440140a91166e4a845019057120178559426c8aa41114c0651b98654b9609d146480ba24c99024142344222024042480504883022426984024d23205244006ca1806c14060112c2251c289052b66452b82808b30d9308094126100b8749c81285483429c922019924450bb16d000460202742c1162590380622b5050a4060c0b24018266c89000964882d81320aa3b68de328250218469b34899180894c20012419469104611bc931a04052d4400d1b04300933648a0031c4a8500c430802252cdbb631c1482e00a92954a850a43804a3006ddab88820078ad03880904620cc4846a0960d10b5211c373289346503a2201b88084482805bc644d10885929208da84211292841826329ab43051904141a844a044120212311992290949244c4428c99251620820141244508404d1049112262902b620603208a3a270c4367241422593882c18a00060a24521378c4b14441c222061366e249641e3a86d59c201a292700a0006e3405021174e090942a1348dd3a0299a96219c924d1421520b430e0812129cc868e2b04804b94108b64c24016d5a868c20c8459a082d5096689994101aa5608c0091088950a4b4484b24654380211a266411968d80a22049369118c6290aa16c62806cd4a40d8cc201e4324619261008122924c42409a10c10230c01c609c010069b84699a14240404814324620a1162031548203191418209c4165220b72181a20010396163b86814374641a06d98344a9314869b92459c044ed03805980249a3b041d0960c5010048214060439249c02498c4220082828e3426d2228308b3451a3046463466a19018c5bb24022a30454146403221210182689044e53828804a72193b840c0c06d0a8144d9100440b20444900181a664843825c386812394645b806059080d08c760922262e1b2501a41721a3100029111e01065900000014669d8021122c8401b1192cb0850e0166a22812c601261c41649613442003089a3a490e0c009e3b8289ab42820242a0aa6451a073264482d04362648882140002ecc168503286e99b0614c342c802260e0b0080392110c841018130a19188a9c36610b465041b88d22a129db307083008423a124629661e00465c400681b28451b444dcb802c54c688db4265d0121119038c0c036a0413115016048ab2090b09260c050954486163a2640c281092800c03804053928508004904b9845b186144a85194186ddc92040a4904a00811c8b26c548645189544121685c04265c38860d4c42d61844d11b52c42228400b611241a129dcefb764c1653d46b842bdf5501ca1428a8af384c3016be82afe02e5a8c299790705b58a1f23e130b87ee9058545ca4762cc1fc1bbb0b5f9e7774e12c40cf09d64146aceb54d786746a48974aa907cdbe16dcdd77eaa11f1d6681e810144694fa949a4342b6b7511314bce155af629d90a93a3cd10a6b2ef2486634aa06121a8f1c1595e6e0350f470c0f44b37724e8bfa4773ff0c6d76d9a597d4fe2ee9f388ae8dd477beba96ea6be86e026468ef471e5135a5350d72e7f82d775eaf3d797c89ae0b90bcdeacb6752e775d7e90a3095cb725b5d6a82b994b439d0df25115cee06c9d0369f237684178860baa33fec3248860483389b8379e53c6eb16fbc8191603197c63f0419e9a98e833f4691229dcd5d94c71e37144efdbfd3a3d27e31d29d08abf2cf5ad55c3d93fe29650990f00859d0d2b6ab597246e7fb071a213c7c9e6090eb450a1e3fb1dc67c1f82fede9a3b84291930bd18975476dfa714ec3a2abad61a3bd4ec0210da3691d40aeac169ea03d9252fe7676d6d9262505e560796fa073a55f8c08b88e050dbcf80b813c55496045e2c8c45fa6da9248e18f5ddc1c3f1578a65eae7406d7cf41e67aff1e47520a1a208b6cb98fc3e6efb11c735287cc64dca777a4a9d269f40f77a99bff4bf40c18ff417b6ff9c4bc4927b0faabe301f6d98a52a9fefd655ae1f25d1d39d8a2963a8dcd54d3a9a6103d676727dae68e774ab301989f4d8f7ce36f0eaf5bbb736305ae2631e783799354d4124c75eb03973aefdbed89b6a91578eaf23a57cfcbafb9bd453320eb6e7dab046bd83629778226190ffab199abb162768975a6daac7a899d4586aaacc03497bf99e4ef318ec68e08d38b19d71a5c637941494fb428ac8273ac37b829bd8c9efb230e1c5925251f0f5e97913ae05ae2b9a94a06c3a3f50e720615766d2996625376d1c3837e587a9a6bfb7b22a52f1239d137dc5f82b4003a082e1afd13ec71f0177ffb29b6c7ca1d029a848a7a51615dfd49f1238ab7ecd99a4c247c6521136f713bd607b64d688e028ff223f4abce8ba86ccf2e467819556f7ca046046c3745211de9619087cfaced23db4d37c4d01756df82f3b2abe99ba612d222e5c013eeb0b75b4bbd55bf94201cacb7c6c661eefa52fbd8a1fd06567695a07fb596b13222141f7ffc72cf791d5773dcf847749859c27aaa4b5704c3b92031af9f527076dda5f45de8ab53bd023c3816478325782cb71b5d17335e235cd6386a816a10a7ed30f8dd9137cd5f66e76b6fd8862a8dedd5e6c388dfc4f73d060c6a19a6bb792ec2ef5f96fc5e470fc3d3895188dd051e59f43094ee61fde3f7b98ba1bb22debdf26acceb87ddaa01363f81beeec856ef25902a3692d0f46b3a37ea4c47a72aac18d77f3417a901de6e5b5117ac810017c280c37c8e0f19b157d84087ea8f74e817a1c647c699fb8ee25c473c8932cf723ac4df3d96475cc77fefc54ff6cdd8490519c97328abb27bf387c78274c42bf6beb338e07dbf954f37da0964a36bdd7740a93eb2a15b553e0879bf08ffef6f48a6983d3a419bab890f0fe797ff96aea354fdd4720aa4a80d81f58ce31039c4176dd6894f19ad915bc52645f4098c6a99306e9f842ee21e735a4092ea05fca13d63c6d41c9d799965124946dfde3108f45334af1daadff53ad649654c176d3d1239c7433da7a383b09d335b1219cabfa72faf74aa4c9ace7d7c35e3ef24283fbc33d52d9f9ae369edd9ba948c6a6e0c8ff652c5dd3249ba4ee9190548df9d44553ea48fc35521eaa19e5067015ffff30bdce2378c22493d4ab73678173a68f5c28e9b3b08de6ca1ad3feb47ae9b95708ad2abb571099faa68c92d2f64af1d3ac55301e71ceed47c9c21738397cfb834b6441ec1b1ae9a96f326590867cde1375634f74a42b5fe376a1856d9d3b4370407d99edfe986235f62e8862a4b2c25d37f15aa1ef6420fb7a9c41f1fc59e9e621084e8babeb2164dfbd0c8c27de2c938896dc918afabae6af451e53fe3478e41a9fd95a339bb010fa98353e5f17e07fe1581386b0d860991d1b3ce8be86c9eb0f6dda114448f42bffa2467a4ce338ee2e41d5fda6af91a333345d904a8ac8d1f9cad18f06a23b02d32c480fabd9982adee870acae3fc0b018bfeda93b163255814cb7a874ae669070ada5a9ba584baa3737d7729ea50d233c7e4a002ba3a5feb7b738fe176193a628f165204fd147b1f8d48c39122cc2987eed7f5f059c176836a28333fd5cdc1547a62e647e17c29e9f5e55c7707211dabde4983ea5dc9b6fdc600fcb8e522953d2bc3ac7d14c3bdcf1bd2ffb62db49c0c756875016adf31909e9c7a409279cf074e230267a7c30d07cba46652e6209e3be8a970af8c8ba6e0abfe8fa53340f06ab556be351cdb6df4f88a892a569a54bd3ecd71391094f2805f6c97e2c4dd8ef01caa44aa0bbf01e5f6b96c37c6f59f2aa8abae86cbbb01ab64afedf832772897ceee3c1a8676c25eb2d306ede14b53dc4b131201196c6eaaf52e5ccc1e38c904fd00951fc0f5368792841384091d47ca81b2f9b15c5efdf13524e97101911f89ac3065dd6888253f9bc6a13464c822791a240f1867dd92a43bd5f2407cd2c85bebcae207acd4e18630dee496a926184757eb76d6567e2be02f8e1260f4b996d689bbefa840f69bb410393e6eb1dafd44d9e9b5d16df766ec1acfc36c7cb0393343d266b1f1038c7a93e96912f5ab45c4152f5c41e5146f94d363bf7507ce873a9e3aae23f2507c5593cd3aba4329b9cc282f51a25fb50e6a8c87911f36d7e249603fd8aeeb7075839b4cf6dd2a39d19bc4d6a3e7c1864d682700d70972fcb47d614df7697685ed768bea835dba162c720c2f4edf2e6be50af9b198cb46ac8791a4b86e8c677a572ec142cfc8aacc8fdc655654c4afa8fdafb3bda9bc8c9d719b9b47da3073ffe1de8e60621c4e98372252673abf4dcddd2a48b9c431ddd3fa156c16fac044dad53e30bc38bd58d7f36a9751161acbaa04861a3fcdb3a3b6d92217f9d43f093198de2ba201d3fafe8f8b9501ec822335d3e38ddfe2f85259d29df67d6a6b54a4ce9b42950d4879db4d5e2fc8619ec15737f2a986ce120160fe68100eb4997aea3531948031445f0f0c1047fdb41e09440bf5655e1a72becc30369ec37729967fe08e75c6bbe07d7a9e25016540f3a1902dab57d8ac90fc4ffe079e0c4e42f9ce69b201f878e0b63a85702ae51a27a0fa5ac968eaf676e2759bfeeadadab6b70cb54510b8d0c5d9fcfecdb5047cd333872d5754b3018b5cca68d78114bac87d37bb3afa465e3e7dea2cc023b56e729d7df130c9161911ed1d56e5eb8617596dc4c1e167f4a976d63339bd444c31362716554c7072c65f483a3bc44e93b3ab41f177dc20cf32550b7346d42d28421b23eea1a3b2c38738ce9803996369b3dc44b5042ab7ee5faba539c208e65562757242dcb1b9dc34c453be1869fd575b3b32336beadc238a3486e9fb9f2c13c3c4688928397224e06294302d158eac9405b11f607020d8f410410460b2b54c4612dd992daaae186d130d2cd6cb59b3db055449d4293d0ec7459f99a5c89a6bbda86956b28b372f2e4b330b07bf280d2b498c785597536fad5c3e5bd2ea1061f036ad4df26dd7a19e3a5ffbb61831761b622877b0b61fff288d340a5bd9e67b32a3b1a182f2334273ff29ddc92c9af073280659c5180cc38eccd73417ddd1250ad04b7c241e41c993518dbbc9adeb525b102fa52d6c5c82da07d09364e14b2722eba04681408056e10c3cb95d68905ac63512c66da44186edee4db51d2ead4af3ba930ce11bfcf316b007a3eaaecb36f99aafa98f9eb58aa4be48afb11bd9ba5bb0c11ed31f2f221766204796aa21a6be78afeeb2bc239602be1c4c5d37643ed6847b3396a3e3f541493a6d038531b08d3ff3bc9b0bae0d686612a19c8786af55f744afbd0400f79381a4949a4918f9dfa67e7428b7449edcb13ae371fdbcce79a2e09d5e43f8f89511ec74482885bd2606fc5a50c46a57ff5f9fa416dc163e47e5e55de6e15e91c1ec9da4c424fbc7491c5863affbc4ff8a3e70640a4a200c8c332fbd6438adcdd402bde5cd2ca3f44365aa1b5bf6a4acb87f953521bd04c4dfcaa108726a9143338ea67a60543a383c2d95c6810e96f75202cc13664fc60df2e278aa81dc7309cae1c0bab58ec267e39dfc01ba3de9af0713d2c7882a6787b5d2cec943a5925449b912b5e5f9f2ceebdc723c375ca5fdbe49af7fcb5546bf3c741e1e1decd8f537a9aa7f351646807e6b6f2476913c1868245a1bd0a8421869feb3bf7db2d19151a7e918a0aed4ebbb3199e3fd7af74117f51900969466814323ed64a3aa9c817178c1a6d7dbc465bd2301d9e6f9878fca977dd82411807a747f5f33c4d4ab5e7bd6cf3d361292c7fe43ee50bf40ba8597a725333bc4505fdc08629feecad7eab499f6ee6fd3033986779920c7056fc7f8c01223efd7c5bc52d65a51c5d3fd5d96db44ef6650a26ddaa20bba2565d753e5667c4e883643c02dd5b7b62cd590ed41a2a970642c3be4c427347539e4b19e8a8ce898d014caac039cb822cf49bb225ff4ad402827e7784570ad6f5a99be49c167de94cd81a3acb72be029b50c072b03906c0e88e26b631034c9279fa87bf75a1ec57f87f5af302fc0cdb272"""), - TestUtils.hexDecode(""" -701B8AE25CD8187095349A4D41A067D4FD48732E62547E491D38845B3507A7A6AD8F8AFC53D139E47FC5AF2723B1BB057FC797519AC93CFB18DEB496BD9735455CBDFFFCA5E69C95990EF89F509728D1CE41F36A4C0364AC8C30E3EF67D3F3776400BF4C838A477231E455FF76C92CFCCE1B69B00F99451B0A8287ED59CD79EF0D6E697C93F7ED38F20204921E6E2F141D3DBDE1C201E5CE7C524370C339753676746DA5DE4A398CFC2CB1F568C16D4DF34A27CF04F0637B1447C6CC83E965A3F86C538CBC235E440CC2D1257CF916421EC75928DD6DA3CA002AC93C8F464ECD522EEF7E048C154D73053DA7BB63A5DD845512D2B6B7D1E7EB5818D170D14A4A698C8922D69A98319A10E0AF558E2318FC390ED990B75ADB50C6199DBEAF5D53B49235DE7CA116932EA38A109322AD05F5D681CE25FFDC9F6A05C4ED2EC6D4242173D2039318EF7D0733D86D57C4E114B3476392D47FC68796C9F66B1F1EC70610E1D57436614D5969564DEB8673686170E40BF5CDE506F7E70964E07258D4551F5EE0BF2651F8BF3D3177DA76AE90FAAA69C4F373E664F0A1FCC62F208A8BE130C499166D13CB34D77FDB32D5A7F3AD38856BFD3A0419B8744DD2F186D03E18634D826A5BC87F1566FEF88D9ED93E74ED4C005EA3EE2EB22FF5DEED283132D00C7A0B131BE1FA38E30EEC68B748AD533BFB23B9A14A936F609D4C560163235367B0D64C2C796F1106A1A9365E8F507B4BE0514C849A81E2C7388C8AF300D98D444BF808C4F9338C47A853222D5AA8ED283F57DBF0689E5FB89A456005B6B95AC3D791077C79BAA2BB42B423F93A7D0D999241AC5B9D64D65274817F9BEFCEFBCB4D5CAA67427F69ECB279553EF0D33A19E14FD4B284A72081F949FBE2A7543497F314CD7496EEE866F33102BEE5CF9C706426EF2365EFDF1AD141552BE65D1DB4373B0E8D449F3FD1733AA164C1F2C24F74E240C5096CD201A11113D6BF5CA19595C4B0A81E1153A4EBF88F38F1812BE517158787F2B378E8E32C9F97432BC9027292E5EDD7DA64FC6A32788154B62E40A85701895E13287BB18883820DBDD7647AE4EE1FC1D43C199EE69B1A2E2A7067AFAC541A8F44E660B2A7C114F402E2054DA7ACC41DDDEDFD7291CD4573DA22739C7785EFC2240B27A90BFCAFD1AFAB6C2B0EF5509D0DDF349C173E9A6C906BAF5692C39F6E0D1442F84AD2FC118A14B12C3AD5DF8A79056017F4FDD76603717B080E3AE560D7A601EE7FCAA36DF7289AEEA59EDD0B73BE91782377150F03C2C2ED40F33A250356CA17E153480A7E848F090DDA29C65FBBFB495FE9B7A2BEE342C7D422F28631A8C9CF643DC76F07F162DA1AD3F24589971032796BCDCD262F55A8C34FFCE05FA9DC001FB35D6FEE75B42DB6DDD2138C0517D003512F0EA8E982C2ADB5E5BC1F19B8ECE67E4AA1681383A97976B6A8F2025EA80B1BFA1796C27F6A54C583711E2EA46D85C515EAAD22ECFD68C5D02853D688302704EAC4863DB1FC69F8C35411EC6F4A9F0A7E7B3385ACF6DF805447BFE863181A945E8E7944770340496F5A19CB7DBD0D9010B7EEA3C585926408FD40F245D852DD208EA97CDAB0C16C1EF80B3E5BE77D953A04C1B6F53A23080B54F439705E417B9874B3FB524794D26DE3DDE88E9DB9FC36B1508754EB51D389FCC46F822F50FCE199DC14E4B4468B8B15A2460EAD05D0C47668C05A2315748897AF99D320E70F2AEB96936D7D739F72ABAA6960DA6A3996988F6A3F7AE7772D49915753B936367E022179E69B6853E1A83B429B42BE19EE03520A5666124B657D2FD6D15447AEEE45AB1FF4593DE9A2E6D152C64DF45C1F62AB9B67257B2A2115D224850A3AB2FA028F8F9FDE7C9A9FBA2FD291346037A1B4E00B0642B07ED54BFD70F3DCA3D1B8628627859611006DB2DD17A351751F85C60028DCF21481291526B1DEEA4C7CD2D3230653E6FEA1DDBDFE1BC3DA93FBFCDC5A405975A5DC68DA0D8338EFBD6CCDA1F2374D72FBE007599E81CF7D5C37985EA09C561A1EC40A70784FC606FB7C3FCD981F112C599C78B15B7739AF4DE129D489336BFD3966C10363A60E749162D1D8311C5E850B22910B999080DFC86D1787C35768CD5470E9F7A51D4EEBA71241DB57021D6569ED2BF201C06E235D6621B292B686D23E29DA4E81C873371593CB07B3DE46E91FAA3D4A2AA6F62FBF6BBF1954647E731AF4B99EEB3C0FA6385699F8EF2D8E1D7F75161129A1C7F8C7C68B906EAB8DAE8BBB3541FBC65F36BB67ECF19EBEF54BFC2EC4E1130A2E4F36B5644A73CB0E244738B6E5788A4B4457291B57F1FDAD2C11FE5C7DCFD4E742A0AECC460BB660D7BFDDEE4CEA074958AB94B6FA4CCEFE02FC7001D3A2CD013684A1ECC2E2F6D90D246726EFFFA99C12D1FE4AD10A6BE38D70AE3DE5C4843FE6CCEEF587191B56F666C1662F5C6FB03955C557E1B4CE247A2806DE39EC40CF8B97835EB0E3F2D829E0FEA02FE60C934FE72A25930FD6692B9ED979F14536F406F04C3CF0BE98647A5967B81DFAC353A2F8236FE147BFD7D3731C49476C3191981C9AF239AE8C72570C6C53E7AADD48E721E623D6CF11A1E386EA7C30F070E7AC4F63FB42AB74881BFA3FF3E8A35EBEF04D39B853DDE0FB17DD9DAE37A76C96FF55F64669CD9521DA3900B7CB297E813521239D87703CA395CDC8D8CC4EC21CB10A1C672493E013EAC0298F8076C8E0B56AFDF9C31EA01CBC1BDA4AE17FE103C9812E940A34EB321BE7BB288CF8BE7017AA58AD528C9DE09E269B10C6FBFBA5E8B6883FE7E08A0D184F8561FE3F43582CA045DC25CABA52C0157495410382A048BA67D051EA115D867D780CDE5EF512BCDD14489C43604F86D929F83D118B905C63BFF451FF3540E9E220851A402BEA0DB1A7CD94DE0407AEB9CF862BFA3FA703924D0A4803C463AAA827A04B0F09556054F27DB98E22A96D07F81662E0E910836B9423968C3F002E605BB688720FA7CF3167140BC21398B5E4968804F3C3065FAF125BB6D887C869FE3FCC27D88E048FFD0925E748C096C74BFB1E54A8FF6E2C838F16769FA4D8564E5CCC58DAE3B102EA300361EF89EEC689FB5BB0DE16C5CA98A60B8990EEC0006A147036871FC2A6ACFC6A6EC907D28E18A76560A5436BBF9353789C8A5DFE559FCD68C117066EEE5B00F349D6591E104295E78F445FCDD3D6883DF50D1DA6A04541C7E8171523FF36A9C072164147D14985BA30FD449667B580D73B06A5971B720A8B1D2A6896FDC5E4D4DAC78353ADC3449AA53919AAD15EF250AE12E9E40B8487F66AEF0B15E42BF34AA816F559062EEA24EBB01BA369747B29404DC1F1108DEAD021898298E72F4BC1DD821E4C88329D6F03F971F554A87FEC87F34430ECD1CCC6627D8CA49EEE1D5DA6704CE960021C847DAEC2DD544D4EAD2E2086058CF131296B7F4FA4B71A1DC6D6C642A256AE0C0EF9D1211EFA3845B12243BFBCB4F423E913A2976C1015569ECCBC159AFE70F1EDDC3AFAAFDA45CC02EB60BA0DB9EA83EC604113479BE848F381FC63C63B3111DC5179A637E0832A26EA32555908D79B308351CB104C43668371DB32056BB63540B9C3E5551A063D2B525F8A016BBACEB402CE7D7072CB9F37CEC13E1EAF7D867534C013D78B9DFE01C13DDCEC7A3444AFF9E182F12B6901CD9A70F21908FE692E4C0536B069C89685BFA9D973983AA8C1DA461D18ABD27A6A717D9F2122BEAA9BB1742622F51FF616FA2EC3A6D4724A3A9215D7B29A1BA372282CCF60DE90B3834FADE6E3743AD6B2F9B7344F45A29740DD7DB2D642F94998579A5DCCD2EFCD2F7D08486BB327B844EB19ACE3B4FB0D85F8A24FACBF318C98199A0B2C7FC2CCA59AE84A522890E22C2A7207CE91623362C7DD8E9F946817C75B71FB9654E2B7F2E83E46E75ED5638741E414D7F8E70914315F0E37B5B4E3E1CFA8288B1724113E4A00B59B7764C2D61443537849E77083FD13BA652001F39DD9BD4B20AB77CB945C5EBE686A0627ECC52F38A852BC9E1AC8D303E3B96D9D086920A19E5088054DECA635E802385600F673D3BD0A5CBE7A5B9BA8B1C4B73B9246C1A1C1071E5F98ED42041037FAB67184C89BF4FFE3CA0AE2A9BCB020F390F0B76DE2B8AADBC99268D3A1D467A024184CC9A455A8F2FF287A4C9DD1B0C86C8E176BB15B12023B291D44E7FF0C44577F7A6D788D82A75C68C9F5BBE504E7D64FD2AD18BE209E85C45627FC045BC81E3531A2B886173F3C3029D1FA98C792501A4942C72A7A892232F390CCBFD7863AC38D837755011F919AD8934742D0795523E6D48A958BACB9A9F7B9A5A9D914C37114CB111CB536EED3D753D6333219EC993AA5D39BF74E8E9FA02D8BEFF369EDAEC67A5CBD128FC9BA6F82E31A4C59D783A99912C7C389EC708824AC7FF05D56BA6D228C0A9D96324C6D9725E3BE17C44CAC7C4D49235BD15384F95345DC36519466A13110A58300F7E3362295DD7069DC6A88B542F2BC5C9F33328D9D8D1683902C025427F32FD562BE3F0680FA05851296E15C5FC67E96BAC924407AE6BE37E9B61D9A6383FFBDC6E77CC0887726C474AD735BC50039AEC665D827B0F6BCDF7EC87EA6BF793386F2A65C997545FB93F0D53737C53D00685DDC13960AF2632380F105840A1699ABE53999C568978ADAFBE21913193DD0844D89BD582418BF8B6BC430FF1FF7750AE8507495C14DF21A3437AFCA7DCEE7B1F1247C802081FC5ACE5B125AB2BF11ABAC97E201EEC2A8C90ADED920728EE77E1FE2BF31A222A1CA5263586A16FCF80E582258654D0793B1551EA3C24C4EBD27C52956ABCE6ACD05FC2F088273FEE8ADA0256F30B5ADA8768D8E9B70279DF95AE5CC68FFA99934C7520E12F57D213FF18ECA6046A9A3F32E280044023220140E2485A3B3EF7778006B18D4A9DCD177D190CD903CAC1EE0897F58762299A0E026B8EEC6F4F3D0BE1F070C648A2D73869F22DDA21246CCFDEB7A9784AE967F0DD0A2011C637099AF33E0D608AA0A5B2103060CA1A6718328D451368EA3049FF60FB66FE54E778DABC48413966EA14E22083A884E8C8EC33F885093F01B5E34477745A9F82C645C8C5498306AB00B78684252ECD74C163BB8AF9B49AA03E244F4EFC4A2E7099074F512D465C84773DBD1FA96D26053230C192DB289A1596E60B96178DD8CDD72FF14B340FB5830696B393CA319649BA56DCD517F5A08A528350E2D9531B3AC187414FA6E06C0F05D9987BB2FC98F7C8D4F922B8AA45287FA83B900ECB6C9F02669063296F1EA389858F6D2E10228E136FAE35F21DA151EA7AAEC593E5948536B68BE58ABC57771AEB406A0C3F931E7DCF85A350A3558E5C1B1F70E6299EC9FF8B9CC13E905D9902FED957ABFD7D09FB84FF22BF8410D387BA85D8555A75F432EC5789498EA36CF235276176ED48D1E374DB5C2DD1A64714D64FD20D4FDE2A605034E4DF607EC6E11D0465DB25B9D79C83182384D64477C126E9B8558489F69AF29730B4D5650B9860326249777DFE9EA5669736692D0780E9BA346C1727138F5DDD4914487CF32A4E9CB1DDD5617B6B45CF8C981944684BBB7921C88F5A25120047BAF2D9346E220EA08AD168B30A1B82B3B63C4913C708C02258B6AEF1CAC96E2A90EF7D0E1EFC0BC5BBE05D286E143FC0CA4A23833CA12727F0F83079F7BA80D809D6C739EC4D0DD9CF75C4FE30B12A892096BC4B9167F16819694B2CD5DB4B80DE8DE988AD50677695C4FB3E0940913C250645333B6F55E36F649A43C3A39ECAA3DE3EC1FD4F9F65D9F7AAF75B60DCA3BD1EC06495FF5F1D4FD6D83CC6316E40BC469EE5F44E5AE56ADB229A7CA5CA37A1508531E44B0142B4330048350A40FC82279D25A87E043240B4BFA7321340502F0D37073DF068596C4753F8709BAA2A7264ADBCF5F934E857B3225CA47D8A182B80D3DF24C3612FE4931EED565BE563115414CC2B6BD102DC6BCA9F104CEC8B24BA5465FEBB7E9730C928D6FC1144224232A990F8BED27FE6D28AA35A91F90D6A0AFE9A7E37A5BAE51D8AFDEBB7D5670F2521095A56862354D2AD946663B4BBC7049ED1884347734BF3E78ED227428476F1070F4DB011F8DC86EDC5BAE1BEDC9C5D253E4C5C6816347EC96C5F62AA3298588625304118EC32DB2DE0597BF2056046E17C69EAECFD26475066AC54D40A673741BCE72F138DD98F1939598E5D94D565C1337D1179DA057D4453DEE27B5C04777EA710D77B317A6E8DD3B4F26A6A9B3F4917A0E881E5EE528462508DEC6762DE2BC3F8F8C42E8D721BFEF7583C99DFA4D1CB49DE2A303B67AFD505F8A3865D853BF19C4A0F7CFA92F5CB18CD5D8E378A5B041449EC9ECFB80E0865CEC1734D34BC44E664243AA8F605366CE9F849700593C76BE0CB19CA1255B074A8630FC962B50106CD93DB41C6E4DF53B6B1257872B0D8CE9AD5F245C3027A3F75F19DC568ED1E0F60CC20DE625241D300DCDC8C953676363868B680B471C2EE623DA408C7E030833DBAAEE8E701374156A6B785E0EC7D1A0A55A599605BCA0FB517EF99939889C862CD790240709BEE0226DC7E8177F641C747A151A89340A6CCFF6982EF39683325390DE72E4451BBA74E3CB102870F1E9ACED30BDBBEF160A49746A23C432C3ED7EEF580969110AA438D00AA03F54E039195D61B7840222AC994784EEEA538B7E830A6508AA0B460DA4B4C0DD9CB052CE6254774FB147F7E4F80214AF1FAE59F8ADA6509123438E90AC13FF7CE71AAEAEF7A39C434C3824D49B894C389CF320A430A7F84A5F4972FF98C388D61C936E453BB1A340528A9FA5F0B0DA9543275435E91B0F5560E95F9AE4EFCDECDE1584761F8F60F0280ABF40FC5834BFE456EF66AF66ECA1098DD49BA2CC4B12CA9CFE256FBEEC328D049BD6BD19E2358502672F029888DC3AF3350BC2EDF5C4E07D59DF8DB9C14B86F1FE384227953E98978997902C8F237C8BDF300A72248B3DDEFD52577BCC0F99F75B92BC056719243F7EE67932A2DECFB15B59C95B43E183BA3DAA41B97E177D03CA320A5FD5D7E5A88C4D54A8467B883E0CD5924912642A65F191DD4DC2B08DD28EC0AD2B1CDB86EEA3DBBF6D47754B1BF7036A0BE90CC3775D263A5BC688844BBB9B1D9296804176E17C55D6DB888C2BEDA3D546FC496EAC5243AB5D51686AF9B29BF6D4A138BECD49665458B816BB09848CC4318136E6B170BECA544E8ADC35D40DED979111B8B1D4577DE2FADE6A1D97F9E82E9D3F069F3287E559E99224C6494F36233453036DBA617088D619395518B4E6725125850B3121EA957E721244DF53FB343483D27E6C3A53224B38C11C1D64CBFCD7041A44836AA606D170A80E84BBC0973556B9E4B1BD776C6A0876D727BB0526809700A0EB318BED67843CE4A6BE2BC10FE9D8228A4C94D7A506760E580E8A0E544ECCB07DD0810D79443046951C72E017CEE5B2C959754D477D706C3E043298CAD200189F4390F59BA27B0099DC551673B5138AA654E054676BF30DC61CAFF444CA22EB32E5952A598C07AAAEDDB83B8B3789EEF97663ECBD33FE356DE981A24C29DD5217E14DFCA30C0109419D8765A061F747BFFC1E221D3ACC7FE239375A9548483543599C837F48EA189880278AB2E06EA44417EB945F20ACB464CC458E249A8969273A460F063C5FAA907E42C9EE304B27C85BF41FB170708969A2BFDEF37B97DB4A16BBFE07370039369D04D0A9155623AA390ABB75D47FE2394E4606759648954FECDF4554F660D3176AF33153A9D7B0A935753B11E6C7295B0FF5680A18A42ACE577981C500581F741CA23DFDDBF22EB6511E19C016EDC96DA545AD16D5EFB9A8F10C45D78E01C74E3552FFAF35CFA1BC0C3DF9D14C1BDA9D510FC7C7A755C71B5273CD7CAF3AF44AF066DCF18B1B7D6C0D546C9C0B0B1BBE88F512824CB8B512438ACBB23CAE1178DA05DD67DA6392649213805D680AA61D26092BC1B2CE50CECEB7541D7F10808DB2D4A6B12841C8B4B6C5519C8683C998A74AC3BC3CC44D81B606A9A3174929E4AF06E032A24E67E9C66885004F07D4775A6C66A8F42F94920749FF902A8F1C3BC5A1A35BFA24040EF3B7ECD05654CAB696D3323485EF855361DB57A65C5AA0B238DC551ABD6B4A8DA0EB987A82F56E5EF05CEBCB4155181BBC61C645B2A4FA8B316FC6C5B3BA12829E74899D0A42B42821094B57E6D221FFA108D5D0EDE9012A88A2BC361D90673BB3D19D6355B9239131B42FB3CE832DEEA6E4551BF6C6533CD8DE572ED3E5DC51BC1ADA13C0C7E4F723CB964125DA08E0D08F1CFAE124568DE55E2B39B1475DC8F6558ED763FD7EC2DE373F4C54399A0317087630AED2A64BF13D113E8AC32E6318EB7BC0DE20E846C0CACD876F47CBF79DB6FCDFAB75B371156CF74B443E8DACBEAF94203037BA14E821A66244BBB7E989567D176FED12AD0BACF79834D067662C11422631554D1ACD6BCCBE23BF1D0C042C1CACA4B9BD01D6C5757E52877FB5DFC92161C8BB15A60222D12CEEE973812B4920B38547304E720AE246FB503C9F97BBA79640485624DFA2F4D508300BB80C70CF8E271770876062AA1EE0F548F6F7D95CFAA17FF1FAD847CBF6CF90B01D29C33B43473379F4B5491532432F6CAB98C365B84D357B48B416C2A00B25D07594ED4E4CA0E1BA5C92AA2F1DC7A6109AE8D71B9F06440A770FDC2501900B9EE466DDD853CA5482B4636BFD58AD8B24D91852ABAA0A37536D4118A122951DC78F02DDA8EC8029ED938125D759B24C90B0FEBA1F589AA1C10FC9597CB7E703D93AC4AFA43D3C239337AA454BCC471CC6BECF89266F588C3EA71AE50F146097D9CCF21E75790A5F3A252977E4D848DCF5D96DDD4FC1D0CB583A28AF9D7648BDAF8F1E94A83CF5349B1F4AF63AB1C66757B75C58D10F27F8619A5A6BADA67E841B6429AB40A09451313EED76B93166B3A5D5561CFB6421D83A5E343C8D277389950328A1646C3DAED357BCF2E8615695D7E8922030148844058D177D4E68A8EE31D5D810C73D9B38F6863083A8266652DB82A43615A45E6D14EFDF00A4333404DB65194EB432187C1EA7C48F819C34E48EBCB0836C84534A238C42E0B9BADFBB15B220DD0BF40F8C0511BA69EF82FA57D099BA84EE4AB6FC422442C3BE1E8DD910B4117BF4047D49419FCD2380966F665001FE4793F06F272E14E1893D502BD3343AFF5EE94A58CEE04E745E72E51124AE8013EAF2C2141012FAC54CD25E97B6FD3F0891BA1DE663EBF009A7008222F461B4E7D50628133DCCBA7CD0AE44BFE9F675E094D972D896551A1205FFE0CA8FCB739192488D2BDDD4E10493B43C7EFEF60888CB11ED68F34630623206E81ED04D300C2C43B6F27E41F18241651FC6B84C19EE1EB018BFD7A0D4483B0B6DCF57236AB27BF4CA17E52739E4D1C508C78F6B6E9FD53F423AFFAB01F75A9B1AB725C247492DAE3227ECEE2D60EB186BD8972FE455C393919E6D9760AD1BB706138824FC3C9EA0F673C1323366DEAFD260591DAE60AEA2DC22FFE5EA2421F35920550C0FBD78C4F6469092F89FB6908457BC81A175D75B1F97E2750194E68705B9D1E9F762068EE2FA9286BCCD3ABE98007AD1AB27AD2A094C6E164C5BBF88CD4C5F325E4E91FE2867A94E9FE1A78DAE2ED1C11CB4D365EC2F3888612FF58B493268645BE9ED69C196857F8C995A42D5CF4542E609BB35B0BB1B4BB85295ADE635E8FA237C5DF471B8CAD7E98420077BF1DBF6DCDCC1322C8BE1B8DD5E228B6E6E04ADA1D533B0C6221FA83BE7C19273F9AADADE041CEAE389D0572D2317906005BFAA17940026CCBAFAF8C7A4BBFCE30EDBF4EF82902E181B41A1FC006AC01BE64CF6E4A4A14FED995D6F323405242BCC5797E43276ADFBA44EB8E3EEC029292D2DCDC8E6C93AA6C02766308CD367D3"""), - TestUtils.hexDecode(""" -16c069f82e6f6efe9eb825ae1b6e908e32c28e3b0ffc443e9472356bb19fe58378012592c1afc414e0ff970a13a9b8cb51b968a7ba9a2f7d0c326b5e1d074f5af742c2b548f87b8cf1baf45f86000801486773a4240372f8f1c05e0e9ceb1bf5f18556c62765cd06c472781f73f6c766b44c2f94e436eaedf8612cd1fe381e645689cb6e7befaf031823029f5a6d8913e2245fec9159995956825ee81fd66ecac65d960506f2b3f58aa4e9a6606bae585205b351c5654b9ff455b08aa9ac45ad3b20e7619a3383913defcc42c0d25acb6aa2f3d4e17e4febb6dcb59c31e853fc5db50770059aa70d8d3c58d3b98efea00f9756260d843cfda0c079fbbd4933ff8512ea6e379b7b1b92ed4146cd0135b2c8ac61496cc70b55de5eff005a310eaf50ea88666e342850ec6c22d2d5cfdeaeea40321c8278e341b8422bafdfe71b42cd3483d71df4c1ac8bb0c86a72480055d272dff99203919fc2a7836adc985befb8025e6e491957159183949343d316004c075332466101f14aa78296cba1072799d978c1b36e94f042eec38b989e0c7e40db362fbccdbdb56236397435b65b12cce3f13bf55abc805973dde8f9c65157c3a3751209afd01396ebd7bb20fc16229ab289848c1aa48f5bf86791468df8950ebb317d72c050270f275cc219faad9980c69c377679c4e137810813734726ec78ce545199e43552ed33ab3689b6ac18fc54fe847af97fff3e2d6fd2bd6885fb675278c4d897b507d37b5cd1eb291d6195c03b5beaecfd90244a497c69345f70a118f88ed8568386b1af2bd23c9d0f2763c19b669a7378c42942a242c3721c59a5c0390137077ab10d792e2670da72dcae6042778d691ed96dbe126c2ac03e6f5a71eb1cc363997ce106c6111e3ddf50da12a23447af30d684548536c2402b60b75805cd0a8ff2ce7b4d7863a0baffd5c0b98df8dbe6fecdc37b2c882027f0d5b78ba3bc35a352d419978bee8f39faf096d31196590c415044500140e8ca976340496f084eef29a1a1fdd8df215da732f37e140aa48aaa393e5d3af9b266f98f5ed1410c9b4c88936f1e2b225a6e1c99ee9ddb7aab09b55be15aff94d2f43a8ba09d673b5d1327ea95f42fd26b4e13cd02a6a26c0d20fca8dbea95e71a9d9b6ce80fce8c7c0cf0ccea591916e4b9eceb3b42645615a40fd063d1e0c7753211ffca88a67b3029d6f7e387b11ca34d5357df38f5d92042b2f9a7d8d27ef6c8ebbce9377568cdbdb146d2e15858cd7133b5cf242406a857e4247462d87994959ab3b350cbdbe521f81b9375ee660b53eb534195a7cb0751c54f3af3ba72ef2cb3aa6c748270a64b17685d046641c20156575846e42b93fb1c754140ed6a6a02df039cffd970c21349e2bbcb6323815f1849d38052e6bb143d11890518da4a213434b820c79994586638b70d6c006acd43e43a79821478bba9ec09f9442fb15308d01f533c460b70a28c710da2b3f4ac7449129081081c4c87a241ab2f9483add71974846a3f32c3c96a08ad090098f38021fdfeaf50a36261c728aa6395b2114a88cf9577793cc7bfe45a7e238b997bd35b2ffb0c3992f188de916f7c004c5f83da5aac274a47bb7348df3590668efe9c2503b2c316dc074262fe874ea700b93a9d2545ad3e22b395d294bca1a2b5615d259744c56cd3d736be2c4624a1302cd31ef33f75373d2bf8b22a9e85db1df34ea4d24f0593cf9d494ede243517e2618dd0a6bbd0ff46987995805ccc3439e39babab22a53893223e25eff5276ff7a5eaffb88fdd248f3b2a4936ae56bfac6d778126930b25f05bbf031fb0574aaa129e4614eb1a38171e9d19b7fa0ca5fe7b4860ae3447bf2de8a89b8d0e85c7e130bdeb0f40e6326b1167f744e2b664e370f8a9d31f662364f442f1cda1da1f9437ae6255367e242253a325de08f6a12774612997a2f8b2a6a6e084ba51a07947ee7f4eb68545594756582be6232224172439c1105f46da151fcf9ca328497f952151b38631f4797f6d6ba367ee502dac0b1c5f45137578a5fa947e311cc84b73c56f058a1265ca45c10423aa165f08c53bbbc7ea42309297f7f37a98d146c48a7cbb566e005b76ec243ce6f7b9231428cfc17eb4b1e0b8d3002628e3ed7bda600a5840d4c1b2fd97024bf2f9ed637b521e8e1645400a7037ce6db2bb696b604d6b5f4b40a9e4eb443517c00a5ac6c1859dd18b6fb772155f2d8be3099b638602bdb9e3941d31bbbba3cc52d7060f7b45416c9923ee3697caf14e7f51361051bcd540cda6a14a71cb62e033603bc9d58ecb39ade2144b13d1746f0de2d1742cb6b34d91917adb69634084e08b9b37dd2c62f55eb64ca81a60ab5b71bcafe2c42f9c8d9ce59e6be9c2f0019c3d96c6ab738cc9df2976f0b9c47579fcc2d72161317c541d5f7de0bdc19b6f7d3264db1079cf3deb1619fb6531aa0032b19d2cb2ccef9fd6c1149c12b701cf8387768c6eb004fa6bb876f7ec010abfcf631caa27cf36d30c1738d50e868214ff8989ad497d0b12ed2ae83be1772a531610e4698bd721630dc427f07bf6b4356d720f335ea66969d14b246b757ddd96d1607dcc72d9d36fb10f9a529056255b9f962ba7a02950a0b9c988fd381d801af73d7d9abdd842cac56a77c5e2a9ab91785ad17966a2fc31e42a663ac583488081c236d13b82b09933afc57e25847f8511b0cfcf472ca6b21898ae47ca8fe674a55f8737053ddcf963dce0568839660b47f2dfc9eaced787aab897d16cf1a1e969f4e5fff7a8ec5c3ca33b6047fccd8d32f4c3a61d2c69075e37640d9120330cdb9732ea9325e4fab3e94ed580fc5be75acfb14468fd12f6e4cf87a7ac340f990e33ee4e1d2cc48a793c8c480b59fcc4bec660d101fa1c61a50b423c16c09a29d2dfce1d2011d4e4cae986e4822090379c17ff077cf56d72478a9bd703c2ea037ee7419b8b4464388d3bcd5544d3a2ebf12be85917021388950c180f2b020ed1d6dcb3a7e0770c7c1f5a44030bb4076e568996c307182b103050bd43ae645aa96be787f1d82cdbd629220104bc5167c0a8b8436d828cd70d34c9ab0c039cdb0a1ef137783e92bd7eac1c995268ada3e1e8a494fb00c5d678f5b6010c8687b57bde36d001452b0a73912f6ad0f7076481210a975b44410fceacd0699fcf7c1489e42728ad705600cfe6c2267a9c7979274e73bc2aab80155fa561390cc9460a93f29c4db673b00dd95d5421b8c9ab003fa7b48f82fd6bfaa264f0debe6af3aae7716b66c5533c94bc595e646c38b004bfd638e261b14562ae061164db1716208f79e5ec5e457a9ec47d2b0b7b7b68a62c95de164217b7472fe600a52a3aac43775f267832bf98ee2112ca9db28be3e8a828bb1ac676178ed490e0d27fae273a7d1de1fbca15aabd065890467ad7d4648487c525bf1ded91ae1bd3a99c6c734d580c69895dff04f3409c2f7a3e0416b8a2c53c75dacaa8bc020c803ad12e8a48f850737fe8d88f08643bb6863ae7b23103b0037255cf87f27aecaa703db904d789c61147b8307928bb184bf94ea902f14032d3ab1d6d13066ef6dcfd80cbf155f68024fd9fe95ffa782b2de5c97e1027e7f794c4ad6a2c23e3b5c2de5289a1f96a4f549dd32e9e4cc07771da9d1c170a315ef9d6846bf10dc97c1ec7b748b5cdcecab920d93bcb5a706b23e70bda6ac80b8efc06eb3594e5edfa4326caf3afab8cbd479f5c689e86e20247a42e828e589d831a6f1b2eeaf747f903100540ae7d725b0e48a3d921c303e13cb2a3ab5f8cc20502b90ffbdd69cb42ec092cd2a24ae408436e77565084a7bc20742fe0983744d7c876b646b1385a383bec18fabda857b91088b8c7fdb5ac5591bfd8b4f5c8f880509d0b6a54ce45d15c639f3b818508c08e6ed4a37497b2080364ddf01465df73e2e91a7a9424b10ed9a6bf1f05bf559eced1d0b667c35885c43db657520609a3f55017f8ab363fd83ff7a88974aec48d9b359d25ac9e201302102b8e62ec176918449e7fb745ef5dfc03381237e259f4cf200714830b2ccc4925afed71a4b956d1bc55b9aacfd42aefd9d4815a6e1f6151fdc9379e34faf98911e2d5a64152c426c0e8f386e06a86190fd5aff238128a62f07e02934356511cfa2212cfe3df6d5c87cdef644e7a78b34a95dde40002d4fdb43243a2f33cd3bcbe00d3503451073c3b13bc772f98a579c72116f57f7bbd07f966bafea91fe80541acc19e4010723daf868ea6b5760e66d317090ae218f57ad67c2992b36e84d513052eceee456c29cf57b8336516148ce3835d6ca526913cce6acb9a6fa1e0ecbfd9f34609a6751367c07a6017a78e078f2627e9f7be020482731cb93e778728e0a35a7f5bb2d6c4c9e893f0f7581effe6881f645223b699367feb54b8bae06a68e025a9d8ff507efb1ee6a0b9a74b14d47c8c32a4188f98d9b359ad1dc9967d19aa737355356442e659db0097635fd03e6d2f629380a5a6394e28a13ff69f36ea8f0fc4b70d2d002500f988db49c8d4da0a71e720be07034ebb3389b2c75e3c6254a82e2e841ea0c99755dff1ae01e51367d4e02eecd304932510a947f948007414e2bac773d7359243b8bb9e973cd4a11f7e6406f450e42416ad0927b133e0767adf949efc3dcabd9b523dd92b63add6c12d211edda7dcc73deefa427ac96b72589ae0c9808e7bf62ac31ed8aa5bbbdb33db466bf8a33a7e3b170058b1cfe84c96eacf005ad0796aba2c994c375b79862fcb6cae4d13bad1dab2b838c657a55f85b988892f62c3581cf60f24478735c04288c1fa09896e7fccfe1a102daa51c24924ce9ea1ef8831c91d526a55ba7ef2149e0a5045d8362329b6e3487ce8a7f0c33a428149c55543bbaea26b533ac8103820d405138c17510970cf367b3e3a4c46822d10e05ed47ba4c3bcdd02eb7e4fd990da55a518761335f9d2efa6878f8d0e29b2704d3af11dec3f7a8c2fa9a7104e971ecdb7f18d93ad2a1ecdc8a4d1dcf8ccdd66608859438ed23e5179f6594c631103828dc2d9f8c784d2a4cff15c58084318c18571af7940cee704e9f3cd0bc758ae7cf9d70995f1f1422bdbd2bc441831aa72b66253be6ce186f6e93613f2d3888a555b578481ca324878518dd9537e5e1e7b27094dc5114a4e51a776fa8e5e86c556f45145cc3216569c17fe22bfe281579a6fd70334c574d1d7aa5fe461b3c0262830a2afd4b485d348babfe81a3418bacda574019077cfdcbef5de1e73c8a8bc3eb9113713b563da34073670cde452e84866d688ac9f691916bd443b02c8bf15c672e1e75b50156e1e5254fc23e0b0d6fa530435ae5fe06132d691a3e59489c7102aeec1ae9656aa334321b8f07aac206dc80cabc6b3c8aeae941438ff5cfbfc494fe08661ea496b7a81cfc949d60928251ba6217813140d050fa68c34dc58771b80b84e79f469442584db07c6b5ed39a5f83398965b715966a3ade89570b09a501860accccfe10aada86ae989bae9adc4ca7480916e1bd4733d6484959e4cd199086f413c17b61e16f42ad93a85ab8ee86e09fc1dff1087384ad087a6d95dd845e457f740e538faea88985df42fa2e0ad89c8885de6e0b1514cdfff9e86364dd37ae591a1843f60f71b8e8b6aedc3155ce76d1fd9c4a20d077050d7942e8369cfd9e0cbc19e62e32d15edd34b7f2645dc31c1de6ac3c36c5850d43a6c479e7680f02e23c8870c1730ad163dd31d38e1e7de492ffebab9f3366e85dc9ff42dbdd1eee8bf448abc8017a2bcee2367e958a01986fe9d7083e45e262595937e3287b499090d4ff466f52824b032428757eac7756ffe76ad43e6f70c98b4e0769ab91695a6ead1a1ed45ee36218dfbc4994b7e5227f0fa0536a9b73b01701d10f97d0c4b1bc9adfe7c2bda52e8e042b976a0ba1b9d988acacf9481831cf6881e70b21520cb0abfbca56bc3fde95dfc84de3b3aa9d4f598dc5aea2473ab0b2d9758b4bcf353c3fc2c6a7e487cdf1af90ba9b5a464539e788b86077ad0ef611a2910f784d72c75169ca095e14e4916c346e55cc1bf042b0d578d2923580709536adf49bbcbb7fee7d4c8a61fb39dcac21ee50f80a7bc76e82b285b0bc3f0b0fc9e70563e82ae65345d521a5ecbe211dc07acfc85f707c6d23326124eae586bf2fc77b6021630ccdb6dab8569b00374a1623f1a99138b870bc25d20911836d1aa907e9029436cf0d17dbc9bb350ecaed0bcbf4d48a4a7cb78e602e33d13f243347496765c40c8b786d8bd4ae6d9eb6ab879d4f56a004f9d6a3b6e98e2ab72296b546cc34abb697e7eceea1273f7d8658e60112932673e090be0c212d3d664237b91714d93edc6c86ec4a3c98731f7c102652015d58abca17b412ba07502d79ba43963dabc05bcff231d342951f36dbf8f8097e363595dcf7141215284cb4517474a85e0f0212c2e3c687d868794d51d1fa9b0cf102a62a3de0e2082848b90f31f203291b8bbbcd0eeff6b769095ebf9ff344ca7dee7eb000000000000000000000000000000000000000610151a212b3238""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -a01e3186a88928fad593837cd6f24d201ab8aa8cd445521805be6ad197e670b8119552cd53b89c7240f90d6338b72556b13b536a015192d33c5cd605381bbc81a8b98cc0eba107cd87de9f70329dd0fd02079212805b9160fc2a5a9a60d441e3ba26dddb791b77640f153b1b81f3e48274f1d040fbe3bbcac672adc977b3de8fcb26892097491c424624b08419936809c44980422d0bc52858c04d12246de036900b1552c92082e212294a1491d482006244014a884d5284810b928513c5042290485a462608c7086192118b88699ba621a1484823148ecc442e44189091b6090b4701d016901a036218a920a40622d0220611b18110164e8a022c9288410b2690d9882101118551803020392ad188245ba23113110ad4c808d0a281e404026246519b9889a3c068a2b6115a326208344a11c3895a982843940c03021121356c0a218accb24421c42900480aa2004990808002496513010d882011c1386520430644b22d00928c52224a00a8099c822881224020168d031166c49204012011e3104a044641598081414665d31422080788990884d9026588224610812c88462888c44511908014846180162041480a0aa3891c345023b1509c826508c1011c8485a1480502223123464c40304a11256e0312244cb88880226891b4801a21500c27840cc300c2c64082182e40a620589044e1a251c3166d5b964d98820404152180a0649a1862e43812a1b84d503005033989020324d9844514420d24a14424830488949101c22ca3067014284a89340458360c92267282968549482223c50980865040448d09812100048c08a24d021382849604003286c8424ec9464c1c308a193046a0828c18b62543420401c4205b90815b084d220268081405c1980022092c00a1114002819b967001b00520234911c6219092881b8410e1300881840d0a040091a445c99285011330d84850a0b6711888611038108c3472c40040a4326843b0610c186a000600c2a601dcb480240386a000058ab6440cc281182769134565131090c4101201498a10b10922a1511aa92cda28251a844d4a06715c3600198490e2941124176a94164c4212490b0765c1c80c2006240ab38954042c43422601434ce1c44d1ac450c1b040112141c3c461191531e4882c1b260d10118148084e238790caa04d01040d032284c9028d0cc05061a20d8b884082282141b6080c208d993640880229d1a66512c988832828e44022881031c1266554306d19231049804153882c1a9745db264813364dc13851442430dc886c00c349014306221008d296241b124a41128219c705c490898b16209aa06841b48022985059066501801160285101c1459994889b84800c02809c4482099661d4c45063a001e28869413870a1b42118144d90c848581846132966c1380060b41120008409326c442270443600184010e42692a124901a072adb125210498220379124c52c84c2840a3849e380410b2389092892d4a071a2b28000c511d4461151367010b08943088c6110720a014502002611b650d182250a24040383099c3091e39830d1b471818249d21680c44600a4c0209836488912851b920cc222660b302112050918b384193862dac229cc800c62c4681a990920962c10834de2842908222aa132821b09856132512015701b1484a440650b4790dcc8801a10311813404186808292494812698c2470981826a0886d14314602a36003289120098823062ad3268ce20451148970d3366c02a6681245454a3092a4186a5a90111b3864c2109191368e440882008344d2920c143149d4206659404d219444e3325190a0899a322d0cc530c010928c408000162413186c204872d8428404306e18a00cd4b24118c8701b22681b266821c9254c1288220091d4c009191950d8c6081111262388881cc8041125460aa8449c444588124ce4a42d03a311e4b88858928c18966c241521da887023264081100540946403a36864b00149b489dc26614ca440211342d2465214456c59224d0c052882b43159125121120844a049d040290cb270110711d932645b060620216089228c03a911caa464c42401029749c9205098483283b06c19290e61b24044a688448681593810411048c4c22149104591101010c6501a3940cab47120a22084802552b011422050424804d1808d0849324088044200081b804d9136922feecd418babb28c61376c9c351e1bc00c8a240f716116db00b6eccbfdbf5ef2f846486c0b7924448d1d803c741615efea5fcc8e10c6d62b9610bbb81ee811d7893c49735721a490539c6fc0fcbaa4e39437bcf193288a48dfd1a9c0904bc7ead823acfc3c3a8a0d794185088ee6f2d2c3d52c1ffe802dfc3c6e174cdcaf2e9157c43dd2a1ab564566458ba32e883df122b81139981cb3c39d0fbc5ef8d99976f3ca7da7774be9356083ee8a62cd1fb2cb75992485d99e06c3b80e730ae834ba0e9712b03b5043ec23ccff02818b633d08adbfbbca8c73fdc2e13987e7e41059992305dba7197107436c150f7d6d32d5287f9525fc223abacd6b738e5c9e0224f782d572cace63db70ad231c4b4f847813b83f7fc3bfa1773be383ff9ee5f2f4fb6cf285aa29c85f79354c5aebc52ef273a18906ff1c8090772ad99c2b36ac609ce4dadc7bdb5413da59318dc99467c2fa50824362f1d3a90b5687e0a538806c376b66c9c51279429bdf512a95aaf44a6a111d8965155138e204115830bbaed35e48f49a11a005b158d50d9817888aa6c5d0850975a2e83672653b4e96b3714dfd0e7ee462d9e102e68cde6b74a7c2db937139b45bb0a7a5cdec9c78c05c87b3911bc62793ba5b30be3ddcb8f53df6819a5c3caf15d5feffb2a9e604cd56565685cf1073c4a6a055d79f7611f0787a9f14c986fc3bd355aa2798d5b5a82e3455e372bf3a7c464b9df7f7b9afd3f79e897d2289ec7e671b31908dd6922fe5095e78a59295e11bfc99b439199ba20999d792a71bf6c89fd4bab83831a82867ff448a05153f0c08829c8f60651a0bcb758390596686dad84d89b1cbe0f5789b9927bebc1548da0469324aa11c78ff3f71b1ceee67a7b081fa27568e1a931a01c401e28fd054c2c9e06f77486cb1ca8d63f0f9005711391617a8a5492d84fea3bc6fce46bf4dbb35d0533fbf71b84724fa7d633c06855981f6fedf5d27c659d7db2d15c7f5f61bb3543df201e314d29433aa35ae101fb46ba5a72b6c222e5a5e953e3f057c5d8c0e2a22ffb01bc79353fd5d5078e66f110a4053c04a541e6bd274ec4e3d33bf93490564ee3c0fe3eabcaced466947472314fba5fa531cd49b94cd1924924d00503e681a280762f18c05b3e26fe8cb68b40ac0149e1fb912eae03101c763f7b3ff32dae52b9c5c7d616c6c0243536a6f1f5a2b9c68257f3f3f33c966c2892a42940b20a29cd52e418484ffb4f956023e464c60b762580208a340056aea262b14c70bcd5518071d514ab5899f9da5f06c4cb49df15d2bbf9c0da6f65842604861769fe51695bf0c37f986a6f71b75fa7799b24c1b7b04a6f3f5db7d9d3083c503d0a4d35470010cd06ec41e2dd8d071171ee1a3f55077f405b58be9a57e772583f35c4cdfc15cbac417ed746b8117d906df3374d41c48b892dddf227069a6d3e74547e8e197f1a52d4243f124b7505310916e02b3d12a9b67f9def13b19abc0b5047ba0ccff1f2ee7b4a45d820b70c365bdfa6c43affeec05a804f60b95743a40f89af27fc68655f0cde5275b4fc29de0f924d16ba08d1769f97c204773c1ce0024a75bada5480beea6118b9d0ca14b1ae13bc3bc1d5b5c3862738f912aefe10bd34a0f2d7ef421906741b7555a1b1e466f962178210826b67f96dcfe906fb42aa1562d228dec1c3602d1317f2fa064f687387bbc54def6d2ab3cf56c5eee183394e0aa3e9b713631023858156cd6e653dc0f7ac14a352e74777d610ccb627df440f9813f32037176a6d829da5d1e96798c4e11d593fb11703929bce06539f62c3a240ff8ca0afc48295b862181fe5f18561f8afec8d04cef4a21c4d722ef1f28a576c1d3b7ef34b2b929b7413a6cfe17d427a48cc63ecc57a6c319e29a680221dd170a09e5ca741931579159183ab153502131b526e64cb3d9dd2e54d97aa55592ffddd7579596a7c914cd4eb58206bae6ca45ae77fa10bf594551c8fe54e3d19ee186f16e9f4095ed00025f60b2d2eb5a51764220396dcb5eaab8579ea0d4758b0b50745ac6f3eff405abea6f79305a45fa60b3c0b985cba79237464487f42159dbaf40678a493995e2cad9b34077b82d121f5d4c09e43c4655cca7cd101f231352d49155c2048ef22668006cc6468c88d18e584e66bf20fbc8158f12da209d5b46004acc588ee5c57798be1c76e2ff042eef7fddad582181589c38e9bbfaf66178f23425582c4cb32847dd6a97d0c68c3090290c4f195308b98eddfdb785d9cbad02da8a75e91040067ea5b39a0ce35ddb8b335954613957d6e20d4c86517ab282fefd5215f3f67bcde507de19f7591eaab854183561e718bd6b5559548a843d695acaf1ee18627c01df6be8739ee0f613cea0715dbe08909698ec70ede5fbd3a2171ba7270f15283ccdd07532ed99fbddedf8e71a5be19af6901d9e6a3c8cf67f5625649c045fe83ceeab6ce4f7815c04196d9df019197637fca994fbd464b90577ee3c71112e48a308a82cd05748f1c8ccae603c5712ac9e3266c14e1fc6517b21d4b4aa0529848015e88fbf8f23791f8281bbd3b0a15f6857567858aaa1c09de9ff64a21bed7280fa3a8da10a00c1e2100c94e0407e44b5426902aaf628e164efee710488c8195d1c893bd45cbd663618596fb6d0177f4df8d1b33433d5f77a00fe9fdddabd3d244a674a59e307d7beeb0635b3b1a5a62c55ae5a517e1c866cb65a3ecf35140a5e196c5022bb8a453a3893bb706cc203d663da21c5f1fab533260ec6e89d0d0c489ff259c5843a318e9e84d1426c4552a8f3a021cf7e80d6983d9004ba0ad05be45e72e5982a9fc2d27537d63002006f828c984029ef9c68395c352791f26b6148523c107ca06a1c0dc8d7bf456523b172f8723a5fa87c2a67a9567fe88bde24287bc4aab8707bb1d0398b06d1102c008d563c7f20da9eec461a399e752ed46330a22cfb6b771207956225a6a2929127cd2b754ccf529ce917895bf163262f373d788ed13fd935c167ee9dc74bdf86d47d96f4f57514c12f5017ad536f7570272fe531327a44b5186814dcb358fa64b74f2deaab4e02a48678334d394911fdde0fe031f33719a38245891bc88251cc3b5f08c0c112311df85094cdf5ad8176dac30e14db04bf08e208571884b6c760262bff7699081fbe3fad6d6dbea91789718375b7ec126cd202ecce6f45a82e6b0366ca4b38e7babf1f4449a1ab10c24af43238d92daef68a306e291662f946ccee2213070be28c6309b60b71750323473bea788a3a62ebcf36a3f0e385f3a8d73bdfb23a11a25b3d9bb788640917174adb18992ba039ebb8952c9cdfadb09175cd9dc99161cd4226c428716cf286a4a46e690a7344a227abffd8a44c45245dfda6dbbbbbfc43f804964f18890d8598c65a8b2190dc64c63c11843c036fbf78f7d474c7cc4e6bb0061c7c895fa3be6f490394e43f2d3299790f0b4df8c95cbd613a6e4fd14c12f12a819944e9dc5ccafc923190cb81e4965b665a054fe8a31706bc946ad02c22ff82f2e907751ae7bd8d2bf79e89a33e06d64fa609449c7e961e36db8932e47136bc13fe765dfe6c14f10ad5868c6cd0e9e14360057488eb539616fd314681669554c783fc82764026aef71c6da8d2c2450273993dd0d754de43dda5e06903bb545e8a0cf40975b2d5854d00f3fab2de99443c3f3e47f6d2f1aa3c852966997ff83a28e63f72de52d77b59db23d6f8871eb9d003553185a970b7ec3d8ccb378251868decf460cb8e404316be05e401f205b9edfceb56a5e8d9a51c36ebb6d0daf0a825da082d71d49b0fe44d4e6b4d090c225484083abcf40d90762d601c3e9732a03baf44f4946ccd7d2a9a6336a401bd7b710d2925ea48c91d22954ed77027aee78afba4db204b33539c024f0ead4e511e74c8e02de35c3c0a76cb673bd74af6b9d953404b58bab7d1858259f71d3a95c48c5d8f37213b1a921bcd18061126b09596686233fc5261c811c5c027d760798aa529e0f4e38ac364066c4016600d7d627826f1390ca3dfa1977b4eb692592a7242de5c39394e9b6197190f71d86ae8e053e2e212593acff4563a05c60e8c74a6dc1a5b5971533b62f5be776add5901353633c0144b16c3ba55d7858bd9b10157f45651fadc369f6ee6014de59769b57b51c9c7ee4bf95111b96292349cec45d511be4936859844ea45da7b111d37ee78f7da498d0756d30fe337f3b37793d3561219d8809f425baeade422fc4af67b403a8cadffa25ae8a38babb6575b687e3b9c2a714958e9c3fb38200deaf1a49d9f74ffc5f6e4bbe7476f898c86ee7ec497efc4058ac272adac5df5fc8eac3c8313844ce4fb5a17c0c159094f00a64b78869f25fb8b459d56117758ada058009c51af5b0fe8b824929b4ee7237c8a7a78257253bc54187633a25bc9b5c6a826b2f5a904fe692d10b0dcdd5fa77da652b793c1c5b7374fe01cd8043247eefec7c35e96fcfaed4d69e87ce0efaffa9096e3fbda53fb48102306885519d424ee45d3d6af88f362c72e8dd51fd04e6c78849afcf45ac52dbe4273d229642f2ae715367a6365135be67cb68bf251538bf61af416e5dfe6816801a03324d23866be83817f1541b84126131165cad1ada28bcaafbc7f059c4c7ac8dfcd0a92612fa215aefde1861e1ce7ff10ea331019495e02e1c2e27f020ff7c805023f75b340"""), - TestUtils.hexDecode(""" -14A8B812B4C9129CED02A09C8AB19443D34DBCEE85AA12528B61F84A2AA9D9DA49011C8E2C3C3856FCF761EA9C9882FB18666F3EC2C8543037E54FEC1F0F944FED3D350CACADA9428B7FB7D9DA4937DA4D1859BEF8C6177F0EC93BD67FC3D5B3D13C34D472D01372246704DA4763FA73BBCEB0F4C3658B2111A7DDC01FCEAA9059FE3DD5BDF2A9FE0D1C2384E82926EB895AA529532FB20E12F1C61BCE208E48ECED036E4F84CD60F8042475749E13D8C3ABE0AE17967D5C6D8C598A53A10231929822FB01EA976A08BCC0D18B1F9B6C7C1ABDD15121E00EE80459E6EFD61CB8D5AF950F0A8FF2807C32CFF7A56661C67348617059D7E128A72C8AF36B149DD8B46537EDE60EB5DE8A16A93349883B73F7C4FB8CAFD01E0C9D7B1EBF6D7C9725651980E0DA598A6ED5114178E47EA4C6ECF870033A03F134461146717C8AEFCB8E8DB1ED4E286C68C7358FA105641EE3ED9B4A5D4826B31706CF0946C152A365B246DC036191613655B829ED1AF8044F5707C320EFA1126B90137EB05FC220F122AA990AB476EBB0BB3AFF5B92442A857F6808E144C60F4B5190794C411C705513BC32447D83B760E907E6FEED63FC0A60C0CCD01734AD55EE178E6BD6D4B8A238ECBE8E4F8A464C381F16F11BFE62DFFC5021FABEA941D24B81CFC3D0F07F00F902FC5042F95A81BB8B795907F8D6BEDB5E5C56D4B2A4353D0188A90C01D7B2781EEAF2BC3D3D58A6F6AD63DF7FD4D32ADBC5A7A2F81EE3F5B98E8052017868EE59D8DCCC0199A006FE4FF39699EECC82DBAA846AC60B51FAB6F456DE4357F5EA43FDCE4B57AED55F2F6EAE49199AE90F6CC4AAF662ACEC2724337AD7F9CF74AC990D3083FE384685A1E616B233752E31CC4FAEB8048EF77480CC849D3376464621E2BF48CBB55E1A7CAE855A216DF4A8D1AE4E4016958F5855FC395C53C23327403720271EFFDF1A90C44E93E74D71BA29D860679E877E410ADE48ABD0EFDECA426DA792271D813116ECC894D799369EA8094C328D7694E8CA47459F31F5065858252C1EEB1AC4750AEDDD327048894F7D79A1D64737EF6E8B93ADEB938C1EF31E38DD60E8B4174AE093697DE4207C7733D82B4FE92590358515D30264A408746AC252ECC0BC28A9C98BFCD76C75845E9611909B0089B571259D1D115EE0D5DC6BD6F3697E1289C4742CD99F97B5D3A22631E33A81734A5D2BD1FF4A819CD6A22A938D3F18AA90794C120F4BE7E14324E89EAD34820070F8160B140E8CD5D68378C081DADABB41D365663AF26C606940E08B20581F4E63AC6E68FB5A7EF5DF86047BAC502223AF08F6CD82E6ACDE60116593046B5CDBFE2411A3FE89C438A1E84CE6D1CD72CFD3E5F67C331E72754F6CF2BF921FDE2C6DD5481F20F509A6852AEBF55BFB4B52D1F8B3E397C9B147433198073049638DDEA7E21C2043C786C88E45E566B6A7E8742209F5ADBCD34FF26962E87CD235CA1052AC02E4BF75DAEE60A06B19A4B0A61A15D9651473DF8AAAC6DB951EB6E669FA5F89175DC1FD4D881D688C477D16CEFE809E623B2F2A996909C3E10CFEF756ECE8E93072AF27B87715953E0C48946DA8E893160CD351E48FFCC6847975621E5C75D5DBEBBFB79297AB368D13BA95308E3D576F1C54CCC1C4D5EF2A41BE63AEA2A9F9A27822ABFF58B06AD99515B97F260843DD2304C855184EFE96BF10420184CBA2CD3ABC38D11B7A74E4A9E40FC26CAF3A84BFE8794477335EB1F4C67ACC9513BDA5D8252E608D03C69D493F8876FFF25D39DCD71442707AF2681CC6D5E117BD24315B0FB5C9E8175CD42AEABF699B7B77C9A8918AB94518B48DEE1777EAD8F18709A824F277BC06CB67915A5A2508E18094B0ADD29FC7CD554D8671CFB47EED2F850FC84B1C0F27767B3052869B653BFFBECBF6D8077697D1F440019E3381FCB917F5C06008A04C8A88B4493698C1964E25A551B03805244570D0EB6999AF2BC467EA4732B460A40F7C2EDD2CBB07A2DFA99B4E5F4663A45F2774C1ACB0C8B965E1053E3AA140E973049714DD644CB9317D9B3252150CC9A525E8729ED4A9A7900B417875391F7BDCEE646B1009CA479A1295555759C5A7597A775A1D1CD8D870A71DA7ACE7CCC7D2F38B18BD66441D80068F76AC194FADB3ED5F4201F26F670621D254264A4D2A88426FA6077895B9BD794C8C84DEF942FC43F2FA115509429A939052200196CC921454A65C4BF1A6E871970A3409FB9773F356BC17E03EDDE8CBF2F91E7D2B548380967F756D36520009DA5032F20D8C8CAFCF4B561A4C2894CA13929DF2AFC2C1C9FC41968746433FACD66309D2A7FB5D90EBCE40ED1E80C12D07BCB075FED76DE423D9EE6B1C787E1039749A0E559B86C4079CCA1CA7E4A3EAACB300C453782071725F6E2DC0652DB5EBE7D1C16B6EE0078004ED1F49DF439107AED04A2E69F70A35057C36A307C8F5BC13FCEA76AA997DFD2E2E4B835677EE961234895BE9C9E7D1486C04ECDE36AF4F7075C0CED9A33C372C33F751C953A2096815D9B6186632D3CAC31AE6D0A931258014D6F88157ABEBEBA1C11B9CB2956253D4950F5B2F64476E4125848F27D9ED4F93035FB5F5DEFE2435E67DADA015F048A90EAA9780B983748CED6056D021D21F6FBCB1A2DE0C627F2D9015B3D9D35CA17C54B0FAF85D0C45A53DC2575E2CB54B9A5681FDB66C9D5A09A3F48DFF29B24E45BE82856C6C76F0B9680F7B666B22221E14DD8B22A15FFFDA1D666F4EC6ADB5B929C2804ED36077E1A39F166C777770124253ADDE6B77083ED159CCE35894597E7BF3DEDB346571C2BBF69AAA9ED133E94AC7E31F2C30AD079EB4B4452232D83E49B43DAB60BBD92673D90F187FA6F3859EEE1630D3A232B99F3F960E8BE49CCA0F1A519156D2D861F8B6C15FEA4C4635C23F2ABEFDE8589A45947D391CD1DC3439F965C6DBB5C5C9AD14192B3D784D1C78B3DF6719D5C474E02D471B9B857611E2FED83869BFE8A2A74493C25D39C78DB019BE93E3BE331131CE85C4586C0D40D676640405FE363646C2264DE6F64365F19F87A8C54C884703DD369FF52F65CD9179B8A09EB92C38C284E06B0537EE686D7BF3BD399FBA8E1703BE3236F8BA262E2C84D55EB1E1E55DC14780DBA04BC1106D98B05593F9164F1651809E8AFA0A04BB0B51F9FFD5062B495133B509A569845CBC3003BFE23A7D7ED433B70C2EAFF5FD898009CF1ECD9E9B6F37CD7794234A098CCC39EF078E3C152017CC73A19B811FAB4A2CEF721029F6200A4D1E4F9E95A0A758A7AFCFA047B6707CE048C3BEA6BC561D152AC4F161347C098F4F44AD92006090324757D73DC074F1E1D445A500AF5A92CBE19EF631D99FFF870C60BCA8515125EEC36D004F22FFB420F5CB01330315F00CECFEE3254E54A047A7FA3C7495E6ACD579A9159F667FCAC4C4448579E7A68148D5518EFE269E97D90D67CEEDC378657A45E9DA855EC55E7BFD0AC3E52DADAF76E800ECFA61F2BF532E7365C4FBC8CE882AB327961C6A48C24CF0F0E6F2C54D732BC9B592008F2E6C80F7EFA788AA6BEEF0B6AB7B21DA3F9D92ED8A8F5F3F4B1D1BED6F66B6BF3ED52E49715C07DBAFD67F4F253DE368619A306C513E645CB5F154F7823781EB3E15F38EE482757009E42CEEEC1530A0159D25F052F4D4326412CBE6CD11C0DCC56B6556DDF806868B83602671C96F81D8210842144757A36CD187EA0900F36A0A9DB85B9609C11DE03A38A9984003EBFDD4E7C07CCA7A7DC7FB5F9F16E6C0C32CF86774B46C56BFE2840D8EC51E9FCB719DD1CAC4206372126DC8EDC9A4A2EDC8FDC8370C7589CE9FABE0DF3C8CEA90E82944B8D489C0F52F73EA3E3BF56BC3644A1BB0AF88F4B556A554851593E5FCAB03E235670638E4AD77BF012AE074F331F67222899694CB5EABBF0D6E6E6CEF75151FAFE89DB9D66DA4464353526116B3C2F382825B11CAB3CBD221DDA588F4BA13548CF627B52478F47D9B61479730CD9CB3F6622702C9A115D69EC232CBEB3FA88AEB832EB266B855A98424B2E08A699453A891C89C45FED7BBA98D6E7A2179A24D41D201C4214444BFFE6D01A15CBE640C3C54458E8DEA5DED484FF7AA78541686C60F9FEE76D1A7ED1F5686A2EC1F0AA037E6CE38FF695DE0C17895C9326415840FEDC1675E9CF30B8C45F8EACA1E65DD18290E8ED826738876FE8B69DC3432174151C051FD23CA4675A75E73F1D3DE4CE172FD657B57D5D03FBF8B29E268B3EBB8E9BEA96A4750168E8AE5AEF6B34701276DD18F1FEB01FFFA2A984D3A59D05A56552639D506BAB3021D507D56D0FBD80DC582B3C20940DF2393AF24FA5233DF073C7FF28B54C7A921949960CB2593AA4F93A06D38D896D547B28E9CAFDB479B7D1BA2EA7B4A6BAD33BA8B59DF8792B22F5FFF41EDB1FAA926FA3CF602FA63ACED78E85DD7C3094ED48D1F3381BCD084A9909613873513657879AD8599403A52ED0D16AF0B3B43C672867700167323D37FD6373C4D51B90327F4981A897CD54C8E35A6A5904F5AE0CDE36440393A59119437016E8CC88894B2A6FF661C10AAD7C7B03B7085B70A8145C305D5E66CAA265AB42B34539CFCC9A62B5D9BD09FA4D3B94BACE361B4C6BF6B550B89922EC01041CF05C0E4632274949D244B7776D6504C9803A67CECF65F750F9876109167CA77D412A7EFF06CBCF129D057143BCF03CB1C1AFAF937E55477F5B15020149D64F53887467AA16C6692FDDE61406D552660B88AADF65C03FE1B8D485C57FEBACF8B11C569622FBC56CA1056FD3600E1BF51084FDAE32876BAA1E97637F73677E8FA1462222DA72FB0936ED66C16A5E892C44093CFE7B4E3EE33F21091E04FC4A07C6CA21E93A500E5D7378EC716A9ACB27A5687BCD7F4559C32F6C82E8C06E82135ED16C35762E94BFD6BC33D5116E4FB209C98C871FA8E9230FA807CF1FD509A75DFDDFBA5CD4F131FF8B666878697B372B92CDDA15D0113E8BB91A7750843B3D14AC4E8C956B44C7A3A26720E774EC1A1F68435B122E539C8A7515A1AC94D456BC4DDD54839AAF6EEDDFF8797C9BA3A15AC70C34DAF78AF1F0C21734DA32A79C1BD3CC8B2636E12B9D2E42AD10446EA1A9FFD45430E03A78D8F38B64B64C9D308D18CDDB4D5DA13F1B4D15157063E58C36DD71677334B4D9BF09D8C765FC68B233B31105D0957F1B675798E5B9E982B1BAF1611EFED0E39E1E9E70BC790886A422DEFEF325A07D97FC603866C2C3682FC651CFFCA09B8122B636A65E2D6B8B9FBE6BB9220959038AEE11AA7003A9C4C4EC9E27F4A8350FEBF1084C292B6BA9A6E03C00979854CDFE566831B077823B025FD1B9C7127BDBBEF34186C74759E32FC222023EAC24A6A6653A7073F4033D77CF83831E8B6BC8F26AACBC3EFB2328C6EC35C3A509FA85E2E04532DB6E466BBF8071FA6020CF5585C70C29320786EBA815EECA6FB2BDF9C9F3A3DDD0F1800E93DEC3C5E6DB4EA5A695865303C48986CE26346B6CEA4A734668D5BED675EB0C2A1FFDBB9E5511EC715BB4BA3604629FA28A53CC0DBA1E819A521AF8B7BFF16B4FBC6766543C0111E232157B7BE4D561618D6ED7D13AC8817641E7AF77042E96C7209F1B65C42D115234F6C63B84D381F1820CD656C88BDEC7CD2A814D6346E90841005F66D6E36E63C5906D19904EA0D33502BDED36E7D77FF5E2592290D6F29200668A25A6B6F44FEA1D3EA00BD4BA165D122455E8F97EDB36061DCB335870F44068EE4A64FDE5695896D6A5B30D7613BD8C8B11DB330AEEB0EF239C105CE6C0B2E1BD81E867A2D823FF88E3E82FCA69923E281A2933D5FDFAC6B217D60958D18ACED57D670851D5A6A445A120F5B563070995793E618F885F149A3A3D498C69A0B9D99D92C16327B7568BA8CC35128500FF515273099B645C683EDA30092C225D01E6337AC652586C0872C9C5EBF09DFECA43697BD97B86FD5463F529CF303A105194BCC3014F4458CD3BEE8088B8B05D58A960334C73E1CEA934CA0ABB2597F703428EAC5DF6983A76A5EFBB4A20221E6EA04F67273D52D0311AB99979CB0EBCE738B0BAD72F0DA80097609F4422D962DE43D5B9E27F2FB3FD55DB5B9E98C1E74533DE23930052446A31E656E150261C6658324BB243E0C55C43BB397367D9E6EE51FF7A3F4FBB008F87FDC3448C07B88F4EC3788FB04944AE1D734E00E1CC58052AD2F908B55B39C0B1FBFB889EE2CF91CC1B3FCFEF11C14B083F8A898BB28B838662274B9974AA8E83579181944CEDA7FCD9C36D5FEE67522E828D6FD9CD28537D9FD57C8ACC7B8F888FAE4673FFDD859F6446B41609135BEEB20804F4331E31AE057171D27D1C338DD976634A460436977192E7FED668FF01B7F996F00958FEF2F89C78367507225C458A7EF81513D849081E4D22013A4A8DA7E6E9AF687918486E785E2E5D4EA5CEC4F92910E6A6F89198FF7911A16D7B46BAC5752AD5F7457E9B65AF0DB57148812FFE9F7C70F5531D11CF96ADF7A3AE1D86039FA5CFD5BD5465AA1649C40A513FAD60B54F7AF15A5A6B34F0935BAB28A1AF631816A0F5F1E53E1A7DDB5FCE521252E25910555D70AE1A309BB1BAFB7ED3856618161CB41206810AACFB9F748B06F6BB8ECA8EAE07B77934CAB2FC72FFDB061D5FEAC548CDD1BCE7CE5D04E9D2E4F38834AAD674F0D540DD6EEA85CEEE4F67B1D572597E9F2B66554F7F835894E81F4081EAB2578CEB8FA95964742436FC6741A5A9D1F2257572E7026360708EAA41D31ECCCB55811D5BB7648EF4021268C8AFF001F2D6BB3E1D4D304374E892E4384D66869CFFAC575398808D2042B2A33A874BF364B6E7A859BBCC67ACD4B5DC3494C1A6B55CE004A354C8EA8F14E9D9A4ED282AC4D78909F42BD38D044FBC1C730F921A1C678062A200CAEDB0EBD42D48C0B758F138EBD6BEEE1E45BF92157E3279C6534232AA6C361953A0AE37E81261832F29CDEE864962D44CC6C3C68C05B16915A8FE35B067EA754777725EAB0BB4E20C3BA7D6E75812C498F29A94D18D90D60F49339CF46DCEC6F0A546A90E0BD6E75B95441CEBC0B25945F2A38F3EEB1A9E20805A81E3008750588397A9A168C73C81C97FEC1BC16659DB16AD7BCE275A884EF801D53868B0DB816FDE421A9D7FE37E61B699736986325592EA93DC18B036D5B237115C35AE3862E355A1F3CBECC5BA89947E6E304A86196E0AD6A113BED701D21E07532A6D02D014C9BDEF9F9060799BB79AFFB218F3B98A4BC9488E5D2CA13531842C6651621484207723F41055274364FE30601C33663A6DA49C8187008BFDB1FFF4B7B3DE89F7FB0BF57F2E273EE84ACF8EE91A5335364BD034DB6A1F8025E6522B4F3D6212F3E75AB34179B21AA28FF6911736724FDD4F3229C6C26142BE5D6F2148C9BEDEEBE6C56B6A20746875A6F74CACCDED95179AF50E1C5E09B942B4E3C5E227C1A9DCA36F04CB89EAC24D5E87D07BB407922341590A739B825AFB80F544F2B1B70D877300B46000E660A568999EB8F54A3809D6879935492CDD67DF15A1FA902AE6ED30D5C5EC1178AAEA8E539068EA2A0132EFE51DA8A43E5D48ECD5D8BBD0FEF8F90288E3068D17EEF4204D639665BA3DB7C172E99913E97613DC4304006CCB37F1E9F62327E1C2B5D97E31822A52298BE0D6457708E0E2EF25A0C4C932F16D25A277C5BFE1AB13FD488BDA7BF30F26E89585F56D827DAFC799D7DE3BEF0B41A3EA3491514ABF11E633D7F4B8A88CB6F3ECA3D48495475A33C9107EF39157D53D447308BA03139C7A1A9AB4ECB178D818DB6F83B4489626E2EE9464D7392C80F8B4B6317095926370681D1ABC3A48D82DE7A810124099E375F39E5C6683F4972556FF258996BFB0FB81C44E3C0C1A814AFAE8CBC041D7E7EA4FD830568DE534B65926D6CB83D306A36861FA2874234E33F4EA5BB8AAE05C3DBAB96CAD63295D7BECC26F5A4E862546A166A09E059293AC85937FEB612178B8812541A929B81A090FFFBB17DFC3C774C5BCEA1398DD530C5286658D326D7BA7DA3F2E15FAEB038B8A397B68AEF622EB10B248DCC942E7BF4B4C942D33A4427B685A0DF2BEE8271E89A366708C9E48F6A3992174E8D401D821DCFE12099D3EF0BA0806E7ECD674422731B0DB2B198C495E9DBA6294FC736F41EAD9232A5E404A8E918A18D7A7846E0BB6716C4343C2FB00286049D7BD823410EE8F71347008A89DF42EFE049C61CEE782102730944DD15C0DA322F6DE4EAD8F9EA549767BF02BEDB1F091252F08B34B6728165B11D2C62805ED24ABE65A8E95441D1D5FBD361FA87B39135A75D749325F09416CD3E1ACBC04F6AC8B989716C55B06FC784B0254A884EA4CCE8ECB2EA278CD32FD1FD99C3085585201EE9492B7F7A2259479B1FF820661466022321457088B202B5F1E67709B763A3A945B19CB5A6EF0A322272D98F8921B775A37B6CF92F66CF86FFD26F84547BBA75AE82411E890A7D8F1B74D657380287606ACC8572D8522B87CF26C0247F25A7F8CA12911081224128ED444C5AED9EADBFF6EEA9FB7485884093C340CB326BD467CFC4F6E6C17D4F13C7F9F76192BF4A10F2F28F538C76BDC1F8528ED1360922E5A6DF1A38AF9FB28542357231478192219477D554507A47E9FCA585730292493A2B3EE225E0DF87C747E0CED460BA677EC691637F444D248805FA183666FA65110AD3ECAEFF59B2F8F619A275034CE415DCEC6E68A3530D17EDE27E93D87EE1EA55D22045CF436A34F907D35264116A848DF0B448E4BBE32A18BBF16A8DAC00CA6B07876ED0720591345223877E26D2DF4C0C3FD8484DF1DC40F1B7D4D49E871D8F527837F1B790CDC9FD95D698231CD090C60915C98F1CE43F7825613FCF8EC929BBAB9BF663A555210868653131556553F7A36368B0D83AED6F9A970CB2D63163C607ED896FC7342A71C6A1C90A53DA0F32141600F28F31A9340ABE97D0C6E8AA3270850B6598670DA455F8E2816EF82D3267D39A8163D34B135221D7D5D98069A8233802810C7605AF9764C6DB44FB55E29470503090CE6A720617DC9D17A5091CD3267DC4DBC1A2B7032B50CE46522A2FBFEE7BE29C3DCFA1FCDD43AE2E09DAE7330D2E6F2B15D10F53EC6D607066504AC50AA7F18D3C290296A8D9ACD1F5A3708BC035979CF03966E0081FC53F654AD68A15A3D17A65A768A4CA5F647BB21872B1ACC5BA3DDB5F69DC215735A5CDCCF50D555FE968551D507A7272FB591587383DC5930C5A572BE9FE0C2797B622DA16C6B87A03EA563845B8201168C45E7603B80E5780E493AE87584A40A09AD6718CDA3759CF1940479545789F08DE83333FACC26D28AEB54E2088934332EB7DBD5829F0ECF89D22C62636063532B4361B9C7C2B1D582E9A7DC72FF7F2DF667D9B7BAA543FFA20AF6BCA1A9CC22B7D7D177B73AAB087F868AC68EA0CA808EDE0C2F931B3B0CCB28E472CB316C0DB0367D4D7FFE0C02977CD2E5B20F28867DB1EE0DA77C5935155175B33D3275426C3CC5B73748426CEBB3ABFC50405E30EC21A53073C83A85EDB485B26AE7B633692326003004A822F261D5E20246F99B03D0AAE36"""), - TestUtils.hexDecode(""" -e3204112bf82f4849550037d8b6325da7435333c716595e2f17c8a85d66bc4a612e19abd17411d3f4b7e3a8eadad39a819fe5ba968c8640243fb5d18a7674a3368099088c000a1c9906573a2957b57d5132fa2df9423c64e0f7d89a338d0d41e9300f563a82993c8e43009eef3fd91c10dc21bf4524dde27c4013756a1cf7b5c2829aa1698a5ebc4c46b80cce01384678f5c444648ed513a8e0c6e4d29b3b4721627c1c8832d736d98c17f6c00aee528abf0908b030edb381770e6d23a261731817b4ba5e632b1f77e5beb60f2e34bc2f16e6feb6fcf8605367b5d2dbec8668cf6a7b47fe5802a9eb93451f96e2ad72432726c9579cf08c4337ded15690a1906b82df1e07fa995eef43df8edb543bfc3a7403877b4bcca16aa105b625dd23e1d938d4d89293e841245472a0c38b77a6697923e213eada80659269fb642089b311e2818f8ee998b227a2130ba594a27e985aee0c6a3b34652b54581eea40f2c1e235ec06e055247cdc106164d6856fa8798e0da03c1b4a6b89778fef781dd6c5c77147db302df8ae78b819da5b8ce171f53bae732a100211cf232faff1e0588054a0ee99891a26f88b19fccb49693a844270fcb1a43f26677abdbe3c33261ebaf69f8f417ae6df03b55506c463088d49415c0e5f3d9cceea7518692649fbd2e0153b1612a84e229ca9a69eef15882d402425bad02039426358124d0603decfed2101e93876d057725f6cd131ee346f047d7e2e0398a5bbda6e1fc5029b57f78e49a49cab5febc682931f3a2b167d553e4f1b6511b8b07a8f62e4744c20a7b2731b317ebfa1e89825d4b7fec5c775243c9af25fef92f61261f2b4377593dbb3008385c92bb779ec703a7e76b785b8aa46c8c3a2bc5069d69ed865f1e5e6283f2aea3740a62226d341deb55d420eab001398596c88406387b293ebd1663c2bf94041f3c13b8579111fd7d53b66a3528d9bfbc6b97e72730a53ba95e0549473cb4141abca8c8330b1b4e0e0967b2aef589efee973c3718eef61d27b2a355be3c92f7654a6d33e5441e3a0f389911b40f6640080a752ca53ca9db239216dbc3d95eff963ab43973fd8633299d5adad7020a862a594c656e34af356066885494b1a02fd6fc5cb257cdbd56e85e74de7005f2b160f6ec6f0a61083bb046d9ca90c04478d8489cd75e176d027351a84bcb6fff940eca4fcd464dd577780473eea0a72732d435eb41d219ef7c2619400339ad2c30cb4ecd48deb40d713e148b474c4de28b91efef85e4f16750bec38224c0916892032bff8b89a4e0aff665ebc050e46cf7b7cba9fe8dc8696c5842f82e6e6bb6b58663e1669be1e4469cc8982650e468b6c9e5a1d49a44172f86676d9f4731994d74c4eabb9086eeab469a8a7de0e18845797ed73742864149d659df3118658f8cee2cec3c8a8b388432ad98d4d78f3dead445af3fd698fc01bb81d4658624312fe1da6465b7f53ecfa4e6f958b9f474711c9a2ac9fc8abdb0682b5eb282e5ec116c45c3236baba0cdf49a7478400dd8a67fa4704a8e98b29b7dc9913d15f56e613592dc60db932f374b1a0ddc46435feb7412b290587fd9e925987e80d155ff821e27d77de3141b8cf38694e3cd0e7ee0d822c213656fcb7be166767da6522cf9c1f29cf044efd1fe7f0d9e9df64c417aae894e354bad581a66432f4ba9b94226b1b577f64a931c62bcc6c97e5f20f0c53f35ae39f38d33600208a1c6986aca3bd143e920a430e9b6a311a751509316abadd632dbc82abc94ae234243edb75d362928f0d8a7ff9f7ba927780bd7bf62f3849f3fd937960ed08794f8df99dd27c241539c41d27ece05215f2e63e7305d09cc384223a3bdf8df83d0cb1f76231529faebaa18e76b35ef77d9ce6d2973ecdfde9ebb91d7fe2ff38bf0e4ba8f9c3efa3185f6ffb72a10bdab1fb829931858ca37e1d3356bb199d9e5d9d90b11339643ce9c528ff7fda54f907126fc745cffd1d9c60dcb92efc39469c70899ff3d5fdc6c18ccb0b3bf04bbd9d14b34c857467185e5f427b134c95622d34f3bb5fc4bedb7fa8e7c16abc277447ec511acb82de3d1372f63d9a30c40e6485598e707415a572a29ed1c82bf0e138bf6c6267380760f6f2d42040948e96d4a792abb2912ce8dfd5ad3c20bcd63fc84717a5b0c79bf6acf89199cca48e502661a949cb3123506318dcd0079edd930126c0e879cad817ee9faf22a49b11f44b0719554da894a7fde9e67ed576f562c787832b7cdb0ce85dd90ad391abb590cc33c83a57a1e7c088fef90937f39b423977eb5d48028af46a43d664f3ce89be3f153857210668a7f152d94aa8ce1305e5c467b3fe47306dc75cd2717b67f1bdbd77b7acf6d4bc79cdb65b291e7356201f7fc0176f826290cb70b54ee4f2442a658812274e08c0ff222750703f7127c72184fefe2cc8e6b0769c56eaada9bdc39d44e8464c3c789b8254919fccc48d692ee13e70745b790f5e89ccf04eac5708734ef847a00d4bdb4a7773d8a8e14779741b76b1a3be2b5bff279d8ea3f750c4ea5aa82203f55b332b785536e30d5448acc215c10a2e63a6104afc5d9002eb3cd9b98f76f66679766a0562a1e0ef9a69d46a453d0777046097dfe965e1b380cafbd62ba18753ade14c2a663c7ebe2fa88ec4cbdbc841bf49366dfb13162ef6d6dbaae627975d3f5d6ff47f7685c713c59dab2e0629d6a14fbaf1895526ee00a32405d2f4930ebae1d4c0ba243e0b77b0575650c1964cdaa8a09d70592a6e50f0586fa398009bd40a2666f0e9f4512fd9453e54df633b6ed72916cf87455ad6e67bfeb91e5bf15221e01bd61738f5e92d5fbb15d43df14f3355d54bfc97b061a1db68354e06d1a2fe0da4e1a6c0c0c593fff12496e42761235ec1238879a2c9797d97c833a76a3a65bbedb8012722c4c4347c30bab6d0897f9bbc0cd8b20030d7e84507cee4069192cae1437715c2179c6165d38b534c63123e9b6f07fcb4dc1c73c376d35d94fb4ff945d6b9f2e8f41a01ba5b58d7b5afac6f7f74d5aff530e3183a0b8992d2e885bc6c2d5415a572cd8cb8b5f09094998025b86eec33fee6f19e8fa5fa11cb49932508f066f38192afa3d11b033a6b635e9a32cf0dce3512a9d7af02dcca39c3c7d62861402586f8f08e0ca459e96f2767e991f70590a1303917476df719c38b8c7dbcd8f61e787131c093e2ba97cecca4d52c75e18d855c491d1bbf517542494928061f24f142fb8fff689635d57170be21f8bdb1944729eb2c48a66debf5399ca10d883c37c860921feeaa1ce240c419a987f71484762db1f6ab4cfc83c1bd9e4ca85c7730e9a58630150784fccf9faa926a28bdbce010a355ef4e8fe3bec648ee207e187fc3a8f73f80850d254cd0f9d9e92a0bf91e73d63faad0f6fe7908158ced03f396527e7b96ed2bcd521a5ac0e81fb60afbe91bb0e70fa6d5c39317158f67bffc160f0b80663267752bb5a9aa97d85d9e9f40f557a215aacc03d022341baebb7ab7eeec8425af176f3b97eb80351158095708083dd51d896bfc03d308906c31eddcb816ccb28eaac48bcce688a479dedf9417c950a7a8c95ae7b452cf83dc548b64d58b52928e2f6411d4b02466543e361de3db17d8994ef28dff206b493564876d5e274658e69b5cd70a0090d669a865e56e24150b57ea6d3c261b11c1e45d7bc387aee61add50c7f756e593de9c3057855ff761e95760813e5d30b41ad700bf544c451bc6ff51998bcf48bd6046d9bd461924121a3d8daaf3978f792d9cd23978f1c8ccd999bc79d2a10daebb3c9d065d30e970ace94a0f774d872c700949f2ff6a997c6e3193c5782c82a077c4524981e7aa6abb27b86bdc75928dc9599a1376a2a0ab53b6668292e4d34346dd2658fc9d10232b7e39ff5843c620319e530c71052952f75f2ab69fa193ee321c5702b6e3107dfb93b60cc99cc88f1fb48c0bf48c032e2ab5a3085fc9ae1f542f7e0abccc90b8dbedc9a2468da43edd62864be9f7f50149300ae6e2eba570ded34fdfbacdff6bedc092e49810a3e0e860438e3ef56f15dae6a1f3e01d1fc6624602a486d4f2494a3a81694971fad50647f1f0d2bf9e2b4580877b98917b22c55207689da27039b3e46e7f37bc785c338cd0519fffdf11c1bac606dc58f36f5a6902ae32391c7eeb9fe1251ea7575632aa86ce0bf516bc370b3b02ac8a66c2b82a5d69506211c5d3ae15d3c78d47df76babf0c7fb0a5ca3dea741dba47e67851ff66b84c8b3004f8862d6e8f6317c708ddcd6f232f78d081232ad98aeb17402a9ced35420a5e2802381912f9773d0d431544b7466f778ea3f379cd9b095fd51c2a3bb6fe7bdfef1188506047a31905a3a62ab7ddebd4c5655797b90e7fa78cc80dc7e9acb634da42540cb27720f67699e357ddcf45fb4bb9c8c555793cc885c31ffbf6674648615faf691440dc456126a5194ada986c9387e282a3e8c4efd5601f55273296dd8a351adb1e1f954a7d466e75057d8ef0f3d187cd0f8c2203967c7aa3049968ece39674260ec8ce49a25c87cb4fbdb73f1ad1981c19984c8a7fc6ec2e8dbf74889cf6ee30ad325fbaf3ce1be4d06255353742b14128c74765d32ea790b3235a3ca4a6e3adbeb39c26daf148ce4fbcb993b48f04cbbdfc88f67da205c910cc6d0c85b355689d7a5f6794990cd5a8380322d807f4282f79f2d2686deb4d598f072bfa2df4644c8f098a1c9589ee93fb48926675c7e1481de74304aadd8b104384f4df77cadf60df790a394f021889e098f960650e40b9f71193c642c2b28dc8e73934646862a9ed47763ef721c0c01be4da0de58dac976c7e52ac407eae45bf11243f741d05b90ba2a351d19f0d91d115dfb4626e2baa22a8d1a047b7a527ee81cc059756cfd529db5630068c8d5120ea7a6125d5fdc982f6dd91efa9d4f19891986140cc788285f0cc715e9b21f2175360b67dbedc68ff3b41bfbbd1d3adbade1c46083eb973876fcc9ed1e264e8213111bd18beda97fa555b1cd2f9fc8d216358fbcfe430751152c09c02a78b8437616d4326e6d9b87a71e5dc04e61ffcbad9c2dd9e2f9b28885c3b5383d968611de6be2655f24dd0cdf262e134e8cb9db1abb07d6fce167a9dd323b1b8f7232a8355d3ecb3bd4ba9a3ff17bf0d97fa29064762a6c9b7ba14b1264cbcd276d85e985926862c96e322308242ce44679502fe70654f54d41cc4ecfd6933df5eb3b3f2bc47d76e85cac79393bf6d77bba0164f6f06922474c9c1f9ab86da8051a7ceb0a29aac113b4d1430424e8e498a6dc40d46fd0c341b00a069128f37e56a25734e9e446a500e6790ddaf9acb20f5f67037b2267bae2d4003e1f6104067ce5a360e031cc604dc828c7ee79fb9aa5261e14f473d6b5f0cd365c5dbaeab2997624e705b0a09650bd386b78bb38cf7e5a3cd67aee3a985bf25fd1017d3f1870d726d4f211e0987e9251ed9dddc27f5322c68254850b4a4845f1610fe728092d34f6f9b55af7c167bd8f5939f1f5fecc9d1e375f97961a304c775c36bde5c065076245a9d6bc90c8476d958d00f5421f869c4109f6388a8c905850ef8cd80927b44eeb042adfeb13d808dc337b0d3eb738782fb4322becff76b85105e0e737dddfbfb423c11bbf3bf93aeda6af3634ad5d2d49b5d36aa2d9c72537a69fc0db81d8b033b82c8921b7d50a51546415e51e7e5a47f3c71c5da157e25ecb701cb9128400f0a7fe4ef801a306ee61c2cd975143959f7ee2df91fdd3678719597df544a1686aa9a81b81cebaf521deeab903c45659b270b5906698af28afeb37ced3362e43a0adeab50e2c9a2019f338aea7e29195ad472467cd35fc8d7bc8e5e16f86b273e5af3583718cd0967b32e39ede17770e77abc124b0879e997caf22ca684cb60ca3860f4f2525a989434b132c2ff173383c74582cba5dceea5d947263b6980eda24555a778e8d676d2570e5049d38f386d68b13ef53b035a83364d8247a6b32627756bcedf14c9dafaf82a4af23b232e37eb4b4b36f4bdfbc9ab5d1a963bbabfec682c548789b2ada1d73f283aa8b98ad214c7e509f5943daab0b54a5f9d94958a0e3887feb46afcf00bb0202794af85caff85580f7647fa3e0a9183f202487ea5ddb661416be051ca0da39769fe2f99793509acbfc3efa82318c69803f386cad629b4160a33b743594b0e379b7e9d483c2e5d2dee40489b306981aef5541a8639533f46e058b83ccc878600a43f1c97e36aa1a5b65ad3b2dde0362e35063d6ab2018e2b866ee1d13cc204a2949ec14ff98b36408392751962c889e975de56ac5bf00ae7df15768f02d9243685207c530531af5b4d838d63f418e9261fdb9204e14139e7890e290c047a795dd7aa9ed45a2ae86e0a20bb1489b2366d292b5c8cd2401c5039ff21b734600a046696d728ba8e4e9697f9ea7cddcfa1417272b61689d9fdfe5f95c626c92d6ef364447505e6188abd7e544838aaceffe14768e94a6e0ecfd4e5c6b91cfd80000000000000000000000000000070e191f292f373d""") - ), - new SigGenTestCase( - TestUtils.hexDecode(""" -fe28a25123cd888c478aac1d081ea7efc0ad28c299b7cf879c70474654b0bfc86095607a496c78350e34307d09bfe1c2440919feedd0b55e8f495f7da65c3415cc63f6996debcb3c67831c2db563ea863c2ca586cc66742ee69b014ac318e8553fb9a3d3c407f9f27c5fe91702bd52331103624c503cdf2a6dd0e9dac9f27aab90261120b905ccb81043122d21146e1b83308c12220a34521a3646a1942103924d1337700844890b098283a891d980685246458c004912388dd91828d2300e0c82690a3288a29689c8a67190826de2425224b45000306a424292dca22954946483865192b22414c46520a91194a60d0948809984891a160218074e6324845906511931715832615bb091da9229a124861a963008020c23246662a24dca98801a369204c24888221123319064a440caa828233131da344911412913038863b48d8aa6301ba4884c4249041990211745cbb848203509d8463004272a21298d12b26840b22843005211b381d2466c02048d0a1104db260811078a012590014810020210dc84651836024c0622db2208cc96259336280821268222101383900a364d22108dc92802e3126091c465a2a42c9c000613133102c1641a202a11c820149928e1228c5892251c1851c2a0049a982849484200166001996d22a08d8aa804cc184522496dc816910c4331a28268e4466a4cc66052a42449a6250a15468c480d02c72840462cda302da004241a170c1b387161124213158c5b920812886001844d4142600b4891a2948d8b802c08b250811224c4a0911304845b14819c9690213806dc88858ab810113760cb80300c212eca2661213081cc2625e432488834400a808912234e5036121836665cc868d0068199186113a42148206609466064486a13362061447021c601208671d1085194066cc3845059242e641640ccc83050142e98884d52066a8118460180919c2482239550e1400c54b868c3c68c5a3064c81645db422c18448d0a914c1344821c27680b212a5a246c1aa76d4a0226dc44804290311b3464238524c4020d88b28492020253b8311cc91098404ae40030a2924522018ae316429c44719c460451b04c14a63052126edab4511a246d2226714bc891c418249c186e630049221446e40069c8102211262e14c86189a4044bb6901a28861b02604914210b118e0bc18c13252a8236910c47889c246c02988840886059460150b06c11a18041260c03a42c9a300d0c48448a148e41400d633866e3b280a14422ca027011440411814041c609500046d138801112454ca2719136009b4865c1442dc0b084c380405838821ac22cc2124114904de140211c39122414019b1691838671ca30516184642295690b808919c9891280012223325098651a01119b421002a14599c6615804700911012349605ba25118229122996c1a239112048cd4b80503300114888058b6512332445a4491c9464551120cd004812195200bc33140182ce2122a184652a48268a336681a1121db348214446d84a060e13424da400d0ca6090214521a05720b361141804550186699a01110b60c198525d41628d3446240366d5b0286084750cb268da09465d3006d64842922368c1c096ac23011c23024a0949120464dda400c20816591209163086118016e88448e11a5059b148a4b38208004641c4051cc80081b074861824562c84554286ca0340014056d58282c8b021222c20863b804cb4472d2229284982d22885100c421149270532251832682c8366ee296088148319a444e201902002544e02091e2324e080742db0691dc0206a4468ac98011009645a2004a50380558200c1cc76852924d08a74c141700e0462108000a1bc03058964551a86c14153151164624040501097120a88411988503367262209153403109396ac8448e9912099b862550004d63c63108a208143821003982d302862022519c448d58126d624669894026cb2222802868c8106d92100144260d1a93300b166264884409a2415a886c0899040a3929db264d140644a430115c9865211541432865d2a2201ac00542b050c11230e4a8400a4180c004101c90296426919b84409936401236446310628240924ab00dda3066232942da048d223492d8302001900822a98cdab25103174a4cb03104186e924244c4281119a80d1932304120459a8601e1a04c11882412006299a600d0de68d40b4872c5c415d2aca8c2feaa1ae9dc06b16212d382caecea0b4bea0a1a4eedd4ed8203ee52e2e455b5d542a745bec1f76d74a497dc7172059da0fbb4ac038204c13cf6e8c61b590534ad23f02fb6d32ea4964898d9768c319e931861679a1cca240b2c0cb6c01a2474927e1dd15b63475b3fa68924d4502b3511df5b91723e59d9d97e909473f9cdf3e9c27391196d537273b3dbbfd7a16d808425f11f5fbf5e6c89b80e0df01c576db331ee6562b4d2ea4632b5c9132f4b88a409f93612ce7b2a074a3a6e8f498dcd1fe2996d9d7f604f1063d0e803cd71307d3dc882d5ded30fd5a799a52e28896b9312bb53d72f3bc4a7dd9e963e2f4d05d06cc4d80230ecfb70c5b826a2844d714729d9b8e391571adbe98766d5b180d4216e902ebff86c226e0bd5c3d00ec141b00f17b0d1d6f3a4f407a0cb015d70c7ececa5026c143710cd530a15052b4f8c4092de12bfd598693922007139e0a6c924d2a8491d982b653d5ae9b8762939fbe8870aef52714e7fe67a2da7751c91f8ab5fd73b2dce38ef6b21e869dbcf4224b9af61a773553701783a17187e2a5b28c8dfe501946f16e15621ba55f169b10542b6f07c445e44deeb1ed07708ca5d5c14230ddf8dd5faa0eb2e209dc3244039611cc9fce09c2c2b6d56b23c790fccd3787667e252823ce6bf9d60155dbc855a4c7b274883c5e2d7ccabf9b0640f8bfee4acc35f0cf8c7a9d71735e2c22ead23d6be69926de7010323083e66571680d2508d6e9e4c752eba3a3f050d4e53ddd657a4d09cfbfb9d8768ebc539874d27458dcfc8d2fc84e8a78ae7bfe1ffa6c0fbba1fdcb56b65ed5985f2e35243328b4f43771fcd9a735b3a721d84cd92082ae4b4d050d0954d9814627385e5cb538324c5a315474c156f4710be47eb9e5c66bb4eefd2cb13d066838d8ecaf73a4ad25af96c570d9b5ca331eb03040ca41e2d23a469072d506a6496fd33163f391b914c36f681ddbe497b5108bb5363b162c7e333f2172645f4363e8c849adc9c5f53d26ca93146bf967e77acf6106ec06db4c909e97cca3b005eb790ebd994bfbc8316c749b7c3c55849288a18f65004a3a975b3f72a8ae8aad361a1c7c5572a99713af4409b1f91d3d8da85def0360442f46b86bce3bcc53445cd93647d0168bbe1df9b9edd77c7d02596dfda2be9ca70b8d959e06961efb24e2effdc4182b347904587a80bc9a0783cd65fc32b3e6b48f67941b8842d3f48a819d52cae5dbd54d0d2a8479dffd63afdb882ceb95e36211861e4cd3ef0341c373951e8446df7fd2bb43beaa246d0bcfe24770f42861ec978d00efafb27e8b1b4974177f192e490eb75ba2faacefbae949b7a236ca1b4141a625683aa652d90f0876fc8bf90dc843715f869b0db24f9bd9a42ba188b048998e7f0b0691dd0087f0ac1cb770120c63af237a45f9fe45b3687c9f9ae9a66525af9447f0944cb4ecf84f01a2b34068b8457d01051f092834e6be601160a5ee17d94e168f6a9ebabd85686fdae3bd7f60f20aa4f9e669b1fc39da73dce2014dad3820d6f125c0c8bb3386b3ae5de0e193f6ddea02da3a5f8873bf8b0cae80fffb5e1acba58292bdbd9d380deceab59a29147f6b05f26ecd3d69a8e428cbba2b78f2069bbba85a28c441222e649dd7adbb3c3b2b3456a026f806834b9f3d43186b9720a7154ba4a12de629997f9aaca8139e3a773d7330c3da727037021618a2adb7ad5aa119bcaa3c366ba2ece4f48ac6ebee1df641a33e14f9ee478fb59c04a2051c88b09cab337af5b5908b4312abe14e1dce9dfca692cbc59625dd0dd7faca4ae82facae15dc860b4649032ef6bcf1dfeca621962bcb3101d1c263dfcfc8c7f14fe007611df65d8c2f308df5317edb623e18bca8a569c74c2c63e4be52ee4b0df90cef8b31c81271c2ccc8a3b21be2da5b733826f66e29fc91e299ba4f2f3f2701d51ab9283185c02746cc9d4350a3ab0781d3a2ebd37992a2439586abe5c23642dce99a413cbf2e1177b0a396ad5c0ef18949b1cd5c067a9e558de1b235a7b5b86b9abe8cd7cfb77752b692c28248823d09d52158e81205cb4342cb032d655b93db39ddda37d03118f70063e04a3a52b50c6112671643f53098e62078599323b9b63ae618aaccc9c28bf995dda6923287083671b10277b95fcc1649a2694c68cd5c35fd87042fbd83dfa792c71332e7a98fd7d98a85cb4eebd3ed4a3570b99e82e9fd421ef3ba9f7c1693ef62687854b32c3e8d22812726ae71186372a1f7c8af334a62bd1373adc9daa77ad5984aae2adeb45c9ee3f268f1e07f9cd4afaeed2b008dc38322bf820666aca43052f4503d47f2a9e2d78ad3381f5156f52b64fb793715dd812ab19bf7e7d65acae18e0ae092d403a3d7fcb551996becc7a7c1a195a418b91e4f4b8df8a478230b8e7e3383135d5a3084c4da9cfba60229a7bef26032e50a721ffd0b279681c1d8ce2e37afb9f58f5e871be0303d484af6b6cd21f6475d3b1514ac221d6ed2b756346875594b0b4003e6a4a798312fc76833b6c04d5aadf1d731283e898226642436dc59b933fa1dda83f7cf2f5fc4b0f16320e5f963b431ed2211176916937c43ef261ba2a930699555114ffbaa00ac6361d2e35b440ae4c063d6856d837103497c8b487fa00b6360d86251bd5faa7d23a213fd16106f8891a103167f167008c1d09c7e1c9d82fae09e5a3ea7c7193147930fef0b8c04a63ccfb986ea736b5d3fbe7a80a2524994332ecce5f0439c0660f9c7c1245cf622749fff13c132b5190aedca8b19fa660063bb18c7a6a3e469643bacc479c6d9df840dee239b582b5f469333f9abc063052d74f75d98bbb0d06c5c5da6d7b93b617a0f574274b2d8b25aa3b21079d463013e961fab521c67f5183e0a3613cfbd8f5ece6d3791efdb20ba9777c5cd95aa1209a9a95abe030134afe843d15e6a6874f3bc6570ed17df31c7b15ff9f3e4b8ec000cbf520dc164afc8c511cd35efba2b178e613908489cf5a17039df559abef9e8033c8c772052eba33577fb840b276ac325041ffaad171880f37830cb60da1997241cb6ee5594b97fb353bdd575916f9705010d04f9f90835b81bb949b6f35bff409d5588cfa50838a96b22ee7d5b66d973f614f6d323ba3b0581ee407791a20ff4a66cb4c208f049ab46617dc6d26d51c4b6dda716c018b70d6331aa999bcb898511191dcaf47001d1127e1f9886de617c2002e2ba2f27b04d3e53515a504a2d8d31c1fb587a160a9edfd1dd31966c013c2406725e79a7a93a73756b9a29f5e5b8b80e3b9c53977541df0c2043dc42dee4ed68819bb8387a33bc2be6f4b33db215d28a983873e200f685d7794d9a1d2c38608f477dd24178817f05884c01d1f2ea94738b5601ca99fe21f07234c7174c5b20d88986cf717507699ea651de129878b2264083dda1beb6afeca929e98df36308be0c8213ce94d4e5954c6cd1f2a4e19a3ae9e5e9d94178cfb6a9c90bc3bfeae5acc91e0493896bf8e20fc3d78204449eb3aad69261d768c263fdad21b4631d08379bbc27e4070a5bd3b10d8727351831a7ef1decb217366f4bdfad707c9e1698d6869bee22f3579e9a79e7107725303ff48353eec66bec3f00d23f2e56cc872f29d1865550b4584f0079804655375e07738b9bcb4ae00414243cab9ba6b91f3e158e87f8881401da309d549b456290a13e0f9e4d48432663edb082fcb0d84d0eed0a8b0ec2df577240b92638d99ffdc5246f6ee8ddf37af524625abb38c23792133c8a7fea5054040b1e64af208f1f0fd02b4ea1f62197390aeb4275328a32e4c8f6d68001b6b9323d4763a72abb5f7246856ce65faa9431c11e13457ea3698611659ada89b8d755e8ce1711420608b67be66a9e417ddf39bf9b4f9f63c160f679955c6cc80f2ecfd72c280e1c803d1afbaaaa37dbf996b1d612c861b8e42ecb1c1a3d40c35bed6b2378af865d5ea21a3511a4dcc4710769443ca30636c7dd175b6afbb976bbd849073e4f3ecd3095cda97c74682c0307fd13a3b754150e2d282c8b42b6d312e901f74f3fbbab48b92cb40d271588f1f71eb8f68fe494ea9feee165ee9e4c038229e707ec8f4b79bae7f3d908a4c1c71ebd574aff7772bd1d7baba202d472b3c24d44f0f2c459d8b903b171d2b39d5da366bbc8c03c2487fa0620db7346251a86aca3cae7b62ef4d0d487430463640c47748fb7d52a53f683f5a49d3f7eee3cbfe59696ddea73d2956aa9f7322f4828f949d42330e65880a1d7b3ec79eaddba9043ebc9e47b9c010bd230b2b68870401c42694ee96faabd822c5d216cdcab834faa71e3d3c2d24d12f70948e3b7b5a4e5511642c3b43157e2b9d1d54b1ae8a5d7deb3d4aac990a040b8320b0ae049bf25dd0ad3fba1beae1d6ea69c1f1ab631f06dce637a8244a3cbdfaca18d1375e0448992affae4a7d08653f6a475b2ca80057112e77b8e6a7c0f91e365b74504b3c19eb529741d2f6df00d965b611ff000d7e85f087ba0a99f1c4ebd1d3e8c30ebc2e6ed249154a709077d7683173c0b160f8aa7cdf7f6a7b39f85f4ff70ce1fde27e7a6197165a08faa439ae93a3d28cee7b1ba2e20f39ec6217aaa6800e1314408552ceba1f8dbbbc216403b976adde8509cdec0650b70a3d1b5daef27354bf1ff057b9992bd1f8512a04020c45d35684a781a3d2e891"""), - TestUtils.hexDecode(""" -4F4C7E0134BE5200C4512299D134770A64A76B73A82463FD8C86594939DCFD9DC55B895B32A2E96B8AFDB8CA83AB857679C372CD88754CD8A7B0A31D2ADDFD7D1BA64556AAF1CDD674F3E8F5FC0BAD2FA38326365918430AB2344CFF785D5F73F2B5D631DB29FAA0F9CCE5CB7FFE0CF4AF1C7A8950EF32F1D72080A492C7A25ABF67F409FF5D4B1E0D77268C0A1B2A32D9DEC61BB71EDAE6BFD58F274707182058F0E6AA31E6D3763732A82BD6F2C76647C7ACAAE7FB4AA51125F0D2D48351B6A3FC7FD18172FA8689AE1602C4EC0CAFA863AA98BDBB1CD8C2681C2B6C5C254E346C18E2A270CAF2606A6504D30C0E2E505C2FF9D18523BBDF21424C645AF0EFB2EA0FD21B5D0CD85C7C1EE176FCF904B481855C4CD739443F3340AE48276E7F4BDC00CD11C2B0D6B97BD00AC962EE1FCF8A73D3DA3CCBB3B72095CB33C5542D86E843641CC98E27545F99188AF064D5FE74739C54F5678F411D96A0EA043652935BFB2E37EC934327C7C841CB0CD04EC17FD06A18E88882177B51B00DB6EF1DA164245A3F2554CEDE8C84DD777F0B92CDA456D922D8B7B8B63B548CBB72CFACA540C0D69F9EF21759F243CFA03EBD6B080D23DD62945E623BC4F8323DAEC1215B251C35EA13A0F081B86E803BF37DAE6D913B7D942BD1C276ABEA3F8F74D0C8727EC21EED2AFD438BB7"""), - TestUtils.hexDecode(""" -74bd615dc15e9ddf76b9f9bfe3092d48d80a2e8fe813b8b54d48297a3a3cc255927f7d8eb3bfacf8ba83c73455ef02ad7fb58606a401c0b29d8ee5c2146dee8824eed0d40dc886a5a0f4cb73a0a25c563fb78d9b347c1b0677d5b1f4fd9b01cde28958ff5ed00199921e2d72a63a4d5a3c43b9f5a47f5e80dcac8db898353bcdc754e89b0fd3279ef60fdc3114761c611f5d51a7c4ec9d4a3616376956a6b755d2e162db6df7c916d1054cc9e624a7b05fab4ae9080358497d8172b90bd2fdd8219e86663deec82ba86c2ecf63624c5d7aeee9f1ac56738c58dbc87d968fa3ee5098c51188169b188120015a00ef3a5bc03c52616cd04579604cc1affd3aa92270491673887b232eb65f3c0b2135157b6e57184b10f262605c26424cdf5c3a5694beb6a74ff252df89bd7693abc92ca4998d9c644cc737e8baa2ec6380d10154c212422c069c9d6fd38aca468ac10e08fb4e49b4d734f284c3e641182276a45be15cb2a75b78d52dc63799a5a2e4e800b30871655a507c2d0b6baeaaef0923d67057574559b87d8765a4c3f87ed76f1ab5bfd5eac40870dd7510b3bfcd84dd9ea15e5845626319e5faac3255bd9aa7686aef2410dba1221f67b3a649c5528a7f87f0ce8556e3f32d5c48622844c113454d08855d8a930b1c7d68522a9d284f1970f8944ed9882d515a877c21d3a85cc247da447d8005d72b688cd17490d88c9028c140f70052416815331fab6c073ed191288bfeebaa7325991edf0ad3520628f91d6aad43411e7ad0f8aeb6825f9b9d63b2f7d5c0f18c67d58634a9d85ef2a932cb231cac3f057656ad2c0e87a35fca332f132b68d60e39822409657c06dcc1cc92fae42a6c940c379e1fc61b6af60022a76e52c1a73033d6877fabcf9b17583aac80b5922148aa45434fcd0212634d5009aa509fb35e57905e033fe1026cfd4e227861d5be4e69838a92e070b96e61c747596e3bf27084e804dbf380aacb659ae79cc4c17f20ae64117088e297c82b8df7235974c4eade96a4567891eaaefdd7fc8ed1185a8ada618e440c4b85b698028f7ba29d46010d2f965d357a8b469281f5a2d3ad786092d5954ac780793f70ec4ce0ba58b2d755c590284c0062374d9a1453119d78b900b33d0ae9a7c2becfb014516d6b5a71da7c16c9215008cd1fa18b0e2d4b1a189c698e0ef49d230b7b284283b54cf907710730020e4c64a935ae5817803ea1f295f19464122c952de6870cef17bb4830f74e253ed99fc9d39618d1755003ce2c6434d5b4815a791df5478388dc9d6b3a72fcb326b71163922a7660304a9b9a0dc3a4df7f7d1d12fca8f3337adad6144add960229ed4b0de6eaca288ffd38a0a0ed6e0454e95527c18efbe3a3b4a18885e5f568577d903583ead64d60b82175aa2b19e100068bef823e2e8972feb348ec9f315b0a46d672d17effae1b47d60fcefef137956df1b4addad9587f6769269ba0d4e8d90090ddc2fe579dcca0980787ff8e41837e4306dda5f10d3f63762cb2f1b88558e749402b37ffa8cc75dec83fb44a6ab62260a15bc5f6e55eb7c1bec665ff4fd2a3d6e5360b3965187daff84ea0e42ebd3c33e57be120002e17e27d23cc5db3519afc91d9a6cdfb04bd7ee04a69ed087c4eab2ceeacbc0a0f4d6997f8471cebc6552bcb17e33ee72a197b5025b1499b1a19183fbca863b749758023dcca325bbf934fd1eee220e10ad10a49a3c5d861e91fcccde741b28ee26065812b371e25ade89e9a4bdb74956b9763ae2ed876b012d9c9e1278845806d9b22774b107443293848f2c510ea69fb45283ee91d08784c88f31de801244012ebb472b1a5032ec6c7404a03e6ba6c804aaa7aafacb204e3dbf5b9b7c455ad35a976706b0b217ddb0009562daa02a09e6a16484d4d85a4b5e5760b8b7e05c5310cb9eb1302447fd94b64963f64e2f182e5cac29ccb93233d43c398a7adc0d782da927a5978f7678b693d3c91988eee0c11f8614d351f48a3b35c8a5d1cd343ddd8f913e91f82f13922d84fe4a1c1599eb4574d1b1c3b0664695ad132627f8e24e0422caa6dbc0631d44244eb1025020f3018a14629eed3ebd1020b65ca21cc46480d958f67dff1926f99c7eafc6ff893dff9d804ab937dd9a5249d377eb2a9dcb8461c3a45e010690e8179343c8fdd033a2ceef78f2fb158087c93533d3b12b0d02417eb067cb63b3f961f56f7924d549e8a4ef12fbed383997e41ca1dc7ef6bc6629c947ea1a4750e3de3477c9d278d35f109f877d8af9dbf8a5be216b7a3511792efe170d79309910206de37a69877079a6d74b2a46192bee571b47e64a1458f590203789137bf3fa3a11defc15c00b976ee977e97a173502a3c13e01d1ab7c385f216ba812263096d0ef9d7c0c61dd2656771bae1edd5073e6a0e61991e4c163b5f6847231dbc2dbe261cddf6f31b614158cf41c3baa1e9b82bc2c4624f1be8322fb23f94912c2b89d82152e84f19ec84eab678fc79cb31ab6ffc25a56056066784fa5356cc4a39b33ee83f41ace4e6ba647d43e5717137c294093ba7c4d5d2f462d63b9ee0fde8b02d430179c84e79c168dec2e0a24578d067b6445972e0576cf5517284498e061ccc215898e15bfb1be5d8eadfdebe789188852a4e596474c0aaf581ada0f472ccd1a1ba6705bbbc6b938e2bf0b115557d73c3f456badae8422835bd12fd4f5a48ade113261eff298097c33dab6320603d813a198bcf6cc7fd9ccb78cdab417e6a8047e11867c91ab4072763d5e63369a58e8a3cd53258aca1c13f153c226a356b3c111a6fdb0bb51e5e6fbb400584fd4258bec8ad1b72796f0920a316564fccbd05e9bd5dd98552e04abc6a402ca47a9ed76bac30bd66df28aff95d7b86d95377349b7ff0a775b32dc5d6f726d16821c217f9deec62138e6b7b659d985dbbd57c7af7d6d0b8d234b47b122a02ea2813bfaeea52fac4100abe3567b18640f0e39828798b9788cc51f2cf987cd41602291195d4cd1fa1d1f152a2130fa6631dbf21fa1ffd933dd9137f7d1cc0c7fa133d3e4d04976ad8270ee85887b3d630576b45be5f2600a5c8159cee9154d7a0e4acb1bac445c033e57827908ae303d59564268f14abbf4b616e21b944c907ac9a30646f37d53b6d512f9c3212254d35e87aaced28d5d3bfebbb3c9e06c806a5b2ca6702e276c74d9900e08f8345001b1f720240813243c78aeaabce954018ddeda0ee6b1d7638e97b6d5b159984a901f297f10921a681ffc28834cf5b51c9fc761d327ee9585bd88c425459ab657095f793c8f07b255c84c5a0baf15c6cbf14335031347a03d11ba6ba49536d6812ec4e35dff2641bf4782f3c57d2d8e4b0d5d16b339caa4517ce6e8fe2f13f7d9837adf95500adcde6aa4191fd0cfd66f866c520ad3871f4f3bfaa5d0b8b3e1954bab44ac6b26713d2af52133c704d5237a32ed5e8ae69b897c29358c4a89ebc7431aaa97a031bf243e1a41658c8de7ba7e769e73b0b57a5b53cca25993c43f63244789e41b9be75859efb110390b8cda0aa314f96bc73b176d8cfe5f0acbbfa245ac49aeddc82e2fcfe9742c26a0f6128afbfd02ced63b67c26ed4755ccac4bb26963bf98f29c5146dbe5593d7a5b372d726d23e2947f6d98fa34454f6b9271a0fff5bb32a91b9140ef7e1751b3efe5571629784b271bac9d4b48c7fb0ac426dbd46dbf86aeb137a8c9b0d3025be5d71d7123581ddddac339535825eec433455a38ca8c6d6ddc59f12f6b4fe4e5ecb35bb3ad77a2bcdeb5315dffc072ba16565ae879e52e7652c9a45cf8ca840e913cd71dda69a81a09faaeb51a44f342812df6e88ddb34ce2e6a9a39b72d8128dd973ee94d6f86ac4b95af05940914f40ff800c3b25f3ef7f8a0261700415391ff4e9f8bca688b4ada9639da8e0ed0c754eee0e1d75f7c4e148971e7a72ab0233ee2aa77a4cfd345fa3062b921a9e49d444acafeb8c7796725dc84f2e5629b91f876fdfea92484aef3f28f9645973b47e9c607ab78877b035f64b8df0789fcab17f8d7ad2bf3a30bebd4233dd9ec3761bf23ff636ce7262974b332cbc3033c38bce5f9452dcfe3ed46aa3ae7c2c133160996e93a83ac01c4a50b0bdb0d6fe30c0d2b88122514aca33083a88b86768a46d11808beaef3412ba771eb77a17bf6328581d8213c5a7271adb13ee318f6b11624ac249857237d13c4308fa3aad7e148d0fe8b7a2c32ec48db9c2fc12fc536f5e9356dc83a8b57fc082a687a854ddb1aaace41e07845600cea04572c98a2a5482301d6c6e77be14bfb481ed5d36d9ead04ebd29e2c72f6855d4e13c58b338608923ff7ce5d366dfa8692b92c5356b6980d7ba133a979cc5f0e5fa066b575b0f7fac0e4eb0b531e404dfe328ee6ef263fc652a5ed151585d7fa47b11edba2b6ea5aca517b2bf5a38785caee5096354f4b703b8f2b6e2e7cec9b3c4fe09b0785734ef10555eca3e0fac89bc0293db20f64891f4b2773e2a2124e64ca5e5904c5d17e5d8dae7bd268c8a537d6fb7f11287a49e63e028186f9686b3bc6ba6c55a851f28804f53a0bd43098a63f5c005c4d3970cef231379a46561d41a94c18b2141843896a3644f1f19675ca47b4bceb6da613c0800c214df0c543dc6449831a7486dce0a6f9a349a4327209ffd5d240344912fe4315d9f38ed9e9995c814864de81e093517ab59e4ac5ff9d3c625c2e3db325092eeb5dacc6c3e5e3841b6df280543ab79b7edaa510dd39fdc44640b37f1cf44160c067432d32e4d83e60064e803a7c2bb5749e8cfb4c65f4fd515a15db304930279e95cbdaf3df8960f59ab547d527031d3d63d94d937a3115d3405e622a3f0a6c14c8aadb7464d5da999f16b327b61e9ed9296b0a8ffa10bf4ee900c2a3b55ac356f98076b705a8712613844aad76f961cf4829a1ba18238f2265a08c74e0f7ae875c19f70e9f73a328e48a7fd22e5657abb9b393bf766557fd834c6e81b07e1d1d92ff689ad1c794a46e6eb85f4d342caf54a0ed148ede130b7bbe1f1c2e868ffb20ea9c20b45f0311b352b85055d3e162944c91a89d00f2f9cf0e9a93743646379eacaa4ab3e54bcbce08e4ff015d0c424462c2acdf08c747fc3b7c7baee4e909af894c09395b570ae516ae687ac6d75c695b06fd8767b871ee41113b9eb7f5eb7d0d46d88369fed3148798736f31678d06b0d3402bb1577dc0f3f19a0a2f9d101a611d1b33ff99aff52937fc21d44e3f2c293d37b9a901ca71bcbe03965f2a458069c9dad2310b58a0c5662dc113d7ba619ce3e2b66b929e6770ecc3f6026e9ccfead7df2e44cd7e7fae06683a4b5c0a3a77bad76c8754133d7c548bee11be8cc084605f24668b294a6a0a633c7fcbf3822443a90477c8c501fd33c8778848f049a710971853bcbc2ae666493faa6426a96483ad0bcf8ed0c4ef0b58164b202650fce31b3ab76dc96edf271415c5a8b0414d7f60a51f01818b4e8c4df3f35f51f7738ffe534b2f9c2fe2acbf7c5e272a2d1fd4996ed30acb03abb0dee3e099b0430dcd620bbd639f3fb8b32d66c02dbdb262596c6e177d4aa7f74a959e90bd1dbfc061363870c42bd573abce58ac853b85766cd52724f158be47d62a90dfb5f0025e208c9daa5a386433ef5072da5d8938ed6683c7131dc5b0c66a4c4c2e14b04dea6fef564dac183478620e5c0ef74497974222f2788c84523ebc5391516ad6dc540095080042a5a52611cd4bc7785fef1768737ff1d9775a29a3a442f97dedf434d0fcaf2d8ec4931960e5ee03b91c6b16bb050bd9b64c9f8858958e1e6884cb916d6fe9643f05887b97f1696a7c111fc949009cad4f2ffd42f891cdb39292e9183b5eaef8c463a9226e71cf2ea4db2a6c66b7564b38aa04ab38d718aaa8ec5cceb4589e4f72e31e80910d209296e4342c65fae64b55be04a8927f0b9e7bab21f37af331218f43439087bd67d639bdeb92c3f774f7fcfb4fb33171659e00f03537983cd481895349a534395c40addddec7404c6adb90ad2a049ee457528a40821d4e57b94224d686a7ba70b5b2d35102b73de70870bafedf2b30ac3fb7f26679a2471afbe8f9c0f645e7d50d2d9b1e921ec8b84a1493e96e3463d1785b452a58077bd78708c1b54a96d8cb5b186e56cffe16f6ef668ed05cc0967305b409714679cd775168333d5042c9ca581c3ae2ef99e76fc7c42221c2ce3e138bc85e202fd3136c35613396fc259c4e223ea528bf7e0d7a48ee2ca96bb81e687813bf2c04dfde469c649a13816d3ea3e13b2f1fc1f6faf526dea7e3e39715ea1d6542e1a3b007fec2051531404040d929fa91c88a73ee9a717a93df44430598fa2d5922564a73b77651f24a4265c83ff09b25daf7c1b682da1498d5377ec73b00b408a4dcc9bfbfeba175220a6928623238412f1937228e9daf416a6c9aeafc06083d4d525c8eaf1f216299aec3d7e9ebf4193a42649fb4b9bbd7dd27367382849ae718394d86adc23270737c8fa8aebbd4001eaad3e4e700000000000000000000000000060e1822292f383e""") - ) - }; - - static SigVerTestCase[] SigVerTestCases87 = new SigVerTestCase[] { - new SigVerTestCase( - TestUtils.hexDecode(""" -f72a05ee9f7d9072a579e3743771e12eb5c748904b15ff67e6a82e1bb77cafc34ea6f06d0f391a3eaef39db6331f1f9660795a5e7415ea21799da7f73b9e11d1f349dd10d258fb5ad40e6421b71a2fb114f893c051929bc4b5e5d9ea311c3c892ab045948fffaf578319fc5a73314fa93a88010bbaca9eb5ad63cf8f88497dd7520d12138628a52a5bb3010a3ee713ae6bd21fbc3ba12e2d444e8d96a3d06be555ac317d856fbfa97b46efcc1b15625457f065c9f8c73c203ea957acd2b865866869399ab9bdae1d30242b31bf8f29e445f07c74afd7e665bc9087d3fc94140393c6b4a81621c534cccbe0018bb3fc3e50342caaaea0f374e23500a2fe2d73dc1b0b0f7047de062b44e2e1362e16dc62306cf4edd306fa423d1b95b847b7974f547f0ee79181a4937094f1efd2864931048f5fc3535434c2b2df5b846ab4c7817b2814c6b4a984b8a3fe290cb63984fa8daed775fe4c2e452548476b2f33c727a0278b4712ce339fa7c68a6db7fb0c25dbd074a9b3bc5f6bbc22232f2ce264246fda6784f18282c904cec36fdbd92a7474733c63ce05a6e7a911cc85cc7ae477a301f069b62da720879f1ee02469ac49a69119c61f4db5bee7f00d93892b05e57ce3f58de9e3429c9432df433d6e111c8eaa02d1583b28a07dc5b3eb57261b7f158df82255cdac5bc7a559ac2fb30706029b843d304cb3e6b4a67f06f465ba45057e0d1220ada4e636075613acf81ed702ca3f1ee717dab24abd513514d7d893c2d10506f95b3988f875200801bf7a4739ac5cff8a30553131b10a317954c11e490793ddb7ce0faafa9f276ef47ba7545422e15653487300d678806f10e5025a7e9667c456fba359d09a11a17b0d0ac75ce9ea941b0fd218d6f3e81761831b9613c641cd85f658a9aae69a8b2b56342a1d879dd21c8485aaa5c3db1f3e19b00d1c83395b2045ce76a2067773e4cbd9408674184b3c333d3e887ce6c0b576808ced66eaeb8a8cd166b94796d60218d37aaa21ef12ef3b3b548bb72a672629583fd994b9f26759d71c7e15de4b10453ca02a64b37448a5eb632913e084db89ebad69eaa9587c1d205436a871a3ebfa7a2ca6a0b657b615a101e4fa29eb7862e804ab0d6e7a61f973c47171eedfe909807c88a0c9f0536f1c2eeb4826b68adbd4f987449e7a5e45b7efe1eaf09226778522a1998f9d79fc62ec7de72a05bd5e99f6aead845fa9ac32929ca2514671db615c916c0046e36951efa903571926766b8fd96db3e187c9c6355b92ca681a2244767e5bf7c1f565940e072536ced11f37a64036749cfeca9cabf0905e39d6d1a434831bd89492e9bf1a5ab9aab5176e697cfd5b0982266ecffd197a20326783972c972be1c21605398685bfe4091332fc53a396111b24f072d0b0e21e67fdc9a8d8088c1f9dee7430e8c75f69f3750aa6ce9ef7dfbaae0d58de48ae87137260e7a5f9ca430e141aa81921cc02a304dd3cbcb1c444eb96b4e689aa61a77f58cf5546b58b51287f4a9bfacc2096e8f555d5f69f50f5e8efc33715bacd6bc920439fd9eaf9968f6771275e16e286606a860263fd947febbdf046247a460f52f3f5e422a7b88b42ca4fc771dde31076254ed22402836af677b32773a9f331a2314c31925957a96c801fc20da62118b5074cffb95c2d31a0b80ae6fac13c13fcabec3cbe4731aebf1fdd3e4fb00e5a30f368d63cf7366631b56d691664e50367cc20753c6e9f6694ab7d090f94d337b54d00413b38531fa4f5bd9e56842e9574f226de48cc283c4c23fec937a8369d9b1a4bb2150ac0ee50b8da8d2dc874b53de33752d7bab603d1fb49c5ea5ccf7b6be07d6fd11e04dab95ef3b087abf23b1983461efd3a5db010317417fbf59e7fec98746be9be60b51381f3e5647ee7ee8b17e3e6c1157d992339f098e424f335bd17703d7cb4cf3d695f0e2d9c112cc71f8ff0d28ae3e2e3a0ad57051396b7b044054d6408a568aa0fe0bac15265c22d9274c5bf3977b4ca5b441da6dcb301e5e14406ee5a1b7f10e682f55c94fd2c0f6b97e6a75a4d7ed7b641cc2d01a2e18adbd02af4cc798a5c11c4d74a342a6e44e85099d4fca4eb68aaf1314f0f9e157c38b15fda038fbbe2bf1f8b3a4464c57104786e92dbd18c6e69c3bf6a6700b1b0873551e5f949ee94bbea0ebda0c036804b4fe6664456fd961e7f3141a0c1ab1b985876c998620944f89dd207ff7baba22bd198636102b3ec3deeac711edd17ea302fe9fd99897487788a3f5fb117b4d2cc64062a7ddc90f2f421a03044ff7d7a864e3a110fd002a9207f7b3d0214406a30dded64c5c76e04d0b09d3fb8782327172d4f27fef14ab8ec3efa160ebe010203460eb6694d0b6994e5053a03df54537101d48cc63930dc35e5360c3de909f8e060e53ec15ec2652b17a12befdd313bfc01335cd678ca4fed253398a61451e4ab83eeb7c29ef8a617b1cd3a09a470b4ede67593aa3f20ebd3e49e65840a2c5c6abc8a7365d4eb18d73e1f6fb5308ac006c8c43d33477a0b4329b6a9271f02ef6094ac6d236df8d5c95b0111dcde62248cc4bece19fdcd7869e9df88047cda20eee20a663d9c48b856cbe1ac561049b8366dae8e811bf9e307a7ee37a2d801e7fa02cf6177940dc6732544dc9293c751c547068f91dc984bb024b0dfa6c9702adb74df91cb6dfbebe498c0f715ab0cc744f364559929fe1a44855dcc43a6afb49e73643e5160b9b5fcf8df8d11ea90f1e573f94ea1a7f472cedfbd8de99b2748370dde471484c58ae5c337d8d5ebe022e3a1b2498a6897d4d0b4a20e2de6f6ebbda6aa83ab221c9f89bd0807d3461580018d83db68d632e0ec538c3d415d022a4411a664e669711513525f89e1fb47d7d3b54b90d227d5bd64d86a4a7b29266116a804f77db66195ac93070fe6b81d7480c360da18b8b57702ffe608010ece065c42695e2033690d1cc14f167de0bb3e5de2b5340c67b2eef8105b4a0f8d4daf5ee3134aa2ae557f1250abb6101d1494a34716d1b91bdb21afd8566662a5b6d4cdd968bdb2500e754ccb42826de1dac6612a43188b847d69ad8aa23b6745aa965d44d7d82b9ad1044706dafb952e1cf8a9db9681414467fed1471cec2fc9c49562529d7b8b22cd7b825f37783747fdfd2f2bb8f8d95b499cda043db9189d59d66b486485192629ce2ae833e9ef0487f8d9735e1b8651a45dcbf9040197c1b026143b3042117e0ec190942c72f120f13265816a6865113b8c7816f14ebe5ba9afb3e772b61330d0494705a5e31fb7a7823b0ea6553ae1736de468ffc67765d1474d8d2dac5140600718ff82d38ff19468c9f0f7747a3ca90db86d7d7c579d2e47bafcaf92d145250a88d11ad6556e24fef74a857fdd216b5b394f229b70e6dc5be32724cbd6b59889685e9ad1c36335f52e3ca2c4e96d332a950fca062cc31360a2fc405e418a25b237df6a393e92c4c02c987c1d8b88778481a825e3537dd8f1013d64ef1aeb966f0f94038e901b8c1814caa1cc8642497591f9c670888a2b7362543ecea4af57b99a5f1144a797157b842220df4b96ca7088c981f030fce4fa85d29ce754638cae597603793062d5d01acdc08aecc52ba59d8e46cf7eb84c5ccfac75f01cb8ec8c45c761d20d6c59e78bf36df162"""), - TestUtils.hexDecode(""" -67D7F4FE3CC57FC8BE9A3D06BCA0FE4A39F39E3A6158D3E4ADA9CCBABEB542CA67CAC48167928336993C569AB5AE55BF95C8291AE1A1AB2B595C90C0FB19041435F3B411609412630D80DB0C832D413D69C8D3C3CA78BD1BDC24167AF590B67449DAC7F6ECBF87698BF3929FBC874F6FD68551B28E4EEEFDE9A0D0E7FE9E569F1F9893D39C17C3BA7A6211B875A7BCAD0C14194C30D60CDDAD640EAF7A02CC9DAC074779345B83F0D282899B2B9B61F8504BEACA3C02A76611C82F2007953D04FD3C54D7A00DF8F6DE554FD83D1EA5DC841645B706C9D900DEE7862D526245215AC6B9D178E60F9602F1931503864D97F582834DB797CAB60DCDBDAFA3FAE8726B525E8BB69B5E0763FC4ED17FE7CD9C9629273AD5B073B9516F6CD7EE729351C213FDD122E3C11DBC58FD2A501B267AA4AB21364BAA856823816E77B81B6061279FEDA6617247B86073E55B19973BC0E725F34ED4BAF0AFB95E436A9B2290A2B316C18CDC0D9F98F9F6F13C5A3FC767EC0A9A49BE1378E92BC9B3010B41AE52AF409AE0FE27CB816EB2614DA41C796D5F4FAC4A743FE34EF7C0B3A78E0E4A5B439659D4AC27B698550E89A1626FAADF71420F559DF2E808144707B5C02090F754C3BD4EFCEBAF6FA4493C5D48F895FE7674C81F069E1F00E455BF5C965BE2926BD19AF76E20533A6115F4BCF2CC5DD3A49E10A2B3FCC9EEBB2B6E4F25118599062F2AA6CC3A9D86167B1BD08DDB2C53A5E46E1BF4E8C1967866320BA66AB67CE581981F2003B812BA058B75924254EE3715BADB8E6B1B9E4F4AA9844D578CA2F0AD12E1C964685FBFFC87108711E022EA7F63330CA72AF86262838863780F4115138672643E6D9B48C782B8637E01D3D20CFD5C98A1B57720762037FFB12742B4EA8E89E4B32EE7DBFCD5C11E4A6E839A83398ABBC32BA39C6A25922649971D88A102D1019B560C96B820C44551E14509468196CEAFE3B7BC8F253ABFC59FFBC01A13008F77C91B19083A9E7BE733C1A5E558C64557389CA19249CAB77014D0569BAC7812862A610DC6EE074C844A055ADCAAD496F6976C932587BAD9D7E2080F8623C5ED8D9D4FB9EFBDDCC4CCC1284D22A2997824577A619905B0D6E451CAA3B2D30DAD9728FC7623F9ED71F80599D65D9F2AA285BAE393D05C15891472B2DD2ED5CA669785EC4D441F3308EB4BBDAE8FC449962EF9787C39A533847540965601D8BCB6B4299AA636589BFE371D3904E18BC9AAC9B3B6EB8B7E8F322C22A6E01E6B26244F9E39586F124AE4E504FBC9D860A61B20B4C127FD0C55EE810AB9803D810233E6126488A6E95F8ADBB3F8E06D113DE6A3E361209E0D36B326E042CE9D2698DEE469DA15464AFF82D5603434C07CCFC4D956A7D55FE79CC127AAD2A56B34EB10E8B85C3CD5163C4BB8C1083BCE5E5EF986AE028837809641A6AF2B8295B743DD9B03931E755673DBDEDE56F6294270532D685DAF1187137CD7D29248F21B290EB8317E3EB28B62E45E140F4AFC6D1438F81E9EBFC6FC0F1A4146AAD83AD1F0EE2952643E7B6872CB2823AB21A155C281ABCD19E20A52611C6FFAA724578A070935B1A0BFEFBF061101A81227187E14E96B016242DA269FC91253FD827A73743A4BC49FB63E2D830D0FF409AA1C73706D7C2297CBC552CED567DFED72CD15060A522F9B88EC910B03CD2794A9FC07A8FFC5CB97817DC769E64D8C474A305035A49D05B1C572363913A315932E391B62AF291DC203B9A40F04F40EBF26A4AE186056CEC45EB7D21D88CF50258DCB5EF40CB2ECF949B18C72626469978FBE0964C8A25E8C2D27149C2266748F2B06746E8C9E7E2F0977BBBFE3FBEC7353F583FD5F7C2B0139EA928AE1F67004706F6D4ED7BD8D13BC68E0F4A49877C0B2F692936BE5FF99544B2B19B23A97EA6B5F585ABC9E69E689EFE25E15804C650444C479E0DC63C9CA2AEC41A316039EC7F675F1FD7C0476707370CFAEC9C3418CCF30B5D85FE0E15056D6C015DA59F9BE9028D9C2D93434F99DD8C1BDB41FA1EB021BFD0FC12EF0D038CA32B0FE1449342D83CD6BAE43A8CC4077074FB1191A8887BF29238D27415D93880682017470A42872D6CFA729AA2B3F8B37038C83583E4C33256FB871A704527594596FE858777A93D3095767BCAD2FE295352C93D227E1766A59ECEB38FB7C2E3664D6DA0DD4C063975FAB3AB4B68D125AF16D233389D96A337DBC18DA11F37F430C1E49BF8AD30258601CAC9215F32771C6FC2B7BC03B55AE9664E0D719C3B40C3E4FA7DEFED8571CE8E46FDE8701975D94319DC5FFBE93B4FC4898E2EFEB3CCFFB3494AC50BBA364C22A3953F052F62E46D0C35692AF40D2FBF899A23C1A4721375F307E2FDE2E588830753F908FAD96EBD5FC360D742E2CB2C38A7E142C95376ACAE29DE8E1034207D1CBC1DBF2968677AECED152B1EC1AFC195F3320352953F2503227152444BAA74EE8F98F2B4512F7ABB43D7F87889CF1F8C12D9BAB91EFCA5AED21058E322CEB4E59DB4DDE13BE46FBDFB225F4AEDF7137B548503008002A36D7A3E98C0ED65ED9322D66FAD4A741125EA4ABBB26A2FDD7AD136590061E7BC0D5228555D1A59F8A6E4B97ABB61F4B1AD9564E84C000585DF8BB31AE61CD25C9D91D1A1FC21A69AD286CBC7E00F592DFC1C65E2BE755DDF041486F3B52C8F72ACA97A149FE0CE1378236D99EF099A668F6847659F7EF617B66192CA452ECE3010AAC18A65D8964381F561B48D044096DECC22736C902D7E23EFFD26245018D9D7EA9E2F907932A1EBB405BCFD29F7A397C71A5E08962ABEDA5203988A81F787B25EDE84A7D85DE92A2B19974EF7D0378877B82BD7CB28B67F45F7EE625CCD054B44B4CD51802B4FE2E219315CA9F4C24065F5578732DC671C3004D31830DB435C763143CA209D7DDF3F5EA42244E68429102F4D90297B7C987EEDFF0DFA7F31964B76432E1DE27FA38570F2BF64D5FA3F12DD9772618ED2B95F51AC90410350320E19084F1596F6B791AF1EFC24DBFA2B7E30015AB14FAF43B568C5149A1152A47D278B5F01786F242858C210D28812147646A1A3A7CD69996809B784BB2F0053CFE18446F060622FE3B9181AE9175D6CFD8033AA752296016E7BBF639842DD4073AB282FF50F94B9E116C63DDED805277D4FD7987F740EF8118946851A5336A9F6F6E2FE3ECABCC518B31E741AA79AB500D9C6DEFCC437569966EAB1D4BD6CFF8AD0E5698D15F1342ED46CB6DA986F0C4B2B427752C18ADC5070043FFEEBA98569E90C79A3D5E0434119A077A097D69DA6E9AD7E32C6E8875A893F6D69424DCF4C0D4EA12605E5E8A9853E4B58E5659FED6D724CBAF582A89A228F99BE89D88F55095D0627B40B29365863C57F82B9EA22FDE731D1A2D8A9037665213F2C410D4AADCE12CF888DD4AF53FF839E962F0F53BEC60F97133D131C2C8EB588AA7D25EC025B9E821DA8E8FD8E550EC5E4D5923BFDDBAC522D1FA64C503078618B52F452B57874285AFD3F6B182CA6C979734C94F040EBAEDFEB547683E98F4D13F12A252E8839317A827CD97A7C3D81962A25DF7D8C62B57812EAFEA9EEAAD7D6A9E755AE4CF3AF42CA2152F663C1BADA0E653EB165F6FB56D86212378C0B9BD5733D4C37178FFB58E7357487B98DEA35127AB58A804B13E61E6D3E385C96884EA91C744DF6CD44B3EFBEFC79ED19C406AA6ECE144A44F1E78B33046C33EB17E3BF61A17D849493D08F0FCF8232AF2922D96213647A47A05A9A08D28AADD3B3BF412F29063C9D78CDD3385BFA9F8BF06DCDA23FF79A5912D867EE1B0D526718EAFA6F0E231CE6C51959BDCD8D201838A50634F1C6BEBE2E4F5235FD01A6D27B90C58C12D8210692BF68FEA5B8A8651E64EFC1DFCE07EE670D473F29AFA63E080F7675F23E7D2866E5F2F9A525BB657E8BE5933FBED1E206C7BA9FF097EC95B91E14612E16F0F4082F70A1B01EB6219D47C716455F4C1C60948CF3228557E787A3186B4758AD35922AF28BDB328693BAED15487F7448D1796BB9DB5C931EFABB4BE436B2710EA280368A8E20C5782A7FE986417003236BE9CADC560B3D7C2CA92341536CF67D412E855B92D0229C45B1C518D8BFC82DFC9F413D3FB23D37EBD96AA0CD0B39EF88B23609AE0FC2BD16FA9E934329558759F05C8D4C8F3F8728335B659D3986E44508322E47121E592C9DBC6F49656B473EF7DA53FF8EF7BAE07D1BBC68EF4AC369D7F8BE60948F34444C0C443A100443EFC444E7FCF0BC4DB6A2C2C64662A538D1F68F4DB95B0B83DFD744ABCCBE5DA343621F0E182CB9E915B2097C186F1B98E7D8F297C347B60EC26D04B6D9C1FFC01EDB2551FB8D11D49E52956F69CDE0E49E2E7DCC8E7C8E78C41A9B2A01483BAB11733A0943A9B765A5811451C07A195D87060F157D114358E478FBA2F2B755A2A455E9831B77EA9D33FAEDC1C562E1CFBD8DE156FAEFF10AF655713E36FB508342D9B4A239D6DB786CF9F57E1C39AE65A7329E434AA88C68F82359E6F057873968F9FB63D898F24BC13C0F7748F92E404C6185CE24C98D4E4D8D4B3C129CB46C614E773A89EAD73CF0C30CD7E6C9F6435F7C83A4C3F877E034755EAFC5F30ECE03F6413F4C7DCCD01649B6ACA9C1C3AC3D112F216AB852A27DB3B846CAED86B76FB699AA7623548EADFE6D16AAF5A3ECCC298D5CAA7E84ADA0B75290FC6ACE736051924DAE8FC5BA6DC9AFEF65F369D054A4A18950E71901F4483A4BDDB2584DEDC31A04C5F8916DA2DE33B37078E5DAF3304344A8AC368A6668464FFD7898A18D10685BDE6D0097F95A3587717F6A3A8827B46653D56E461EF861D6908AB7D865B532DAB37E02A7A6A72A06F25572D83ED6DAA540FE56BFFB2BC9D104A74F135127ECE457991152DD0564BA955971E8C9767DDFAE190052A98A63C4C0DFBD1B51BF60643E4C5EBCA678CE5150F03A6EF09AB0B1C2A0D2C19C2B30A645C7DB9B56B5AACFB862837A38407070DA9C7DDA20B99CAC7B03D10C8F28D6B1C686FD26F9A8FDCEDA6B188D472BC593AD51EA62DCF73D32EED5444484853AD0EFCAA60DD42DD2C50F5AD15DEC7B71BF585581B9F9C68C7C94C154CC7E0D19ABC90508C8EB2DE93F0BE4295973C1F443A1B2419E20F3D5F883912BBD5CDEB938A4452FE0BF2361A9E3B2ADDFBF000DB07EA19B2735CDF0E8E5C7EC5CC7CCE1A9C3E869718272E54CD9875C21DCCBB06FEDE38A4E787D111DC6A253A4604B314FE47A9B6F6FEBA3F8F013A456DBB78B497C4CA7F90CC6145F47C96D266BE5507DEE27E968052CAC85EC87049CDC68D723D8CF89B0C91F67CDE2908C0C71808004A070CFA2EB6408F5FD6108749406FFD3D5DEB6FBEA00FEADDAC4CC0E22A9F6F50B9893CC4CAD028FBB73C1B7BD4292AEAEBEB668859BAD444D0C5FEDE3C469CF28C5C726B59E828C473C8787453BAA3AB2BFC29C691FCAC2CF496ADF3949CC42FB16F3677D456E614B1F88406E6C9DA7DB9937B00764D61C3D347C140FDDABDF8CE5E3E2D385C3FA6FD9F13F3BF8073B5D6AACD5294938DEF9C6ED414FDE4B3C5EC43865A7FB02787E50F94033CFE32A85BBE24B09FAA3B55B8BDDE60E325B691A350F2F128CF74FB5B6DFCD0E946AC7BCFB839B3765616DF35AF29F3AC82F4E2DF7D4AE87A016094719A07B5897105E2B08AE3D807960FED396CF38863E69662238541EE295C06B290404985444F4B28388DD942E51867216C734580B3F1D5BB204B05D4993D6F8ACDC8F16FB77B607FEDA67939A2B6AE285ADB2C98E7D37A81AF0101A5CE39CEB2C67CF99441C1FD980C2C542E7284BD21F1D30E68EF3606C65D3230B5146DAB41D4ECBD5FD89FFC68441BCFED9AD8B4E0B616127A7AA39E84DBD1343E2A41B4DB1AEE0627657438034E890C8EBAE19791705BF6C948C630DB1423D310A34BF151AA8ACF3269253BADDF5B40AB7EB3A7AFE2D7891B925F65EA206F4CA121175E8F348B4162917A68FA768928AEB0504A60C4F42802DA25DCECEC60ACD21FB236080AF1FCC9146BA30AD964416F4B524ACC416B5357206980305555CE3485425EB8F87401FB1D8CCC184C486B5B563242BA9531147D6A2E7C0BEC1A56E083F05344BF97A18D0CE0FE56E8BE869C746D4AAB365225D8871D4F99020DDB1CE2B5D7D2E5DFC8A0DE780CBA0A9B9ABAC87F19C73639965AC2382488387F06199A08F283794E1B8D3580E5CCADE811ABA6881908277624D5395021016DFE21C345B9A21B474043E187403E5B0ECFABE43991865A424BD33D233AC4BD30A3CE73DCF49B58CC4A3D2CE25C54FAB3480FFE0D51A43B71FDB7E1126E66856D263DDC3BF1A31DCDB935DECCF858FA2CE5AC89BF32E36D8009657F11691201290A243B5680E060D2CE30F1BF2444D67DC94A24708F8F9261945D1B5275ECFEAAF40311CED5C3770A1C194EC44501DD25B7F5FE67BCF62D1BF31119F8EA7DEC1CF536C1026A8E72C7B2E167BCAA8673AE5506CF6208F3E1B6057B5D488B29EB84D6F94AB8AF322B8657075B9EAD3297505AA521D601C21540EE71349614CACE0E7F14EF42D6CD5377DDD0241E34CF273A1171135A376B98C53B218503A908577C268F6DD46CA9C26DFF5942998851627474DE9E6B46F49DEDE85CEB993A52D01F6AAD6F96439C18B0DD5A4FD559812227BBC0567A28C1299626B171855AA0C74E2F9B1AAA781D34CA58C72C708AC49F5AE1453902A1FFBB8458E8B4786771780ACAD999F8DB036CF4C3F77AE345817EDA2AD8F7D2AA9228C994F6AEE512F7C2D2AB72F2099EC932D818E495CAC8507B06CDC6702944237DBCE338C20EDC84D958C14233C1884BA09A023BF5284F0B0157048B6AEB508415DF337A553F6435140D0CE5D5CAA77F9137B2C1AD5A02B13738772743F192E53E970DDB401983535CB096F7D98644797F487CFCD18F1B22BA7494D892C1E5AA05E66B1A4326C70E348350C97DBC26CB110AE8289C97CCAAB150020827B7D7AC7913B4FF515583677018949D39CD73BC7DBB90696D5EBDBAE6BD6FC78E3826C8218996F079A387A17456875952B268211891404E80F8360F042EA3D9F7F7BEF772E64FA1EE8B4EBE0A1162A46EC1E9899766BF4D3099AF712A847CC86291B3D6FBF51B3B3CFF87D7DE71E73069619480F6056AAACDB9ED8E228BA075622C2FF242CB050342DF8F02118D071D27D1FDCBFADFF49184F5A100F95E1BCB019864E58E0F02672C8F5FEB97EFA06FBAE6EC3D57A10EC712BE0144323292A2CB27F1B1FCC104140F556D09A6074F853AD4328B00E6F2F24A61A7932311BC999805F2E774DB44ED72ED244A945928B9512556EFCB2BA7BE0E668C41AE7601339F0162CEC0A1AA91C3FEB6A8A40158D7A3560924455B9AFBD4B3881F6C08EC2895C84CEC30CB0F5B499B4A66267C719785F94A9B9F96FCEBEE939AD0FCF42D0E65DC241698DED0EDF1A9BB4147898E6E83851499175105BADFE4CB00B9000404DC92EFB4EBF41D9A9262EDA550DBD0B99353D001F90AA05591100BB678634FDE4E0B1C174222C253870DA3B8A797CAEA9B446309DE5210F9A932D6AD48A4A7361A943C1BC66BFDF75CAF5409034A8768BD535B20996A728A26E28340191E03DB17A7032FFF883EF664FD7351DD37DC2D72F0CC4B80BEDD1DC33BA3046162F5D0003140DF78FA588A9FDBDF778836C6CAE7E5A20FEF030C57867B295712DED14474FB87A301C31214FFBB4F8D166498ED93B6E233A669CB88D441A38A0E5846EF68F5DB20245980CA184878BA8BE1992A0638B058CD3A3A501CACFC818D2B5D7876DB6EB08E9F26430FB06EE0B9E834D1C331B66CD0BCCAD7A66ABF4A9D8F7A872932A3C0B25C5BBCA480159711E0BADCF69A1107B286AB199B210CE95BCBC4244780C074C42B6BD43869F27BD666F9B2541B1561B4C207E9A667EB1E31942697FCEBFD0B920EF80CFBC5CABA6F528187403D7E8262C110458B5382BC376799032362CE57ED39F0D29D7822C408923C29242385CA9749FACA43EB4483E095851E89D24CAC7BA5AAC60815CB5C8C5331CFD66352BC8623D5700F49FD98FFF9E869D5AE173961138D76E00CED6DBA09144083437CC8FF5ACDA10BAEC0081C8BD2F5838666A093B412532C521753C4E11ED0521923D1EE6BEF3B4FABED7467B9C8F75FB24FD8D96759A6146B34EF951C4DF92228C2E58231A8D25E3F08ED5A27BF6041AD7011DB41F815FEA503973D4E7B5798489B261A0AA4D0C32A19D17C584B1702713D1174E542BE4EDCEF27016BFC78118445A63FC1D17FBEE5F71DFF46F1EDCD050239C68DDBDEEFDAE7EB8963B5BB4819186D45191C05AA049E50C4319936C8788AB72744912AF28BBF5CC77C835C35BB4F987DBA6657BC2A7E58B7CE69AF37AF680DC0EA7797B29528AC70D92F295C561E2EE0D0E530854AA19EDC43C01A383035F6A5DFB354E9306962EAECA25EC85B9B78E8A1DF6CA50EEC733F60C81BF812981337F784F8CE07D0C03D8B3E72BEE1FFA55FB92DD0446CEE29D8825CBAF1A6ED295E613FC700FA31167224D99338C4F59B1BB9C1E63CF77476BF84F2001D42E4161F7737B47C1A5F219F6AC8B8E3ADAECA827AFCD6BC0CA09615BCE15F1BD0803BDCBD41E68F781517907EF3DD8E8A33A1E30ED09D7EC1D3605DC72C9232EF9F92475743164E92D953177B98906DFE5E414E134EBB63C79220D4907869CB2D93280F60DBECCC81B532CA336510E2A7F1D631F7BFC517AFF223430F9804C4A4877D8B7A385ED48F390ED9666A56EBD62F6C943D0E52AB1EA247BFB07C05908E99358A51E6111486133F4A6BE3BAF6B2D4C01529925ED911CE728B4CE4E8CF8379BD216108BF964496269BE76379912E94A4984B890A4BBB9692107D56AAADAF27ADE475E98A566C0C9E33DD1970A3DFF0E2F79197F6315E320BEB5E2CA3E3C904B557075981118B363042BA687DC682F13D213974B1647FB43DF7FA168C9D4F599C5BDFF2941C111C6C43FC75E69C290601EBC9F23D665F944A9B75932DF7792CB8A005A7CC83DD071376DB11F9C950B38B270E06C907FAA102AC76722325934755F53F3650B42D0FF293FA37086241C00E99B9C03FCE21F8D7555CFA93D09A0EAEE3733A8A5E4C45E74DD5EBFFD2F75EA60942BE34412BC82FC9959CFA155DC87FFA0AFFC1E7CA5057EE016B9751C16DF25610F1981A08B8E3352254AFA433E9B86D3CC13FE9B5B7FBDAD83CFA0FFE511E44412DFF1636BCBB49E9769FC52B302AFC7A96A3DFB233831007CFD6C302CCABC119DAD45EE63303DFA1F11C39C702AAAE00FCDCA913371F158BE5493A9B5C3B06AF66C8D5DE2BF9563FB617D1490FF6510971203DD25B27E1AFB289DF894396B8C26548BD53B320203AAF053B19CFC815C5D37E3115FD6CF8231B88FE4C330545F131A01124BB2487A3363B3E534BFD38B1D5138F8887EA63776D78783AC45675ED598617077AEAD86206B9FF61E3669C93C3C3A3A8F39E7848A88C0F94878E5D359C22BAE891FC7478BC8227FF320B047D0DFFC8218C1110136FA803EF6395E52DB8326CE8E3AA928CE42FBA04B1E7F1AC7B73296CBC1567090B9E92238859A87686D8E623B780F0376B8537F41B1BB102CC8C480C0B6C069F562468D4E1FE111B24D51F63E9BD38C47F35D8C2B5BE2E737274229974CC4CA63BD0E1F0446F6C4448EDB2498F2376EE26BDD8581242703715AD434E425908D61EAF865FAC5E82578EEB0525F54320B6C264F37DA36B55C2308D4FC6C7FB2F4D12A88CAFD93953193B7CC46804A0C464740B4972A71B7EAB5F6098FF78BDD452540AC5BAA894C10CD69A992217B422C88CC7849B4D8357D86234449B452AB4D49EDB1D2769512CF8A797F5FFF4E1E0A3FBDE292D91722D71322F0BD48C68A3CC998D03F7581EA7B5F5150E7AF58A076D09D103E9F64E61A2D375461007210DB511EA89FC4EEA75FFC71F7BF31400E7783F12F69A1EB5B7228952E2CD1D6FD57109237BDC024780006C229EAD71EBF4B543647FDD9216D98DC78B43CFEAE12166CDEDDE09B52BDCBFF089B1F7427EAECC21CCAF3FD5A35EE72C3107DF0670891E1AE12C1FB81581F3A45480F1FE06BECE6A494074FF3C47F90C961E371E8014707AB0FD004D19166140AF7B1C9D6B7E4B6826601AE104CE18E17939CF77C2A31F711D5C7D5126F4CB642178CE542973466696FAC1A0858ED62E4F2741E47B83B97DCF4610B1E4E262E700A06FDBFC6709BB1D4AFA7C20EFB72E0D623389DCCB049054CBBB322E63B09176E2903DBCE49083B01EB07F140D498B793E149573D8CA91DD2BBF8DEABAD9CECA0F896A7B306C22F8A761A65CE2BC1358A6ED07327AA0FF4C0B6E2906882A12C50D61D021A1316646461013D8169C4B54C61614CC9EDB2CE0AB0BAC96B36908BA3ABDF92D11D96EBBB9A60DA780AA58B804DC6F91E54D82068FE2FB10EC1FED54B794836F54503135A7F91921E2BBC2A61C99B6A0BDC04FBD2D4E7E430F16B5D3C7F06243517452BB7D2D51340BAF550D260A26A2F3B5451AD7D4E3A70CAF63F92E25D137C9E9B1433CAA5502DA269211F58AF2720FE3F899282C2C02B78E66D3302C5B9DC04B98197D3685EC4E6D4603D79B357282932689C2928361022E79C197A470212A69AC2BFC7505366CBB2BAB8D2E31314FFD77A04E85076D76948E836CF2A87918D43208CD856FFA33740FCAFFF9F690B2E6B33F1D89F65C71"""), - TestUtils.hexDecode(""" -a7a908a5bd14b14de2439fdbaba72b5ee9bd54df9c52b17b2e3561949f4739205c112010edf1acd95513c740e1a23beab2269f5db9b432bbbee5db53bddc1fd355d8ee23f018cdf3108404b0d1ddd3b815dfa8b1c724bfc8f9e0c0e610a8b1260ae33ed202e1e270cb27755f10404dd66d3d32c530aed7963b5ae36aa4c1d0ef442b149b71a0756c9e016b7ff63fb4ed25c59edb578d01a0dcf04935a4b5609f4018a32d18f9a59f0edc0d2e90bd7e0ae75b5402652dfa30cc0938c7e35b3666093157f1c2f6ad80024539443557db996783056c63730cfa60c46c86b79ce446e2e66d2b279c192cb4773409fb8cb918e363220c0c1ed95e9a7524d0c0ac53c172eb3fe311b14d16c2460d0e583aa3ce251057b5ca59fee59f72627fb3b1c8e74a8920f10ee9f96a080d6f0a143fdf029c71f20451757b2519fe0c10e006134a2ef8d51cff472dfa63f934e13fa2d9f9705092712bca99be482313668f52a5e996a59511ab9bed2a7a4ec0ec1f17a3df944d4222b32e7c4826cdeb3abdbf325f7f9c76f5b7de28b1d5208ce9e19e853b90c9c7e2a26cd1590152fb61ae4fe56238b5e52fdaa6a17afbe5078d4af5403b620acc4942d01a432849fb5a6bc19bac30efed04e629d3caa74fb0d7c2873a3609c0b6f8c41d88d394bce13f3a144f0fb3d60a5ed31225badb206848c13c156a2b7be5d9df517d5d71ea3b578f90cc85fa72c3057442c95571dd20c9c9b1424566a408f6e135d74728b4b1aa1918aa38dd2108346a3189f54c9ee83684b1630a29a69d6280e47099ef989c3907b95fa9c1119152d97f9d9181fe2bb89759987a7dc16556223bb0738d1a10ad7959270bb737fc7601f2552a322181e1730228c4f0889cf196bb570002cc439ddb83bbea27f5ad9db5e62ef69290368544e271dad0e880a032a188cf4ae1b290f6576ea5c20ff9ac3b3950566fb8081768a4bd804c22539684572105505d2d2507308e5e50d05ddf24655089c2cfa4185265737894310f66d29551e842e9df5dc36d2e1a894d10504099511c68a0a81900c70fc6c2b32e84587d6e4654c97ada0ac1b7493a8efb756a4aa0278b773cd302f0746a6a18e3b1aea24ffcb32a57844955bab9abb85076ebbc568b4c5ecc898f9a1d9e65c6852c64a1995733420e0ba5a61329b191e750e212a68ee37717ca8961593f146e0093d1b70f07cca6b6f2805f48e66c1b3d6405ae5f6a95fe27d427482fcc5bbbc2c5e0e0449c73eadbdc261ee9636bfdea73a13c0a9ad432b4b7037432c799cff8051a331b261028739bfcb17544732bea4c2c3ec1d42685d007740bf49d8f8caa8bc31c7e59f9ca033f27eeb57f03af68b8ca30a27f78c06dd3a7f821f58579353c325982273415975b03cd8649c9632374f25bf010aa1c0bb82eabba168c3e2ed17213734718cff337eafe9e48b6ab79655e98a38bb1f74519aa07ad10529370ea2581f99c59a824a5ee0747fb6bce34396514a6a3dc4755e913304a28f4bf4019a42acda382a7a7211a30b2878264c4266043cbdbe2c711fd0da53106b0b5b16e78bcd1a075b253c98cb0aa9b980af82425751a7192e42f5057d5e5e71a2d0dcc9404035e63a905133c7724ffa110c942c54e8970dcbcf99fe1987931a5fc14e83b731aad5f2ec0a29f6872e43f18a94f5f9f11e2b7508ebe29a803fe159aabe2cdc242a6ffe976044feedd0b5826c129dec3c05764451feb8b99953a635e7250e74772da18755e819be7db6560b5ebe2de9eac9fdd490a6aaeff8bf568a38f70bd0ca443d336ae6776212e0d99593f4123d91dff7ef68222d497d1799ebe6decd2f7acc6c363e43dfdf9f72b88c25e9bf740cd1207421b476ec3b68843cdd285e292986409aa4ef04ce4b6479c95e52ccc8b5b0247afb94f43af536ad9ee79b58b636afa64a2be3fb22fd128f1f1f05b949921bb050892ed61cbcdf66b11ec042eaac3765d7aa524c0cb022d386032ed7449262529d2a6eb8c5a7a539deb3d1db814f0284e9dee64661f8cf3906a9802efb7fb5c4033502eeccdafd77a6d0f6ecbbbd39aa21f14afc3ec5def48b48afcf5ec99acefeb3007a90a54da935eb5d4aaa68502b1c469acb166646a3af67fdbb51d1338085d2798174db7ce74f2ea9c61a50a6fbb718dbf62ac33dcb7fa80aa982924f4310adbc07b2b672438c837d1c58eb8b9093229cab0d6047091b4152a75beffe7b17e44989dbef1c68feacf11a47d9dcbb230b9b180f9a7d10036ccad63454f3da00537078db225cb746466f1d56df35fd9380620e37f4692aa0b9b5bb1784a4cb80a53a25bd9cbd7ffd2d3177ac7023ebd1127adc732ef7d4963f70b130af5c33a824c3b7ed6d2e1bbced1959560cb753917781af33478ffb947488c8372d227e5efc9f5db11bb010c278cb40ead48ae49b2df5f927363a9e78bc125072929ef80efee18c7592271393b6f29cd1e339e512b1214fc5757b1ddf0bd1b9742a0a11ce469a78866b24035d8499c42be66110a624c928641e59078bd1cf6771c7446bd1977578c165695c4d6aa4ba9383ecd2c41677c3c5cf9af096f4c8c9f5f244e5395ef1db825d2593554c7c741ff0e0540f0ec897a1d8cd88d2f86a1aa21e5473b1fd21a8065d49d682d4dce206f4b511f4d466a56be1bd99d1335b17f4170a08899c2015e687f1caf70140770dddc885cac8c29dffa7d5df823b3b8d64e96008f5aed8d52ed710375e34a7743a98f714dbfaf70e78b177156634c0ae931f5082d2c6b7e8d7b1f025802ad9f74c711e218955938b14fec5d0983bd2f44d9288edb72bd1eb41839297ba5915e518a1e57e28a4ef8eadbc6ac4e14b4f61ff5834b1fc6f21a8065f7e84cd99e1d86cc9fb8582fd40eb4f1f1f4e05161cba9e54c823e77f882cdabd8ec501be12e855e0f492fe572311a01e2aa73c9c0c0ef43df7256ce9a41502e15d7fc76a3786dfc2812ba4451ee9a4d159d1052e0fcac791df2027258c5f0ef51d23498d0ef333c59eaba21765783f7fe51db331be068ec4e3e779eb5cd47e036a5bfb6634dae1e4fc719636a3e4944b64af890b1ec70f89b73b33b626d5b3f4c33e45ffae3472929818e1de7eae0f0135937f4e065b2b1dd045ba8372820a294d4a4c9d44af6e321ff565c69ffe8babd43d095509163bbf8a503ec55588ac3c58074a96f3e32499a6845387f9f8b4520cdd3ad129165501d28b68339c1b0b43dd1dac6d02fa89b3c381373a94c1a59ef4839a671b7fcd08c61cb12b6c66edb631988fdead1a818f843f070a66ec46523f8879d43c98e3a4884c8683f9eb73a4d186fb43a343165202bbe8e1735749b64c9ee36f062f2f8129e227ef8d38a7f35677b01f68162d9c5310aec1a8f8ab1365546ae313c90be351030641004c735c2ffb07d7edfdd7434ba984790cc7c3c843c23531593caf985d63c4eef255962825a44a2c9a5c73d1878b6e149fa754a46b77239539851b2adaa293dc29cac659a0d0840bc545401984682144d7b651b125dcbc3ac272edd7e8805e086e7e33e2367beeee06458dd2dd80deb7e36ae6f9d10f84459a9b828aca738136f2dfdec4dddb3dc6c0ca72e2bf19b5b87ed28ff661de8ae64d7dcbfb71f17f362897e12e94f3197e58b2d62eb849a169524ab78962b25288f87321a753241b123b2aee98e60e2ad7341d8e1796a160932c51ab8c6a0c97b188ab05dab278cb64f025a42ff8e40a424858f7e56b27d0eb08746def560c8dfd11bc359b8afb1a3b922bd34dd1f4588572d26401074e4ef4f37500d39456e458b6a9f30b94003fd110987ecec56629a013245b48be1f8df1b2ad80b3097552841186ee787be2e8ebd555253f59e12c255db9967f8f506746b8fa49203e4b2bb48d04bc117338c40a6badaad1bf8f100b8420aff9231d20bdb2e78ce173b12a87c83f0b594ee7225d4d0b975a60ad615f8a21f3a4abf819bad041fd01c740233cbed5e690e6061998af1f0fa406862025feddd62ee72ef314eb3b12d40227d92de05a960cfe96707f9c9fe8d51728fc8258531ad38cb8206d978283436f6b7aea2282cf63b27b639c78abdaa21be576a55388febd14807625391dbb8689896d08ca7d41d28d6cd342426dbcec96d6d44e78739818a757a94f615cfed9134e38c4d34569242c51b8992aa6419c24b4a80c9593ff77d8bc840e6bc7328b69a95354606602f0f8f13d480166c4c69fb5c74fe5874ec7d98a9170f47096fab89d9ada1285aa2ffcc968ba5dab962248471b2de8ac7126988362b845127bee0edadac224e552b0bd83f0a0d9439bf24de27d54243f8106b5e95716d835a7813fe504f195b6f2d28e12dc041f50e31858cc79ed3a143d9c7f4fc8badcfc3a8b756150168ec302ede64999450b0359b368e3acf00bbc9608aea9c5714dda27888d63f60830cfa1ce2b224b854136a204dbed8e034cb5c77f9b86ea2d342bf3a0b37a2fe3978e4a9c7d881655014bb23d8617ff04f6bdf39c01da6a324ac58805396ad35733e42629ef4ceaf840fc83ccdb66e96c6e148256059e3b9eb1e8de429c77f8fff51bc994fe35900059b044c1ef5b336031f3b67d3bd471db0b7c8138b36ece1f56101e9298d7f222fa9f48b9f195f1dd87a869bf8cd0810e424b82cf6841e686f91fa3c443c7e7e547f7b920b774207212de69e7e4ac8d79b45d076b82d8d8d78c9c55aa6f57a7fbfa48e03005bb65fce5548f3fe6ba2af580f5881ff739a098f7c5841e4f1351c5afb3258c39bb39f96e751c043c98b46f218b44aeb90947d291cf6042aecf045cb51fcd687769eb88f07099d3718de8a836f7af203028a5560544f170099475f374f8cd296e4daaf3963d3ac620966584659600233838d0c5c62796df7085b19d42982315cde7335f73178cecd12708124004b937fe29ee2b72fc91b94e2a6a433b2a35449bbe0bae6b866e1a10b4021357e7dabc76c6b9eebf238473e953abcedffb63b4dcf4f73dc21a2beae5036cfec91e22dba6470d2ce404a7b22883b8735567dca179df3d908a725e2e5af4201b6be97f11e9dd58ec44256e2fc223156a07040bb3008aa633a70c76879a4311918a748c98c9f2e485ad45b90b9a59defbfe2741b96904f1619ae66a70180a1c3b550cb2fab06f80d4fd2ec44cfc09ed26da85163f7c51e8357ea149774b77c41a11dca2b70ea2a6f82375f61a4e1815cd019220a8ce7a24b6f94eb3aabab0241c8c585c1d35422268a3c9bb9ef43d3a3490bb231fab37a466723ee47366d71f6131f52dcdb19768a911ae8d9b11e31c946e0a663171d53ec51688603bdea9d2830bc87ebe860c8f7bc1ee1d18980f95ded0b462764d840b70d4dba5e022110993cbf58888ae3bd6dff8f4b2e1acf367df31d03375e45379e33defb73b2a605f402d364d8b9f7e48223c979239ed5b2b9707555a698bffb93200ba565b38453c9452186300ecebb1294db3a092b3ea1ff78ee1bc1f85a51f50d1fca7ca0d634a027ea705ec6cbc10ce51fa13afa4e7e756eed9d19e9c0b8a9daa9f00b11d2248ef3dd74bd01ae7a93ea2ad16fd0f0a8321a67d39b07eb49418f475513075082fd9e0fddb7d225d064d354c2b3f57343220211cfce889e69149b5db154054dde2736df5efc993e743ac1445e676d6401b5039834fe10c49011e3f03bcae6cfc3eb2ecb8f8055d6a17de626ce8caf8d8061f7addb6fc9c229a2b3152bb17e6c40ce3ff89acee7fb5ec800fd18ad698306e2c25146f22aaa62aef8e054ae7730d2dc0477c51b0efe2148ffd7daea402118658bbe0cf265e29a046258d3b3977b0305d30bb496e24e0ed6d997b235c310f36f4cc884abf0fe62b6fd3f164914e6d78c6d4abc9d130a442163b4f2b3234286ab7b361ad062c6d6d4a2908e3033ae5db787717a6a4abbd5975faa48ad91738d0b29f50ae36d0712fcb86ed1820d9bea175e295c0e9213be5226414718842d3539d7eedd89d6459eb50cc34a058b8b453d38890d76893be1de65d6d2cc8d23156e2a414073aebea846bc157a92feee6f6a256fcf4346ea061041774103be4161229c079c5a529e3f375256f9731a60d7c106aea032927baf6b3991c2bfb69433a3f21bdb0271132eb43e027b404cd9a882798995351facc5acea7b2b006b649fd1cdf6628fdca1e4fbbc71006743ac2767501b2116567b911deedf5936175edc26a65a6fcb29dabbc3f8db466a21a08fc34267c557e6371f23b7ab7f698565d9161b0a658cdd82278c7c0f9728f5a63d821260d2b33428f728bfdc32e3f3d3050d2b87e19dfc9603363b2718c039751746396eed60cb7fcf3f7b965503d6ebab7e04faab921a143c37b8fd68260f3f4e6e0ee396876c2df262e5f55d145e410294d1da139ecf80c792e12f121862b6edf6cc5a9de9403a0d141a1d4eb8ca2e8aabb6babc44cad5fd4d647ea147d00e122633575f94b2d0f10a1e34570b0c2232505e7a898bb4bbcf0000000000000000000000000000000000000000000000000000070d111517212531""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -a12619d8176840867fd76c85b14a43f92b39487e19dc0bc5078a6ad5bb20ca92e505b3f93603bb83db02fa9bdf62c7265a7cfaea6cacdcd374e271d3d6ac510ce9158b03163e38327a68a1ecd5250c3d4dd32837d802e124d4fed040f7e14db378d1b8c3609a47c641fb9d9f9895fc968e95dd51c36b55fbbcbb5d0dc8e7067401c983eb0d0e31158e96960541f7bc0a721c2124e88eef835bc88387ce8e50f08da1f192499f6a722f46e2edaf1fa459fa98b753c8bc6c9b494d21d95b76e39e0b296279bfb37a0d7ccbb804d0098461325a53e8c61a098a8a19ef767200de1de9a50867f0860b37f022720d0a050ac9ec738c56f3839a0ecc0a6825adfe08efa4d5aff1314d4345cf74f75d44c2babfd2fe751397ca453a1b835471fb6afa4d33405ec9f3940d03cb1b1baade4088a9958c3fe56dbdef0ef1f7482ad9aab7c05cc5b1d6b537eebcb3453dea0961cfc8c370923dd97b4ed7c37ad628ea456958d98aca0e8a0c94f027e359b3a6d3a0401720899a090cb163b8643b9247f58fffdbab10d76517ac25c3cdb65f8fb9fa8ed5370f4005cdd88ee38c2e6c84ee06857618bb143db9462c256b0242a0be101fd459c180b5f1a1e54a123e0577d38e1616fdcc2480784c25c8e5da8740d132be3f5a498be74eba102bdad5716c9b9af34628c1a9dfe14b44aa52b69e5aa21f482f14d76228d49cf73c4710679e663be5242df2de684f5e1538827f612e7d2e2df673c97b4262990b4af83163041564c8f82abd740f434cdaf68e3ba0b33fa68a63807aee5b998091fb4c6cdfa37b4b9379d4e841054cd0d4df3b353e5c1960cebc031521da09cd4875fcd216ac0a57f3a95db3ccb6415f6da06dcb9cfc1f40d7024bc619a7267a78e0b1b8431e25580915c2dc2b328ad88ca3b551f271b217b0e1f749dd53c6d2de9ac24f93b683f268c2ffdeb1d421dd91ad3b3f9db1af344d27ee4bba7c6add4340277aac9759de7612f64192652e464269e919f73e50372df8d9854471b997fd4d84320fc17eb53da8c7980b36ae1351221d9a8a1f893a897e6043ef1962711cc4babf1b6a08353b03bed793d3d5c1d2da8aa8f6303a5e74fe2570876c9fed2e65db4b73a6285b68aac8d7eae27ea873d07f28d55f98b65bb0e19fd2d4302b5b0258b11d40a5afa0c7661b6394c1d0e533545e45c185a38b98a2f54010c87a58b321b6c5da226b4a326700457410903c2ccd591adda69ed0799543cabd39019314aeaa125ffbe4cd71abb849998e98d781780fb1425d32339f20f5b8562888aaab6beba58ec69c40520ab2f62d1d30b66eef52419196796ca59fd0d990f09f7375a6f32c2a473b2e58ae5ee07d8af938993c1b9b827936d103910719b6d46851d28e9d14189e004637c494f48a0c62cb5cc421ac919222cea674c8bb40fff2021352a7c504160ba7fb11a67b8e7743a11f8be1149e61961e82b284193d965632927a17b0d5dbcbafb732333a7fdbd7b14ad0e74f63999193fbd5613993997fd8cc79fb77b7f1228cef72acb76fcd9187dbb40135d3f6da905dfd5db52c61fad72767aa72c120d8b60e831fcd1e85c2d3a4262fd098e019ff4775f8b2506c33f1ac969da1a5b4dddeaaeae533916c18cc5e986b9f1ec39a374d375a1cfe8b41422ea4b316a50be72f56ab39e6107234ecb087031083b2cdc34076d76b0a25a3dc6523dab07fdc55e88dbd6ab7355f464db2636a6efe2eb2f12502f2ab38acb143058e636536fcbf6bc50fca85b353179f506c8647dbda379e0f1d04df6f785e56486144d5568579250bc18088714653df6350b6618889f28ac4117bd2c82e9f1ee80c29cb9d41541bdf27589b63dc300d49b72e1fd9f9836038396b569b4c02a58ad98e344a5a7a72c907058a193d840388e1f3a23a7ae512ca1e3ae2ad910ef498b19b0678a6b382b0aeffff8aa26851393f602dcf3348a303439b63c4856756b8dfd4fefc601c2f39b68e6274c6bcc58e56859b5d3b22b90ddc5047ddc813baa7fe0302833101a4bd217adfb3de05dccc25bc0f786ba55b8c498fb92203ebf2441b087d28799901452abeb87fbe8e6eca37342e782978f187d471957530379f573fef8d5b059e6a080be35fccd10b1d880609583488c15c49c4ae298a313ee008ff66c7eae1f78a657ab126d5402d4ed70fe9b93f278f2282c20763592bff5e6f51b415717ed651e99a93de7312811a35240b70f8a90449906b62c83a78e6c76449de415c84951001f2bc61c8c99d88c2cfa44858a91d4ce5323a3865e4b85bc281e5139f219d00ae9ef8f850778571fba831394774dfb237ceafeea621d6b32b8480ea566eaa95b4dc31dea36dbcbc8f4a370b7273047dce6ab39ec54ae2225eb64398568358eede9566d2a0a19794b5efa5b4fcf742b6098c800f693a26b3cd8d2834417a471f55c9160bee9ef34792b80f6692a066a951ddc520dd1cfe9354a3229cf030b625e7bc0a2bc60847d7bce334c1629f73b9f4d44ab5f0ba588edbe5a9c477a6c4716e8a8bdc47582b25f9cf94b349ce8aec25c8bf23efd8b393f66ff457a92cab8f04dd039c54ab0d42899410393507733e29d2094dbf57341108082ad11a127edf57d5f9b47e5a31e30c7e8708a00d9dd5d33eac2c3418435ef1f2e9d7b675eced020c4b38abafee74e66c3f6fd18126087a0154a429b40603d4f95a7db725d167690feaec9b9654bcdfd181741af7f0c00b8f8c558f6fffd0fed1b3d3c501ea911f0709bed24e57a68bda19441a3c420bea91f0b43733e4fbf23072727131315314933924a50cdff938c1e4754a05447a09b5b01140b4b095986fa0c5f065d36d83d47974c86c29f09f3bb4306f8927d4c7843d16dc9ad1ea594d742cabef956829042d550137aa38cd98be854b3dc02442c8358a4994ebcf253078dae428d084de52936079da403eca30b93d4ca5f3b0f40ad15052fe501d27c63a6af4f1ec3ce9dd63be7b3c1fcdd539f6d27cb58f9e6487cb95d268caa6f3e98c761bb651627c193e2e9a9b99fa56b4b608990983c8f4d4d14dcbdcc43b56fc8d35c62656188fdacf1970aa4dcd8e4de72ce813150e1ee2c9ee3ce5eca09fdd8e9d518ce0a4c32bccef10e566b305c0a93bb58680908988b84fb90087387fc41b013367d170dd64e11f7f245351f24d054d18ced50faf5fa58c30732874b76163b5e38a0665790c1b49ca13ee419abe708093d80e628d9ecce057ebee211b5dcae6e938575fde133a2ee7a011891c53cd6ad59716a2719c675d36ad09ff8fe60f7821584a21345ffd3072685717efd29f3b977c028606df2a8407c1a60449a60c0bb837dad423d1367429bf85f19eb539997f0d0db1fca77e32014fe50e17b449b0db6a5b5b7efbbe4593e24cffbee6eee071fec63163bd5968431b32a6fa996fbcf270a91e91710bb537ede6c8c84cb7145f78a636c205670dc8cf8db465431b377fa6b1df41c4a44cc89777a1144fa77db35b6ebcd8a98722b3e0d6111037c34fdaa632fe3ebef1c5bbc3c70852ef5cdc9edbf9c280407d213606af1180483e3d6a33781e9a78d8734d72a3675d7575ff567f6944447df15d75e306df470cdc12d6a3dcce7fa21ac11baa4c7f7d081cb0f10f60f02247452bb0e2bd1c676bf47a1ccf2787"""), - TestUtils.hexDecode(""" -36DC7A310D995379B796EB8F9CA346EDF60DEC7F6C00AA311B3E09EF96A6795C4B077C1D371DD8D4A538AEB78B81927D08008E817A6FC6B3F9B14FE56EF9B2664E76112F214EEE848E67EF33B4A4E26A2378E9480CC7D25C369E6C25A2673B946B635B6EECB5F5F1499B484DCCFD5165D6F14CAA8E1EC9A9E4FDE417403720D7B4BB30060AB95C6F227767D671B75A1BB5AC5CC33EF0509C69652748251869B072B9042618071233B48A9BDEBA330F0C450A2FAAE79291B9E2480D1CED11FABE56210A80C39F25E5574356CFAA32E57782145920D6C0D27C3AC7C63DED6A770A5A45119FAA92209F2A066AB90FCB81A886FB87641C550368C1B412E43F4FECC2FD659B2BDA6B7309797575DA2893314DAB058DD92C7470F570EC0B1D9C9A149FE0934D40182CAD14D5B3D98C4B7454CDD2AE7E54EFCD554AA5B458888048BD5201C04E7D6004FC2A597DA781BF15AAC9748B6659EC16602F10AD44145607917C3599A1F53DC95839086A6A4FFD66F8EAC8AF8F11C4F2EBA3B58C46B93D0494C4CDA4E8B8FF7278049D2B4BD7BA16BC57678219EBCB5E211D51A168B5CDF66453412565B9BD606CE29A5A70E60F3D451D4214B0A258D6E9325EA5196C55125F0E115B14FF34FF6B172471C2B4917FC36B0DBDC82D0475AF56249AB9297790535C0F0265D2A853DB0B41B418072D0ECC17CF91FCA86F6E10762EBC520F0AADCC3C79EFC25E9692FC0A66389B15ECDD1377A9C3D744CCCC4BD160FC65A45D4144DDCA04E5408576DBA6D5C875BB4071729361B0514E8B96405E2F48D47138D2D2DCF4DC865F717428FA1262DB0D2B7B1A356E9E76301D38BA506456B4AD70ED09B0D5A1375AA6E132D7E06F8745E7A5B5E4F6455F4282A87D2B372C40A34C09699AA8C2B2E060107BCDE0F9D99B64F17DA5FA01B6DA87B1738882976B21AE12D1BA0AEB37644AAFE5AC20E7F3F631FFC2A24EEFB61DC37485DF27FD9045BD9BB5D3F00B9B2694CB94B01E7A4F0D909B8612DD28BD64E6C1C5A612CB30DF6004276FF58491B8129FCB0B539CDF891A97AB58DDF04AE40BAA5781C3AEC65FD7E84DFD0369A53CF36303270DC80E3E428854D82B08C7AD022BD99AC0851B16C7D8D462DA21126F70D661A59E4D0FE4441806DEC48E37AC4A271F15D916135408A2751CAD53564967196763B512D52240B2B0D3D924B83CF482B5316B7988D73A16B773705097F5ECE0027CCB2C2EFF598B8F61ED4D6BC015E56D4549432A6A95328FE3122EAED0149E2144E4CD2262C7FE7495E41E0AC9FAC9A11E21AC940D25E74AED8EF6FECD21747FF8166589B7038EF1DD504F51E01F1ED911FCCF44949638AA6E8526F0B9DBC5E536FE2AE7D4DA9DEE66402A45CF55D0137FAFDA9207AA7E22FE396455F2F43108961FA6B0339D89EB8ED7EF13B936E3D2DA18E5EAE45B05DCAF5D845DC62CC55553E37CB328AA2C649ABEED0D862E8083962B81B84A85EC12D3CE5B600123AA7CE4764139BA7AFE5CD02F70D06DD9AB0BBE868070A9AACB951D362E2606FD940A8F5BE632393E0A179C2A62151A094901F5625D952D39D7CAA87B77C4919A8633458AD9B6DAA16D1B1CAEAA8075741094FBC0C08D30D9956812C1D3A75926C546ABD78A2B9D44C1B6EF8D6EC2A2EA8B7C23D0EA57E1320ACFB576FB9C575DA98B714D6B01F03364E618A2C03BA84BDF0E5D2A0403B1379416D87B5E022BD958B0C9170E82F8E9A727D39C8F7549E34A14792776AF0D72A27FCF63EA985B3882A717091EF35F5835D4DA127554B6637AC313BA3BAE8170B9E70A6DDA2DBE813A49F045D8C3A65ECFB4D5F71FC75AADEDAA91A81A958273ECF0CDC4512F0D0ACCF9D9D001A30D0B6B2D50BD216D6086AC5C9DE7388A7B1319F2E9E6CE128B1F72F765804E060A8A92C93295A99C66D6D79BD7DD4F7F02317927D60B2E9FD59EC3F95A874337228339EC673BBBF53BF0FE1886A4B14F19CD7FA9B771894377F904EE8BE48D64EE5D40882C684C81DA3198604FA599DA8D4EDEE8EC3294620B6555B3BC9627D4514DBD1F7E3E9DF7B56BDB4CD395A8CCADC184B2B8DEB2AC7CBEC6C96001EDB67E6CF6F872469B110097C69EDE1121D22FB5B5AA4CA540474630651A4F9E8F7B0ABA5DF568D882626BD158F925F8DCE1D81668EF7CF770DC615ED0F5A807E25991EC97BBF2F9E997A532A1BD82A2A616250D2232F72067A17550EE516F28940D8EDA9CCC0E02EEFA496010E499E62C50B03F1D3C1571342DB8A5BDE1F432F7B6163BA3AEF35656434937A42C4E1F473331E38467DEAA483189902364463832ED8C5E04E0195D3435A6FCE75EA3BDBDDB0A0319262083141B1BBC0C278CFD40319647E90BFB51374B0AA5EBF3C564EE95B7AF618669C935756AFF3150A93EDA92F0ADC29253758A6C8A83EF55F97F1A4C0DB566668F30DE59D93D8185BDC1CFFAFAE472E0B0FC4B1E16F0B748220EB2EB85EF127838D576638E738E9F93A05D41CC1264AC6BA03B202D9E3B06946CCC68DC15261A029B0C5E91DD81EC1D79BC51F74BB5EF778F00AC091513443308410F60AC1850F2548C8101DB3B6B4D453541E36F0ED57C2C14F465196F8F1D0D3ACD49CE3252BAA0C10521311B8B8366C579A430526ED58BDE92FED3F0B359ADB31D67BFD212BEDA7236DEE4615ABF13C856CCC93DD02AA28D1CE1F12C2DD69FEA828BDB9F4CBC9242E1017D1063A7BF842B00C75243303EF9060C8EA501BC73B3EE470919443EC91D1F0D6D0F23A899AB86F2E8A0898D318BA520DD15D9B24F4F10A1B9FC52457714A151E075BBE419E4216857500B8354A8445B5FBB526A6E008229F33D8DBA14DD42F424DE3675E704DB308048B2D17904DE46B76622BA08C62F17EBA3E9F414A1B10921858832EEFBC282755B319E176ECCDC32A25CC5E76479AC112570AA86518BB1E6CA3F46E010E8132C0A1E8273403C5C4D7046A05398D461CB6843D70EEF8C94DEA5DF53CA1A4C7842AF5DBBC6451554FC7F9913E56957C51E0A602D882BC389C5E5C7899539DBE6832B0AAB5EF26B2C96CB03D1795179A62F748CA501CFA34D5ABBAE3271AC1F005112645F10863AABB062FD2C781E4573173935B5392CF9E88A1A31989E1B8E94F77CEFBEC591DF6529C6D2FAB72E678C534C4EFF40177C41D02AF0EFEB6371835CB55AE0AA99C0653876CCB56ECA127A0A1DFC0F9EEB49525C9A5786F618DBF57C41C5CAA971A9505BECEA8969D9DB28B0E707C659EDC42280035254E91C522300368F49F2C36211E455FD620DC956AFEE41A2493BDB2B0B8AB78E0B838DA6584FF753BF88CA6A523042A285F84ED90E0FD5E28F75A21B53F618145C16925486DBF6B1E7D76585D0D117EC562E22239E14A49ED714814F01DE2B250E9B3B6A1C99D1A71CEDEEB3ADADF611C4A4F97E1B26AF9780AFED5783129FD58B1232C7E2DB9050AD3D494EAC254DC46B0461A1B4B63840621D45ADE97EE5663C9BD8FB7261152545AE35536611B5C65DD6D66878DB71640EA429F801D6FFE291B06062EBAB9B416DDA7D261A46E58B154684E86176169CFDC4A60EA38300C3D44F9A4C9DCA0CE1BF37DF8F786F28B5B3CC7B0199D3322CFDFD2CF88C5B794C69F59543FB985890471DBC93A313992ABD33691CCF69B96A9396E5F55B54FF7BCA82A31199E5E81CE94B6B523EC5C3E2F2884D8BD744CF0C072E29E4B542DBB370FA5966F68CB20ABF40619E76C099BC7A9A373707707624E8999D4CF0A75D4AEAE113D7823D7D2ABF54FB4E68B8A6A57A198B128DC69584D2DBA473B6725FBB8EC9561D6614D606ADC4FD9CF449008C0D54BE4F62EC1441FF79EB59442AEFBDF1F0976844B4FA3969EEFEA10794FDBE35E89EA52F50AB26319BD1604D3FF5AC660431F1073575ABFAEEA00E1246DCD1D9399939D655C222E19E9DBA5FF42709FC11E7E365D7F7CE2274FBF1738DC5CF5631547549F2BD4DE896C8FE039720F5E0149BD81533022DAEE22B93A3AAB9AA9DA15180EA071D98E9FD176804A5B04D089E9C2D386271A8B13E7D668AA74BFFFFCDA3B4E528937C41D43A87DBB46C2B49B63BEEAAB978415536A87D845F6C2484F21D71D0F904438C46E7B0A3C6DE5ABC01C6F7CBCFF21D3E74AEE96C20C32884DE4EBA0F282C0FAD06BD9CD6B7B5031F149E4788F102D2AC2C99FD09B14A4AE3BD6859CAFE6F5A494EE8CEA29F49D871B79BB66AA6E6EC3718B97E83765E96D5603B209027BBBBCB09EE6FDE3AEB65AB1D73684820AB1FDEF88086B93B6338BEC7088E04F5F6E520E3D715C6C5E5B79E73B9E7AE1C5EDEEE4015860CDB9FA21FB434C3F28AD865042284A7FE9A5FF47E8C6158DD83EDF28BFB18DD5AFA07A48BD5AF25B9644400CC976A9B0FE9D9071E708113802A78CFDAED28378AA4FD6FBD9390D8A17D6500A0E1835652C7E0B332A382576AC4381CAD51A31E64E5E24FEDBC62EF9D0CABA0C8EBD8B94625207D0C8C1C6DF4EA2B20832EE44D1E2DEB799BC97B7245EC404F10764296E5BC4A919EC24B4F5F7D18692FA8DCDD5BBC170A81BE7590B7BF4058DC7BEA0C545BC85F0B3F0936386C37115A333285451CCAFB8397F1AE1B56D0A8F884BC968E729D622D21FA26B89BA2726C91E6886838DC9912797FF2BDF6800665C1D1DADFA4A240BB9BBE21B6DD750389AFA49C5C366ACA5E9C3B31B358FDEC42B0032D9E2C22112E43BED2023B364DAB334BBBE2C3B669EF700702B5D1837A6EC15CEC2B2036D56B8760129F593A669FF00237D26BAD9F9C2F4ED4018D998E555D2C3CA1D53EAD6A1E27906353983D4408904E5FD9D79AFEFEC26ACEA1F39218C36637977F6E2F3F6211AA06AB9D5F991C76F420B152BC95C4BC10047E107CC82E3B00B2325ABBFDB0FFB2966D5FBA0EC7E8DE1DBCC053C4186AF23A6BDF3F14A7186665AC2682FB94B0E10516D500B7F67BE4BD2523E194A1ADD8B5564FAD9105C86B6D16B08AABA604419D55F571F11F4989197144DD12867D1636D12800D54D36FA88C620008095560103366711B8E3AADD5624FBC7FF51318D17311F02A807770466AD559CFDA0AE1439442E4413944855D4D0074D529CA8DD621DA02FA98F46327A7BA600387EAE5E724D64A82E94ABB760C891EE39F27F0CAE8D1AACFE20629DEC5DD9BF4CA91E65BF413FD2A9566B7DCA9E500C2C328F533AF2A957E46D9FB11F0DFE99127656B1D4BE20C946BAFF58E5FE1A9ED282ABEBF6EB35A35AF324DF0A858CA8AF507CE43D228ED81D863F7096044A084DAA37ACB6AEE98E5A94D363963D4F852B955C2F076848092E6199E07990372E56BA1D590BB83D0C7F834C852CBC39B666B801CD32A0C36B034264F3BA6911A719001FD0F4B63D2D628FD0CAD34B4C9355534A8A38512E758B110F48E5A09B504D20D178508E09B1423A1E61164E7D138B4A9455B95EC8EA786F5FFE67806781F1E619505FD7DDE9A904E9003CA7E5EA1077C94C228D36667031502D78B3B52C3B5A09FC398D8B5497B6E3F0C5381BC99DD7B11DADA2DCFAE352DDEA2C749F8CF5AF39587083C2C19576EFFE871AB94D1C7CA2183FABDB74B27A80FC4F20CB86B46B0B7F86384540EFF1C888168F74634F2C0BF7FB54F7002EBF90B6C4B2B25DFF068DFC7D087A27749D6C36AB0A33423044AE027DCA8C42678987005FB9DE5C2774924AD2A5A8FD2E89C288975F89B5C0EF70A20EDAD1925060A12606A9B03626039635BFF332A0E6BDDC4F5DDDA209AF8DAA0FEF045FBEA9523D04458FBB0BD81F65396938436AFF5FA66E997AE58D64E7B5C1B589558B3DFF6D035E31008D2C76CA426B07F1644F609945909DBD16559B36461CE882A361D0415A9D93CB98A5370C56913A299B2DD1AA372CB75C7E590A9629CAA6C439CC5C7D94A21F36F998C6FDEC1C1721ECC500ECE1214EFFDE65E479D38C635EA223286DB326EF9B19B3CB862C96C162D3DE238C2948E7613A0FA4843E39EAC51EF293AD7EEAFF0F522934C982890F83E922B2BD52815136D0A758B33641C54E7D4E0F3B19AA85859B750E7A7FB80892C3DAC5048767132E2DAC5804709B8560A4B3828B1CD25DAF263A2466AF7FE328ABC84EBBA26902FFD92B0D765AACC0C0DCBEF962E1B35B1195676E8A67ED593B23B2B0305B611F9E16633E77E3F31794C58C5309BA07DB5CF9AA1CC108186318A3F16A7141854C2FC8B469BC0F54BCB22976A3CA05FC2C8E23F1B6A891E7527F204ECCA0A5400B68565906E795FE4DAF52ADA95A9883676F9110B14CEEA389CE9BFFBB5D040E60D3D03C4E6D6CBE9ED53EA44B1AB6ED7EDBACD0AE0613DBA5A5C673A534D48B539DC85F48175F13404016C5289348504141338FE958AC28331853AE80ADFEB49A6637936BF82FB26B95295B2E46F4F9534720A4E86FF18B31335877C9CBA96A9B450C1C8C9C9862E51CFEDBE3DE5C8B901D792A179AF9A782C330035A14CE6A710D398BD28416CD72373FE216744F6237B38B97351A77D5D0DEA1A26A0A9A24FE15503240933E1CB5AF458E6FCA8624669A0DF439CD7FC13F7A1F10A0CC7DB8C6AFAD9C99B5FC45A7C565B5DCB74FF0EF426FE7C260D3ACB1E9E83DD8E6E11A642145BFBB7566D582D0540D7931AA28B7F8F682E6E2D90B6E6812FF8B7F15FCD3DEE686DF06E8E6C456C99C6B4215C4E874BCEEE3B4F94BA825C6A45C2A2B4C6DC04F8FF5939C74E7DA37E02D8230340C6E2AB7CB82BD226DDC1A7C7BD0C0FB36F71F9C772233132B8871A0D76728C2A141741C2662438C5CC7B129A6C8FC587A0E475545D176818B51190F0F19E91E05C04477283A0A7D4D646EEDA3BE64459780BAC1862D83E6B99C5731DF91F0CAB454E70A0D94D934D0CD83C8B8301DE282F9A1FFE49E73EDCB520C016FDB4AD02C261DC1A1E73E38809E60F91A4E38C69EC70D2A621DF0D21588F24CCD59D331C69E16F0F6BCAA8F24031DD5718875BD9EDA5B420C116E4316137D4B77623C9D73D182900BD7A0F90A193CD16107E692D469AF09F74702492E22C796B6B4A960D47FDC571B4A264EE3528A0F5A9D66DDAA33FF20C3101D50299EDA3225834C9429976EC8E590C6D48A721A14972BE70955EC1A0348D2F84347C1E8E21EB0C1FE67223B42A6BCCAC43648F3BB5464121180F8E3E682B4B664D91584AF55FD1C7D2E6F79A93C680238D29CB7FF36D259CB703DE03B2EEF6DE0CB77AAA8F49C61EE482A8DAD30824E603411D5F09482DC84BE794BB6EB65A7BC1DA92C8BC8364AA88D4B8212561745BCF3CBA0D6AC8B8AF80373DE3F44EE39CA3CE4C5763F422CD4E8827B1E7BDFF79DB990A52530E4A1E21F6CCDF50A322A086AFDF24EB5FE4D99F1D1BB4D6DA965D168E9726FF7A4C82F327A748DDB1DA5A3D0E9C8E0B060872B009CC9F913D35D94FAA912B0D6FBF233DEA3AE3C2A4E35BBCACE21CA3E5F7A7B9A486AE9D7A7D2E0B79FDB11D87072F1B307402BDB22746B86A1A0E6B41433D5BAEB2048ECA53A1ECF895E9EB9BC5D6AB5D5DF72353566BB90578F12C6A16A163E95CD35DA27C79379756141DD05C315B466871E2B726B8821FB6FB439B49430CB3CA47CD211D03DF40AE4A0BE87B6000BC9C75AD23552E2129F47AB64BC9E5E1620C99405CEDF7BC059547D547E2868A6D470D813AA5095D0AA4BB18D91964988391EE6F05DD47CA1DA0423CA238C5E50D43CFB0527973506B9F1DA4A8055C47D1FA1E0DC783CE3CF75FFAADF574EC2849631E2551368291AFB5F2C40A4F1A184E37A19E511F482B7920F6D51B13065E6327F3C21DAA7F73986F2D1FBF375DFE2505C0FBD35F403D253BDFD0BA1B00CCC5A20B683D4F1E1F2374FD914C7D674901A0F01BDFDC007E8021013BB9A2F885F0699D16805F9F2511A0C7D3CDC06E36679983A2A0F12662C88BB7DC643FBFFB58CB51AAB3CED28553910D063ED8FA37FD756B79AE4151521450E552E4F2B62EB6F6BCC8086BBBD30331F3F2534AB3ADEEACCF2A6E66F205935A167FA1D5C747936050E276E8E4CCAFD9E0A056E4AC2AC08738BC3A598F07E933B0ED285BACE3D24AE6FF7574351758F983FD7EEB3944473EDB4EC9A9828A5FC656BBF04DC623C75F8B8038F3699BD5F255CCD3EEDE4FEFA12AFE8F64436DDB1FF2DF100B09BEC657DC5D2B18E5722D5AB30D075D9A52A576B6F9FC8C8BA3ACA6A92E6596F688FF5D2A7E3183B696AB277B0B17F004843E58760683F90BE0C61DD0D1BF9099A865CAFD1BD1D8AB1B7D4AF2F86D51C18D7868BEFF3F6C53EC68FC46EC9F23D1AE1FE85CD97D8CECFD57A562E7E574ED1D0A7005813EB980C2A46A98CEC602C0E022E87D4A6EDBFD7DE9FDA8C02EF85701BB1CEF6013F4869D32CBA56B0AD6EB007591D03C76A839F9D01985C546C39E49D59395B10346820324F3E298C5CD977FC2FF83BD422CA550DDF2A69607BB8125647B389246ADF0095F22692BF907EC86BF8D70D7E8F2C50E35DC6EF34FD1258E1FEBA0B254470D43C77CB0073AEB2D4CE5F6772D49A101052D8CE943E1C7760F2994071644D27D26BACA88EA07F29B2F2050BAC5E05F2226F1F584D17DB80E4056B7F9C60A5D9DA0CC577C6BC802FAB26E570BF017DCC7236A1173E273397E373640ED02B4F9863C40D2A2A7828C3875D8081AEBEF349143BAAECF9089EE736EFF0EF80078D2CA7942FB24A92071D229A1FDD0F6A87D362E5165D57F62D927757BC31964B5DA63B90EB3591552F2B9902E2269A163FF221863ADEADC9BC92CAC0087ABDA02004C0B9F34E5CA8599DC3C4261489F7527FD27AD2B6501E602FDE47DEEBF3F3EFC0166B1EED95116CF43C8AFC0EF89BDAA9ACFB6DAC613770DEA78960C99C9628C0D21FAF63A0FF7A3F2733EDC0FC07B83F107A811BB3C1DFC6CFBFEC105193272A4BF915B1DAEB232E16216E40FD3F9D9399B15CC4C073BAE8D08A4EC42D91609574EB009A9B52F06D3F428F6EA9B0511D8319A1B1299C154C94B103CB586370A58F18F04F5D21AD3B638660D6C04E99D356A7289E37EFAD643A5EBB488D54F4A0194FBC4283A8C4ABB8D9A1D70150AA50F991204C038AF54B5B74F722CD6515045D62276A9E936476F42B282C3B08D9328089AEA259510240B95BD5E81FB9D7E006DCE0DA832BD9A833799E05CAAFA6305D16DBA4461BE13D3CAA95773B98F09230F2DBE13936495C2DF5BE3A8F3EEB4FD211810F4B07D3E2BE1A11CC87079DF1B32D44B6FE7942DF2627AC19FD9F584E771D7ED98AA4C074A9DA5B7C156F83D90EBBDAE78D636D51EB0CB30C7C7CBC1A96273C0AE0ACAD8E15D1196BCB2EEBDA332896BABAEF76B4275F863732D646C24627AB014AB602A47594D6031795B17144E6E2C23F0341422886C1E2512222ECD530017DA02FC015EBD5BDFB319F3AE942D75A55C21BF347A44B300ACCED7A339007A2527EF4499E3BA5DE334BE58D59918DD0CB55B2F478837F71E9CEFCBBC90808E0BEF8CC7712A3B008B69476C61535FF0787B7833B70C69B1EF506EC4F445B72AA12FAC2589815874E9123BA13A17477D61E41163CB21ADB8151658C99F1422C71A8183B8D0B1D489EF436564C47ED8482A0DE9170CD1BC34D88CE76E1B47B84E770020125F718B4AFB1E4587668634FC7464114762A9D74A93E33A5C0CDFA824CACBEB097B5CAC3B554BC0D41C402812D8E43DB37C730A6219AB6F0BACD096BBF261C78E991DE0A2278DCA7D1BE0E5F2FED72CA38BAA86924A84275BFED3B91FC8DCC5024316EA0587C96E030544F631076DEF65F05F98C7641A958313686B8580CFC20221ED50DE4D2CF32461FAACD0174AC46A6949EF8ADEE6FFA3F537228AEDCFFDB2250D7BDBC848AFDFEA67AE53CE9ACA45F349557E81F70F9DB92926FD0CED8C104E6B7AD180C7B3BEB86171EE84A8DD2C243F6869E04C2DAFDF0C938C0768415C56330C9BB6EE756BB335BAAF96EEAA5CB52E554E39E2435B0731B0062376F4730108DD2F05824A798DA24C239724D19F12C6F2FBDB52652352021E0167F31E0F5941C4687DCD13A81A20A0AF05A55D2533280941865DB4D5715AEC293A64AA2E5151C8F44A14B72C0879499027E67E4E2B487612216F6122361E8D34E92C2163B0C88583E3887DA93A3AA0E77FFAE3FE8FD5455BC86AE6D6D5AC7CB7BDF156A960C98B0BE50E1370A43E7D183636DEB2C64B264FC5922D4BD46A8206F911E7A742E72E4EBDBA39B6151AEDF5A6CB4157B375D9A59899808F1838C61EB4388B923423D3879E8228AFE0CEE9561135849A89363F84B41BCB166EBCD0E65A2A74FE710F2B3B55CA9DE2FA9DC163BFFF4BE91F10493936FCA15F5F39422C75233DB22299456D1EA3BAC26F6671557B2A5FB0E9460997DCA797C67C49DF109CFD597BE34C8E0FA0353F28B815D0CEB31DA93E49EF29CEAF20FEB0A8F5924DCC62E830353463245899900304A8C8DB5830BC0E97AB83853D8EB05660D6A9303833D170E138FF6F1C30D9DD64574D5F875F974225DA81ADE3D97924A38F552276F46A5208403AEF82D1E92959675EA6B353E5C6091034A295D9C12C288241055A2334C30DF0A37D2590626A7D1787A4F591A6E494BF55ABC76842BBBD508FE54C5630D11C54386A487A756ECBFC0AE8957E7CA8678D5B9B044117365AEBE79AFF2E6678001D23624"""), - TestUtils.hexDecode(""" -e8b08c99776fe554292851f9d80f785b8109d6edcf9d30b4b3c8c11fe8b2e024e333272f4d72e697aa20953d03f013c0c3800e840aba56daf36846b0e958f7e1a465deee3fae6e45931424ac278b6d1916dc71760b7518643185cdc7b06b1dc0a54c83597e6a2aee0894c2066b5fb1e2439b2782ceec63aee1742d10f4c36793b845d5b86db9d22a200e12611bbd102cabaa00ed5cd47e6cdbfc06d7bee55e65e4ebcae019ab28f0f05ff2efcc3c44a5c89a5e80fc8758d774ddb3554975346aad922319273ea930b3718562c3a96602645c58e375e8b78f38cf636b42e674ab4c5e1a8da59c64100984605035e1f735d6ebd2948b556b056a07ab86f8d07f8cbc72cb7251543ceb39a9deea50b8189face6b5ff23bf62ea3686fc0f97598f36ca445942cf3c2acc5258f9a870eba919b99c75bf598031edb693552c086377ab84aed818e795b70a62c14f84d5d01fe9257cc9df2f4cb2f40173be7d11592e9289eec23ad30a8e5dfba2f6a779464e79cb5b07e6e5a19dbb9a829eca1ff64c0a672844ed2e636903bac6edfce1315cab8751e9f12635160df14cbf5ddd341824e8033507de1f6cb7dd87c5496342a27a8746e94da455ddbca610c7990ed01ae5dedc90cee503d525ec5033258465e282cacb2c0e0ea7457e62d06c194a958322e64a5433e4936292fa700dad6fb7ea4d5689d4e3efff132d61493859aa5436c9087fa9ac5b67419a836460fc9bbb4d53d0c9b6fefab2d513b76f0600d097b0c3eb7d7a82e01ba3abed5354fcbce02cc7e85fbeedefde5652187fceaef8e6c05b4f37c33a752fea5af6160a7da084e41dc7134534fda67c4e1c6b8dabf7bf05d25a0ab7e05c41c4e0070e8add04f20d8c72bf941ca284eae27cd9568e9938adf4f55ab2c40d03bb49c58c6fd8d74245cc3b4922891b865dad534e256ebbcecdf5227b39ac335005bdefe1be10c2b7c969f4dea6f581c278f8479cd7a40a6d369bc5e1fe5e074230d01795dc664e488e4e360b169976b99a0b9d257badf3f397ac914b15b8ce4b3c38e6c758a169ca015fb6fd339c4255c51013e7430c991a006591fd69a069cc2f966c24ad78b8c0a4f4601ea08ccb683e8d427d1a0db844308e86afb0e3f6965af9ccca755b5e2a8358fd2417b46bce7a69b2edd6e9b3fb617dc5bbbf2803a557e33c907b4ee7fa7a9cfd9f148730d48e471097526e4330515f3dfd5e4f0e6c6dd2c2db73c2c0913c82559032c15b3e580e3b11f5c319db8b04ee4a3dcc87a4251e8ca8f77a8e61d67a5586f2494c3be2d70d95076e6470cd3c3ed1b780ad9217153fda872911bb01edf13c13143e4082cfc9fba96f14e7844f3ab040567faef1f03caf66eb10d92eada39afc6d70d16325008f628489ebd9e80913227e270a8c272709658aa843a486039a21951467dc1e5df0feabc68c28ae9e9cdf95f7db12cff0167657328985f19595b5aa33f44701a8f40242a0f33ff9829078abc53be36c002405557c61b9c5585f7d61d0fae020b2ad18358a278aee3250b12bc7f0887d8cf42137f26ca12a866c35876bdc737a22b8a722e71ef500ce958723728aea23748924eab3552a7cd4142dc7e138c84df1251a2ed8f94c939bc7aa0ea4c0ebb4cbe817aeb65ee5f0f9cd407899459e719f0558f8f40d73b1226a004b910e26648852bcb3b08aa5340f6ac6426aac89acc4945b180dc4f401d97a6fc68e3fa4b8ed65ac74727e3ee5da732b02caec13b88cb167b15e4c7da21dbd937549685e8068c3eccad584698291b9c3410aa8314762fc838f9336b6b09c191409d1aa2dd5e2a075b070413c805f116d42f90af6c7ebf8c322bbaa14a5692ac0749ec7df91e5eddc7ded2dd873907e07b01f14fea1e0efe6d7a1a5ecb95f822be8f3a2f65224c3d801284de6f29a25725c3784d7bccd1253706e107fb9dedbec4620c87c615f4458c4c7078a1e69a0f5178b318fcec51e73995df8dda6ece7b7267d28daa1fbe7f36680fc001974577e4a128282b67819227e5d100baa5101c5a1422f096083b3b522a6b71f8943b536d7798e86e18129d1484cee60ac63cd849f5c9e8a58fa42c0298e3d595c3c4f145aef17f79fba8d7424e5ad7d6831321e51ac88eb1c54c6c1e2f3263c899550b65cfc52da78b7ebfabd474851b3a2b5457f4e646c15ff50efee6a8ad5c99e91853656255fd429e8982c56d65d005cf3ee1a725e224c768e8c92003a72f3060cb088f7a8cffac0d526c028f3dbbe84600d5a9568f03b2304ef37d5ed28941169f8e204a1240e6d910dcdb901932982a6d45a7a10b1630587d31551b6e4424fd929b5a7fee3c4a20929102f5791062acb3c53a6edc93ab5ccc703b8cdaa39857ab06b7f818a59d8324dd1ab342aa1c3b0a32dffa0512b92c1ab9a4f66e57e9bd27734ce2b2788058637cbf94b03b7a1b640f03735f36bb36052bb461c22fff6c0580b6eb4bc572fabc9a141c1964d664168116d9836f7c7581cc9537bba32d1e3e5519e29858f889e282c805084fe3a64db0234bb3e1dbf57956ce4165795648f4865c1232e24a6769e24c0b271aef1146425a9032884393d275fb68e3b3c91599ee82a4cc34338715a8590f436e4185246df9bc4c066ed975f502b967a5761c1b8f5aeee302f96aae3dfdb6f4519aba3e04cfe5c9b2d342048a4c2721484e9b311c9a18ee5f726a512c93a8d37cdaf6ee96928fba315a4680dccdfced6a13f46e06aa162a7ae445bae5b1134f1656a2d700dcb2b5138c780b428d346feb98be8ed911de7aa5ebd72e2a6a8592a81ad4fd6a6da64edd2f5490cead76fc652998181018457f1cc0ec4f4588cb8f418f1b6d801635847914c3f317369027b4c4608e65457f949e08110b23dbb6941632afc1d1292c55c169965f0153ec72d93498f5a68140ce2c8282a59b1011ac705fd5f0a8ed1ecdadd58d4a1fbd4b09e94802a0c67f2f5faf905bc4a35471f886a8f2366c25b710eb43aee8fea692d12b4f94513337b0ea9fce3c255188ab7b432ae37383470eb94abc2554c6f165bb356415a1f8d8790e1bf76f4411c8f32fc550e38a0ea7b8d37537855724c08eff4730484e55accb2f975637b74f29937c19fdedb5aab7d5a3bc9ee1df2c83ae8d0e59782fe18b3a17c82cf649a4299b74f022012e189f19d88b06387314b65add0720aefd0018a09bb3d13cd63f98fb73b8a57564137e89811d59f1c74a047e264ce816b01e942038574a9d1f4fa5408ad1661c31bef7e97742aec79b74df757065e8e1b059b5134e53cc8560bd87e9a68003b124b15afb6534cc6181b6b71eda535ae7a3c107abfd2d8e5886cf8a7d67a4b723ba794c0c5a9d1a63f67a6c42de3e3632b8a9e7bc7eb9a5e404930265a7d04c1e16ac17a7b5e1535e1bc80ddd1800a7ba1b0d73ba053688137e1db64eebfa9b5dd8573a51db93aeb0c6c644c97ba9dc87efb2a5d79b3e3ff396a45ac1f0aab064dd05c1e6ae48b2686d662b8bff1e87db3745c7b3126a091e688091d84d3caa1adb471df496e79e42b276088a600a6f8d2aaf3d31b22f7e7efd2b894fdef314f2258d32371fa022e272760c704997b2a605b0e1a8d0602ad3a134357b0f2785d79c557cb04121fb054354608655afa7a763c8276170c13f9e76dfa711e26ceaa999fc14c686e2ebd61d18e74ed08fa1b872e09246856d9e0477e5e21a72c7869b57785248aef0d516f670978ba4dbac563b77f365cd46cecbce0b7fc7c9fe7373d6ad47d094b3669849dc21084124999ed55f13106d4be1e52433d86ffafbad0e4f221c305aca71063037b7a26ca73ca37129aec69e665cd2e70a94dc5aa8d22e1a425853645a3eb05f8998c6d766806087f14f08fc95ae3b2b9190721bf536ac20cf49222f5a0dd03307995adadefa43a205fe9dc839b5f27447611a93012d3abccf3f5d7a766756111dbdadf6c5920782545c853ae1a550a08b14a87bf296ef0aba7669fabc13a8d0d85d67e36abb24a77bf87bdebbcec1e28c1f82fcb95e82ee936f0c1a60a38ca3ab846eb39cf27acd9a219abc2c6244878ee25efc38a6552773b7444e466c24a15458df3cac856201a12c3bba6483d886482d58112effb0cd72c7aba4df0c11474a41e1fac0419495166d5b88b7e5e169c96c9ea6ac96dc5c2f749c858ad524e7f3d32177aacbc836abbea91ff9dac9d313a8004a186ab52083662a03d42518199bb2b81f9b03501ed8d1e8a8069e6a4fcad2657d4e69c0cd8e4ee56389d026717c72c99f13b2d21780c122bdff75c0469f32a1c519afc5900855539b1c75a3019342b7d5fd8ad7fb02af96fc94ec29583a48b964c65586a6f17af9f268a6cb9bbff237ddf393dc40d03b69ce5925a5fa8af87a6d0f497ae82d6468726714f7b53bfcbb647253c9db17a7bd5e760531ed90d7cf044ec0bdcf9724b640a201f5a08e223ff20e818e16e88fd92300b07e89ca333bbc05e8fd01d847bf9d7ce85da9478833f5566662888c8238b70cc3481ce0b8fb5c5e144d05ca8b8952c4374b261e48352bda2bd2e8de39b6318a0cbcfe3c36e6dd924e52d82928e964930ea6526aae08ca596fb732dfa02f2f6da72a05a227648e1fbf49554117aed210263cc6f5ebdfe2ba852d1c4c4af8f71a8a6501927109026e544432504a5bd066d7c03d443a191629a2c67b00f634023bb07c676294159db4df69555ffbd6c4b5a6d4726a54f9a0ab243cac6ff603e2ffa3c4acc6046a849b099654d0d894ae6536deecfd326aee5164eb1a59838da8cb33724697c17d6735687c860a13c8b8fbe497b99c98b58c8a0f0c67e1239b5a0880c1d4b0e2cbfe268141d035c02047d0a5c64c4fc79f245e50c43f3f64130be4b8def3085330461a12b1cd047afce58b05d2d75ac4980376a2739821149c95e17dee53f6da1afab57c02c7cfa3652784caf90f6f66a93966c636a29df19b2ed5699ffa1aa0cf5de784f5b57c15ccd22f5963924fc55f997b8a508f10d8520c5498f3408daa04028ec66b3885c5495e10666f8125f4761cc09071717244928ebcb985cc8ec8ac777fd411b8a2aa51320c60f6c71bdcbae9f6e37eea62c1f595ed27bb83b25842d2e26988d48217862afade93f152155166ca55c13c143d6c176208157fc8a836ca68ad5094de00d82665b2675baa86a6012fc36593e1c9aeec4da750c5c747643072dea8fd786738f5e788e36767bbd29a87ad1731adc579396eae378f8c4fdfaccdba49304649d108b19dac8caed2d08f116cd33af7bd22091330ff4e99936dec531ca9d735430cb4a0cbc4652a9c1c43168b1ee012a46b1cb92d3035714eb4f7f4d6b63b60589b946e5a47e961f3c575d13e1486d9a388dff8c8e9aa4663e5ed91cdd8d3d59f02deb394ba37ee4a05df162208286c19bf0204f4d609b229087351981b6e62fc580ab06ff34474db029a16466d9630eb263de0b76e8b53239a044f15f90c4836aee8b2203d6db413b583d62c8bbe7d657b2c1185a5720457a79f621bad76674112e28c34ac65abbf65e73f54f918d0b912c429b29c5c32a370ec1810cbb07375a85df5167b32a321844cc54c34ab54b87fa6378924e54a874ab871c928d49e704dcaa40b88d7a7c5774163522a6620abf5d73643338be36e5b2e30659d0e39695fa97a6ff8cb8064e370eee36c5a3b57de7d218fa325646cfa4fa2e9a0622bcf139eca8acc28de6f0a5d2e37dd2b0d6f6b39989eda0de372b20e2cbbde73857ae39b7f0cbb2f4337e04a52f1549bc4daf89e484b06177bc9cd6b199906b62789431e4a29251cbb4539c62ea6fdca9c84721c02b8af585f64e8420a7ec91e6387a897196685ebb760d1b4276cfa36b51f4d3e840e2c5e074c69ec7f6557afad4ef6774dde534f88cd7683a6855bbbf8d43d520cbe0312c9e189f710c75ad64926a97ca0e3b2b575e3aecf7b9145c160c415f8c90160aa5208744addd8b52580645fed9c66a2f6d8b0afe577ff63e3fda7e9a25519f0d2fbc3bffa9f45c40f70452a78b903d923e4f0fa9475659910f75455d144295e4091f8a760e1e68460227d37fa6220b4f0322d61b8fd7a40275c4d9446255862682f775176c67d294ff45205726eb733e5d21302f4df66fec98102611e3bf8084035b42448e86ff9225935ebf7db9a847e8a0f72ed177fa3812f4f5c0dfb7e452acf0e1a23d781607de22bdf31177d5eb5e2840bad442feb2f8baeff6f17bd63ed9495b0351949ccbb6337d907831e22ed31cedaff7cdd13bc3de40421ac6afb536ff89bf041a3026ce04316b6a082c06e0437440313ffd36ff78d6e31a4f5652c52e53f06fbeac2a7f13c64c061dca9ce9dc2e7598ed90a12307e5125397629887f0a3d3bf8d24b675db85ecfbcdf8b3fceb50e96b0a863d30a7791db30ce4cafe8d85999ea1282ba61f667497a8c52a2fa3bfceea070b2e8a9cd8e51a244b73a0a60a1e4076829c1a4668717495adbecde4f4fc0323325d71aae30000000000000000000000000000000000000000000003090f161c222e35""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -f5e15972ad2246b58dc056182273172d39b05662b5048af41a6516a04e042cf2f0c5ddafb57cdadd0def1a82bfc1a4f6fc1c5f2e934016eff45dcaf88535735c50f3bf6e8cf4193e53e118a828cee10640664ac6fe927f1d3317e26333d1320fa0cedacb8cdac09f35aa4ffe425e9d76c4dbcf07f5853c521f80689a8f8dc36b4ee2c2de91cbc3ae01cca416522008a0372515438a42398b3cb6e8162e003dee631a0d6ce6ca42662cc5161aab21dc999bf840665fe093dd7f3eadf35eddbd3d5712b49735724d367ede964eda26337c412310bbb326b1a83454d90dc2c64a477db6c90ef3a451a38ab814cbab44f19e8c2fc24283ec18f60b4b3c683954bc78afb64ab8e0f6817ae0095b14c83604b934cdb75c263e99bdb5cece8382539dce358adddaefdb2a568071347a68f75893fd210057de0bea4c2fa882a86f120934c72a94dfc8629ce6aeb024c5c561e1f5e8230d830b0a593b42ba6d29c52997256bb9186446786566d9224120d95e8c1793aaee0fac3eec75aff47e90547cb7b42cad315ab5c0813ea269cfbbb4eff999002de0541ab117e6d374b9f956f44ac01371fbbb2cbfcc47e6696a16d1d731f878ee362f3355c6b625a9f77a9455b51cf54468d1a71580595dd4c7968149a0c39580016b1d01ad59504db610f7891b5e0d2ffe9bce4a2f32d64894396bc6a91aef4722367ca39e4c723f538d4e8d444d0e53fa8f434040751069e62f42a6d8ec29950b8fba9878533013983c8809af7e8252ed9186919c561c12a39a75be5dd4d1a8a6bffb00d7b305f13be81c188718a128b98c5795b2083fd221e950898c6c929b5b06b1e9649025c68a6fe0ac6b0de9a8acf6d53dc361e3727527ce4100bcd9a99293e85c0cf2c6c4e13b349c1f2b0512278661b3e1d08420d15cdbd0265b6eea3540641b18e5f301b63cb46cd7c404c8a0e5489f072da3cc013f7895f2d368dc37cfe65d50c613b5dd6b2d1d27bfd074cdc20062c00d8a32795e61056a4287bfc455dc0c9a9832f188a1f390a5ff3c7cdd8416ac997480982935480bad96c215079f32cb9dbacf094e0f36fcb701d834ab851d98f478acc3fe5cc352d8c31be7571dea6a4f2dc003264a5673fa9a8254fc0bf489c39baefea294e808fd6ccc6bcfe724042b9bc3e2d57b82ade7f3a85519829a1e39313ed34ffb00853bc3cefb0656529d7cd3557a7a3fea8a07239a9d2eaa4cae666b4e77bdb04e0cfaa75516658d53f1c99d6122ff64fba6f01ed7ad50619a62d9af7325e549ef4d8bdd09284cf10432f58826d29c1e3c06991a04affdc5d1af3aaa7c8bcb5929c20fed0338803db2db0a3ef6cbf4745c511b0824da52874b1f3e3efe9812017b9eb3dda24f12e8713bc5f23c4abc34fea3ff86489c16e12d5d1729549f8140649963dda606affe6884a7759cdbc9c7d1f7c0ea84d0c8b42bc133b43d3cf24a404eff4853c458d795c1a3097b6350223aab7b86aa4e9700aa0794c0993dbab8ffd4ed89277a51112b20feee0fe66207db1e9b98059a80c6b0739f55859eaf867f0a64c08596cf08942266b61b391ec772c2c809319d177b081362e1ee216cabb281e79e896d093d13761fc0b5589db0d72c1995e05fd4b2095b57c24917b8974421ffcead3900834ca801c841dc4aaa46ad0e2b8b64b84d66c8668aa3d78ef19c6e13eff3d3d45be3b35fdbf88845b868df1bcb25f7ba7b7e52542b79e829682ce01d55b254fd66119cb8583ab33177b86b6fd92ceade0a8471016a3ec439df031c9b15439e0295a3050962bc2e9acfff0da13b9ddfdf864b1091df92132e9120573474fcc15594d9248ffaa873d0597e77d63fae88a69c0fb226dbb81b304fb3b9f3869503c18aac521938985af600b55dd67387704faadae2376514a12cba29dd0486c954fd48fb3e36d54d72dc81991275c17db80c900ee6197321ba86faae1404c7d091cab83a0e4b54d39b9f2e3bc7431da20263ecffeb3b732c24e81a814a0f4798739d856d89c976e2ba1910d4fd5fc4090322f7ab5892ba2b45636e0eb9ad7d39a1fe65f6917ce299c862682fcedf6a357f82df9daebac485e5c44213980f1042e0c5f01221ffc73495dffb389a3a49fa323338d123dca12a11109d3c2f983f13b79e35b525ee2496e9e0daa9237ec2556af9fefd3d79fba73bd291b3de7f95326d60d029d418639f0a6724fc6c38f7862a7f1bd84ec9f90f090b5dc56d2186987f4b2ecb491f7f271151c7c270962ca1337ccb7fca3e32985e370b11985dc143d5eee404af8309e102798f8f39c829c693e1e9ceac552d4a782ac70758a851caec473ff3900c52f6f5c372df2a132cd4f216c5ed6cf4c9b827ecbe313b0254dc163389329223769de91631793d8325704768bc824994b45c3084c9498669d5b89a2d39a5fa83d27d41490a2c7232c8d26efde3887f82ce24c7436626ddaa2b4a049e84037a6708db1948ef1b95913366b695e4c097fc73e6d1d24b670c81b57806d0fd4520f0ff772cd9f7833a6165b6a9e4a0b6b8428c9a21f34f195c4057e313da89a55e21aaea8c5fb9165385d0e9d475e9088f7fa701db2bf4fa32cab7851cd538a6851ceeb3a21a44bd89df644c919dc95cde8c946d2b33ff19138b33d5a81421f47b9c8ecc2e2d9cad606216e9e35f4ac025f3c49aab0db157449ac7c471ca4317755b26b3561d279aa193ab67d91da3e33a7ab072888f5df300c0ccaabb9d2cc34522b0e865b55f850bcdb835a10d41befa6fda0f84a86877e6c83de62ebfb5bc7c0f291282a70bf3f6ec5b6109c3d9fb30b5f596c8177f996d3b4a91eb113de00361ee6398ced54b65ad054cbe1bef0a9586f2d6fce45358ac9da2f62a1285e71832c762265128c53836bb3d488bf13a4452053a6b2af4e98a32996a5218a761d3a847b0a2abe9f222970f0cdba9f40e5e04ee155ec9cb3c3d5172408d7b0d99b93d15266be3c174fd25729027fb02b23ce3304b5553680fc6bccbddbf8cf18d0290c865d55d057442e37f02726c89affc7016124ee3e7cafffde04f8f6588f63266bb5cc91169e954d98502a8fdd9cd68e786df2e4d512dc4a05a58945f2a4e66651d4c53f921e234c7f24fda5402570ff610f56c8fe45c5947f217f7935e4f7014bb14815b9c7d49c5c64b1178fdaf39db843f94e711658a13178a9bc5d46f0adbcff5232ab09b84ea33940b94fd8fe885c5c7fea6d0505d675b8d602f4c91893c09170b6596bde36f3f118a8c375563f94ac6d7a19d581f31332588f365608cb09bd01d7f4e5e01655578b28a366379f760e6de3ba8d031cdaba280349f9e4f8091589476323039c7e08f3c2cedbbfb69d64910a7b50ed2654e56a8e119838656a8049ff33dd81e7ed46766e1dfaa7a0480565f0e2ce6575ee811f4f854c8341ab1a72742970a3cbabef8d4e8eadc579eb9ebdffa35ac2860c8168540c0ff06427d3b4f065134b972d97f6ce49fed68b0e99e61d17c0f89952a40d375dbf2f971dbc67d7e64a6ff0ce7ecf4d921d68c67dfd55faf634ed322449a9ee445327be4df5762f17104de608abec72396f450bf60465b04644035ada94d19cdca98a4dbe51c75485b665a8b0fa6174d7ac9b385bbb964255d74f7b61ced4db2a1d7bb37562a2acf0e25070449"""), - TestUtils.hexDecode(""" -CA0104B9DF99E87474389167359968A307F63AA32F0C804A96B18FFBE00C748B1D6894CBE2B7BA06EF17B6947ECE31DDC9F614348F01995FCCE77099A0D88B2BCD1035667631991C2BCAA4C86B4D31074A2FD46C38429B52CF0BFD7CD3E5D194DF22E2B0D57C0C9D624C772B54686AC963447E716C6B4DAFC00AE383CFFC69A2F6F931D616954BC9A140D785F15C5DB28ECC793D88C78D11F8F8452046ADDD3AD26988B21BF895DC810739FA7C45A8062B2931AD363B0C7EAB4CCFAC71CDD0DA3B54CA9A6388DCBF79AF799446395DC7A5B7ED1788188E9D03EB3BF7B80F8CFB9B7F33DA0D4DBE1840B9C6C5D80F6AE64487BBFEC86C596E2ED8E721A11D783F7552A4B01FA24F60B5B683E287BD75EA0DDC15314E014D402F527C5DAD74CFC49B4D824EFA77C359B90AFF15AC89C1AA35959570E2148DF7A09E27E2FC096AB5CB306B4868AB80A24DF745DCF9EDDE57357866182A9AF50796EAF97A1A1051FFE6F9038BE1F6239CADBF0BD81B23E2991941F34D0851AFCEBC4D3F8B472D6259CF61FFDB87F79928C66E69D969B254D57541A87C692160E5D58A837A1FE90A1799758A70F958DBC1BE5D6E6836845940C75E745245FBCE59D1F83462B9578534D7A05DC3F21C34EA93ED78387B32DE09ED3CD2A51EE2B8F7387C8C2D426EAF3795E99B158D467D9A039234FDF207D65D2577D1688E1B1E72B5EB096FB6377DC8EB6B3F51900380BEA561C03D546EE242EB4264C0369AA2D53B2B190E0422FBC4CF896CD549C2A08A37070331F15A9ECFFA0E91B1FC4D5157418914308EB8C6A992B197F33DDD517DF4610E88F2E35E505BA7C7CACB8E76677CA9B39A4094EB4590F6154FAAFA76C1D95D4072B5CE01F42355C47AFE569FA80142EDB49E2ADB34D3C356F4D882A52021C5216B3678AA6A5D52C51CC8BF09E7EAEDD2501A9886FAC977EA5F385F46E8718D39073D8995D392074C2525A4ABBE228F531E6B16AD5BCD5EF5CC4C3C71AA77EAC1747E2B763D0B3D66C7F35458BE43369BAA0ABED23202B733B3C7A111F9CF407A7D62EFF5BE3A5DDC3E49AF130012BC6D5D3641EBF268236473EAB09BE87BAF7707546B7AB194D2ECF5B03A56662B1D6462898DA94747CEE9DDA08A9026538D799F163E1E771EF7EADF8833C0510104FE7AD7EE75F44F8D4572E299A87FB17429718C576B29983B50FF81F8D48D41CC764809429A7CFE05F68168B6B36FF66CD75DC0021D774D07BC716A74F9450EAD2995089FEB89D1EA73A9CEB83155ADBA737B3DE33B6B617EE7F5CB6C6672AFC439990B612A6AE71540FC6D7FF535FC88DED0E6A80A484735F63209D39F12E6E129C4ED2EDD8C8B5A24472B83A058B0F1C86B7F4C53D88927C7E9EDB5C40C5D6C7F0ED8A626C5F35E1D3981936F0F1FE4E8CEE0FC7F66F0016B14F3D1EAA993A5DB9B92C03D99C0A867FEB343D9F43BBBBBD85F58B2380811CF153FE66E5B5DD07D5A87ABCADBBD472692358777BF17AAFB622D487A100062465D9BFBE0E63B9D862A02F09E371EE820D969B29B4E6F6A1120CDA9F9E3FB804B26E2E9C3DE219044D1D6E62A28CBC90C262B76914B8929465FD901777F6F5C112D196A002A0F4C4FFAFD2578B5CAEA21452968400DAD6490E313D32A708A42F64E9CF412EC0E358F6B833EB0190C5933037202C266ABAD212B570E609FB7D338AD3F850EFDEE9347EBCFEBBBCE90E7F27372E244C3F035D4ABF1008055215E573F0C4001FFCDA5E6B6C5B29B7F59132CD86481FD0E1245EE4084DCA3D44A0C9E6B6B14E1BCBF56F470F15609DE76588795D5CB62BFC9C253EEFCC155C116D70CCF9112D8E0A801A3C640C7D16634EA02DA9DB9AC57DC2F7D43F48ABE631D3438C2BD3EC97832244E81223EEE47054878BB2472F64E9ACA0D5A8B0B04F783C5052E0ED6AFADA5274C94084621E989084EF9814128226346996CEB6FA07FB957C7432878505442FAFC4D945A953336F9C92B8ABE4E4A092DA65E2BF1A7A274E1EE9D7958E35334D9B7CF8B314F0AA5C45E93111460A8F5409C0BCB842DF9C9887FE4643BF8958CDB40EB66438BA53972E359EB712BF4C553D871ED702F74C41D1217D7887C891E49043C0826FCCEB2897BFAF9F217DC9F566DE1C416DE9118491162113E2EB56CDD4C024DCA4A33359D88CB0247BDD6802455063DE9666A4C52075359316B3B557D42B7C99700F55CABCB2B802AE4209C6B937C798433AF94159A4EC0A7DE00C809F6E6675A4213A1CE8A7099FB7FE6A0C7FB383233444B64AA120BABA1C4E61C6426001184E897A3C6B0BDCF9759A72146EF848EFA65EF09076A4FF2E6DA518C5A08F2A2A12D904C893297234E53CFFA04F285F350412456C9A13E153421D65DD30B236653AC13CCE3D5CF1EBCB8AB46808414BD3725987D6E464EB4F97321595153DBF9994F7E19AFBD19E9BE929D18563789567B28B1AF05BDB5D2C5C289FCBE8EB159D0017E09DA8FE5E9D49D3A231814778370DFE703ADABFB175859A895A6ED86F9B6B52CCDBBF936622C5E5A01D50E2B6D5730EA4588680EFCCF390211F211472F9E10314482CFB45A24706BBCA8CB515B6A9AA6EE1D2509E8F9AE9D6F545BD3971A02CC26699608FE1F076A925008AB6CA8576CC5A962326A369BDA8ACED3618F02BBC55337FAB2D66050514F904083D4386B43B6EAD553DF5603201C6D684F7156FBD2D3DDE3D7EB0D569AFD42886E57B747F21D44B88AD58FA2370FE6BF2DFA4D94D8FF983A1C2B89876E75AAE3828D1306DB9A639D052EFA6A0EFA0F61737CCC45E0C516815E92E256BA49E7853F9E9D4670593BF9402E59EE80F6CDFF8244D156FAEA8220D483601794A3CB5E1D7B60DCF991A545D2C72F62E5EA05BEAA77FA86A80400A07B97D8159F0EC170913ED885B578767CCA7A5BFB8BFDB7AC99002555145D9DF5011654700D6FBF2EC2BA609C969EBECFCC0EE346FA01B6CF07E6855F3C832BF1DB6E247448438BAEC055FD41CDBE921E5F62D93F4E7964258A9CB3991E8084BFFC2E5B29BD1E32A64E32BF5E27416CBA7FA3DFC143281F3797E1927AE9D9E07FB424833A7911C23F231D676EB0FB061C179C72FF0038E48068D43A805D56C3B6A16F5A2E5E8457F1A3E0F927A8880CD261F0D0AD8F82EF0E52E1BED003661F1D4510F7BCCE680CE84A0181F046366126A53EE67C7309C6982C28966B6CA1F324D03F5E09AEB111486C44B6551B1C36E84C2A72F78AEF5CA31AA66EDFB0792C00579C0C7C1FAE501735706CCFADE03E9A0847E498A24AC1DCBC7DB8FFC946B8D914633559B63E3031C214414BCC1921D2A53726695340648CF6C2BB4FDF132C77BC39E9CEB2E4D22EB138D807D7B79F78CD9713F5BE7512FD32E73E886DE16A9B1B19026B91EE6AB92DE4DE663D9774344B283149AF4890BFA57ABD1C9DFF128F9F169E4CECEBA0FEE1C33D4E34B877EF04DC887F7109B2BA65EF5732ED4B7C6B33131EB5867811D4A8A3536102F5AEFCACAA681A6A45A3BDCB24C4FDBF49A134244044E2B424996CF6F3C514C77EDF2AEC177B8F80A1AB77F6D3D920E508C76EB71ADFE2209A132839E9BB16BD9991A545AA0587B7594E0422647DC84CD355B20983AD582324D4F19E33E9CFA5CEDC739B26F43BBAD1F165720306F48CB15B23B961E5990C2DCC39E5BF58A9BFC10829590A7AA8F60E13EE1DBA85EF5EB9B1F6DDA891ADF7357E16CEEA4ACDC00E20F8F364AE3EA838CB4A0FDCCF8B439A242F8D18B8E0B9FB8E074922E0C25922CBEC46C98A82E93F0E95884BA9853CC738AFADA3F08BFB66C17DE7977EB7CE5495B8620B537B49D1D37EA4B3477B79759EC7D9AF17EFDB2EF89945D453BCBDB349CFC623FBDB8F125EC492CCBAF30006523B543B6A17245CDC5EE7E28EA895654A5EA74781CCB0F30343C73B4BB88CE07BD37DE9220712F11748EFACCE925626FFDD8447D37BD9CF2476437C093BA4CC0AB674E4CF9543CEA67BC25B9BD56946C0D077F0849796EFB74C7F66D5B86CD9A38B8138D816F677CE08DE6A6A911BA4DD1834751548578CEE4CFAC50C11D685E52DECB77A475FF5468C38DB23853BB2118C78AC3D52079042FB7F370B3D0406E402EFA6432D3055C572C81DD999876E8306021118BA87D5D430E4AB9C24670EAA1274ABF4BFB8149D9067C427DCC026A61C5B724CAE1858ADE366FB42CEE52C36F0F99AC02E8BDF784EBF311334B83B2B277982519DFFA3AC35D97F9F30635CC17BF8E017EC4E209EAD104B52C58E8762052CA62BA7A82FD011860E4F298D889A11F6A2BB1B4157CDA42AF9CCD0B5324329A92CB9FD6EB81DB3FC58431BC5C9A6DC1B07F7D2B00B32E5A39960C5E2CD69CA2914F23365B518ED746B27733D713E8ABEAF9D1FFC6D3D9B601FB386A6911F24CC818C0353658CB826F43FEEA792055720065601F1364BB6184699F16E3EE2B359CF0642C85E9115B18E55482356E2F91121C5884578F3D2C45462E47A3D477B3D63448A8C1679E68F9B7AE509100B7B2B142FB6BA20179E599259414520B02B745E592FD10D0D40D780A95C164D651E96A7052B69BBDA979216989A57506638F891336E2EA123303F997194B7AAB4F22CB192AB59A8BDA7CC88D0F43E4DD949146006CA3F91CF28535ED42662A61F630AD6E7319A7B98FF5C7200FECA768F14BFD43BD60DBEC814E22C26F1A8191ACC869A6BCE61991E4F36148908A5B1557A507C407D73A6FE75A548CBB8CACF13E57BA6B01FF0DF900051AE7C0C346D5DADE5F1C1BBFF967236BA5BAEF19A70FEB320BD76035F3A6B11383F13E6DCB8D1533A6529C98334A3F2A9105A5CF1C940659459C405C197130EBA44F0A2881B4614B7A0BBDAD5930DE5C3389A7349265629E29C0123CC89F3F540FE5C9019662A4383A38248F22201967D908EB48D530D17D50A08B35FCAB73AE8ADFDD72A8A7551EC28C7573E2B33EA4F61EE84C3DCA33DD5861B8FB7176C4AFBC174250D51F86B1452903191E39EF099C0CBCC15B3FB5DD30A2822F68AA37D59583BDC1CCDAB1B2E0337BF397647FEA9111A5B94C6A3369E90F3B86C266F4C11C9A7D9E24802B31B5F93B8EA9AEDC6C2944965D6B54601311D251E81C77AC1BB2159263D0A92F377F111DBC8D554C3AF747FE7E82A6E6BF0E4E3743B7AA42C3B5B8D3E5D9C3B427B3290452136E61592609826F4B61D4960B7C3784D0E2508363212AEEAE624489B739D0573CE23B35D30826182DB5F4D09772582E4D6B61938041344EA434614C21B01530327C08539A84F03275D0C4A77FDF230FBE6639CC7A12C34545C5CAD34AABF8E25D64AFCA8206948737DBA643867A146F17ABF81A926294E2368A5A2F0C381E2C244B21843E3ABBA680CC3F1F0509DFAFF4C70B68C82D3D7EF8EE053DBD154376FAAB5D561A19362314B037CFE18DD03BB817444FBF08D771A13B9D745DC066C89C10ACD53597B74916BA719F9EEEBA865252FE13EDDF97978092FDD1524CDD865FD6AE9C14329EB62B322F46905804AF1CFFC13B46B6AF4ABCB107D44DD27B460101F7A38DC786239E34CA9D1A444898673BB3DD92EE88478A3C539A563CEAF5CF499AE8E07BDAC0CD5419DEFE2977105B5E0138D84A8F9BFAD82F58884377B803C8B68164A3E678648C18127A832FA994EBEDCDE4FECE85DAFF8CD6F44F4CE57694522DC30BFC492BF62796D05A9B87BF13A7D538EE5C55E6898D50ED127E8C12F87D160AEEBD3CB126BC4144A51F685079E962DB6FDDE3BA6D0C8038BD6FD8377C4BEFC2EBF1A876833516D206C2E309C61E4CEAB5F86ED83FF20C8723BFE63D8E480798292E6EC6D418D3CEB623AC6983A3F8A3AD568F73E408F15AB88C8F56F3CCF5B32C76BDCEB1FA41357C42E1215CC503A316EA0A83FB341ED6ED20B1154E5001A754F92E97570F9DA7EA8AB7F2EFEE7B79A1DDA705645ABC5B1E04CE4F922BB03435D11FC83EB580CDFF7EDEB78F2CEBBB6053410E84477864C16D4CD7CD9D16B932372FDB99DBCCE2DC3B5CDCCF7DB86AEC9BDCB8E4F27B65ACA9A3FB985CF95C5BAE253797C8474D0C25F0FFBD151E6558E524C6E96267677EB7A3E128C918CD3B09F1DDE311401152C62B4C59EA1D408ACCC4A12A34664D7C0858D7E99A0327724AE9CA55A9322D865EFB4FBFD37FC79F8D7B2BF08B1824D44777153ED6604E05DB1FC9B1ACCE05F8C53C32594A84F32D97AE49E819029204AB7713AF2AF2C281448A34C69D5F3DC76345031D2CC05B6B26303198E182901FE65710EA95793DC8495F1995F0196DC9473B7AB922786BBC61A91868BB0BE05E2034EFFB288502DDFE2595887CCD144E98ECA4D1E0C044C642396F98473BFDEEE796530467F6B5EC0D5B79674EBDF5D1416F94A8EAC7F4833947F1DE610029779CD436729E55AE3D959F99D5438E0E4407D0A870A38AB31E08F16A06345B7BA730CCF55CF1FDA1E9D04833ADE5FD74A34E2629DCB75A3482312860404F7E75D94D7FD2C8215C6A21BD5FCAE81CF4467931A984AA24B927039526B95C2F5F39AB2040A23C76B64CD2D04E95DE6DD9B8EA849F9F7919A619EFAC498E7E3F4A70432E28B1C5DEDB08D122AE503E98D34D13A4E8A69FA267C3E20671077F977F71308D3EA1AAED5DC33B3F41E0ED981050B3B915EDA07AFD71CFD3AF13A2063813039BE85EF98706399299118D2427A7912A131DB7BA731D18DC2838A116E05C4CBC660895294A73D170C060CD83C9AA0884C5F3FE52F4891C2101997D688709F356A556CE202C571E1170BC339F3E2A75A5A13810E3A2F2133438C1705895523D03F00BBE4F4FA9BCE6D7A14517BD54E281F202BAB40DF35253961DC9E94DF5C2C5C3F0E420AC67A85BEC2ED70545B94202AACE5E58180104E42C5AA6F7F59915BEA69AC10F678D40506AD2B502D77EBE4D05CF8253B4795094F04BBDFCC8033EA131BE83F3F647D22D1212C16895F52FEA576EFB344A476D2A8EC74739BA62632C4B5B08076905BC0103CC9B2193EF6C4785685F2B3F79FC39B5ED09B258E5E9BD346557F24CB542B69A3ABE367123179879A02F941F9781935D44BCABCC563BB1F31C44BB77D5E7A4FC7EC2C11D597E7288C6088497DCC97910CFD8245A4F255CFBCB8FFF95905E8224B770E910A253356916EAF1B3277D831BEA5BD6681C6C7D57D363608EE78973B7BBBC156FE5536C963030B6BC8D306F3C1EE72F14163DE0DCD0CE741EF975A9DDA77EE386B991F3096FEC95FD394E26578269F491572B36AF42CEF1D86CDC82D63DF00AA397E1960378763F5CED239BD2A6D0EB7C5BD7CDA2228B684FA57B7FAF497310D510CD386DE6406924CD592ABB1E9753EC8BCC594ED52B70C04F7C53E19B0CB607DEBA79FABD6748A52692CDA34BB7CBF95D1ABBFF8AEF8F8AC7E5D52EF58FC79B0C7662DA90A0F737CBD42E64B648B624AB497162A7B27E41850A9BB4AF0489550773EBF1EC6742CE8D53A20921149563AA74337ED4CF1EE8685F41D36F748B6DED5F894BBC50A8DEC84621B6AAE690D6EE0B392A7266A480CF985295361B14AF0A5CEFC1EB737ED3AEA5E5894FDE80CAE477FE742395CACD1174CF2B345774BDDF71853BA1854EDC8F5CB03D33C5F58EC386ECBAC8E4209F8881473A4FFE306ED3194F455D4441D132B7685425435E58AF1F2964B657C71EB6E28FE3568183F7A0E570821EA49DECFBA3128002E77208749DCBD3F5E15453AB6DE9EB313D7445377B3BA74BD2F67AE31F560ABB628CA0DDB120CAC6CB62EC9CCC65051F70FC41BDCDF29F885FC9A558929F58CDE1200072F96C3D8F22032A0AB3F705884F0D827823FBDB62FFAA39EEBFECD9F57DA083D1ED541CF36465A999558F2299A865456C94D67E74F1EDC7166F91F4CBAC8F89E680BDED946A174E9260DD50C6B0A980A4B886850797149FCAF8871AB3080A76B645E333290A0DF319DE058981B8CFAD7A54FCD62345DFD9C3E6F7A26D212C97FA6F09866E23D5A19EB9CAE760E876B2AAF43BDF9004D5CFDC41570EABACACD4B57662087B6A91B6249CDAF905BC2B1AF5934F1A05D20E6C6784F0FFDA0A3E79A2C0939BF36C55EA0E31B1AE614D44CD413118EA165FA549026574D1549FF7D63B4C464A896C5C0E8D5569AB2B10D1DC56458FD1E069B5F91B1D084F7AE34F67ECDCBF33299B12C102F953CC48B0661AB4EFB493F7E4B2EA8F6FE59C3D5EF7D121B26B912B86BC0AE987B6A3543558F0B935AE62B4711A586DDAC9E5960C48B99CB80191B11F4053527905123D20C549457BA87608948933442CB06BEA0E73FE99E3C4198E9E7C51BBB7074DA46E752E46B3E419FAE2AD60D180303D710C0A59C6B980B24F0BFD39959368B5F56AB3845A2167F4683AA82A9613257BC801F5146CFCA857F2DF4FBEA85C54930D4373F70C083F661077567F1173819EBAA585EA3675F97951CF8C9997887BBEA9B99E17A1E0215DFC2B9A66760A277F68E747141AFE5CAB6B25D73D562B91BADDCC7938F2EA75F1C990E88311549F38FCE2C52933498B22E2810227D1EAFED4BEABCB153324622E107A6D96214F3C6D5DB91855005056A8D1BC5D5518867C373709D24DC1FCE21537C58999E26CDF4FE61ABE5E1225DE80F98D02253999F39A145FF3008F12880C173A7ADEE15025E3E186FF0C2090872A0A51505A09094FA2946AFA1840B0D6D526DEEEA95FD8E259E70B2E794C97F50E7833B165E7BEEAF5D3CAB7C3AA1CEF00003B94159F0F6DCBC74808E3FF237D5C3E94353FC0E700CAF48DA8BD94B991EFFF2DACC9E423A2AD63824CF879EF838C784C7D4C0CEE3DACF5884941BCC14E043082D382AFF598BBE0321DFE9406434DDF558EE2BDC272C2B04CBF8CEF92EF8180D0FEBD3D62E1F73F3B1E7FB0EDF9B50538D49C52CEE53F3000E581FCD7E6FEA1CEEC9DCB4876B3F1D1B1A301A2D395DEAC54D68181406D7ECA05A416D3D8E0EE10228483D8515A0F662D933C53F945B50C65C5B8D51EC45360661C92761A1F74EE06FAF8889244620DABA05593DDD4D6A82A30F34DCEF50B1B1D261CC357AB0673370A38DFEDEF3D591377CA29DF609682EFFA212092ABF84FCAD677DFAD758575CA35046467C6925B6185F9B734D5E194F5CA48DD10D0B84B7E9096703A9EEF0D3EFEFFC0F58C4D38D741F15AE766D06156B26E9C82B464C9F609F0A4FF699D52E0E11E054738476456CB81859ABE457F3595E9D7F1CFEE5D0437094CF093F468C79C093CD615F7409A505C610169010F46E148F3D264FEEA1DF42B3E78D1C4B33C92EE9BBD9C508E89BC4CE0BA0C412F75821EB54730FBB627C6C93694810CD741167D5288768165A68034CE2B16B0E73ABFBF75A905C9A9E577024EF2070EBE8A68076AE37BDF3507C7CB10EAE13D3A05BB3DA33F873F488150CE67AB892D61A11FAF5850B6A26862FF0CE85E4B0AB3EEBDC81F68BFDE39B0582185E4322404A0195BF5951BF7CDDAA6530DB0EFA0A2E6B2A9CF8DCD8B0D15447448847D1EB5FCCDC80EEDF166988D55DCF3BCE37E24A0A5F302F820C2782849E70BA47523A7AA1FF12F144148E9B5A1E05035A346FC4028BDA824B8D5FDECEC4036EB2C3A7DA612A703EFBE4D5E5E17CBCE1EBF546880C227EEE2D9CA4113D0ED61AFA70171700F0F9A1BC7CE7807A081EF09E9CEDA5DFFDDECADAA7CB5ACB2DBBE26550ED006C5B7DD89A2585EBED5995F8F76F3EF8F13B6AE77084727DC894C74268D4D91000155FDC94DEE049E54F4E4D2494EF926F23B73E60EE16CC3711B67B6F6B3A3BA6BA8CE602AE1BA87ACAD58650AA8F7F0F36AEA21080CA8DFC618AAF865B14BBD69FF7B413FFC81DC6C8BF2A7B122EC2C13DD7832610DB9E6EA0E5CACBE1703AF551997E6C51BCE7BAD4B3EB1F392EE12C5691F795090C6F1D6405D0E682F279B3DE64A9F45B1853346D8D337FF8037370CB4DBE5B241959FB8DD985A4F154470833E422AD9EAD7A14EC1CAF6308FCF7E9AAC13ACAFAAD98011148A2D52D40511CF13C7CF0ED1E320617B908BD1A6A442FAFB2E543703844B0D40FCBD1B392CDF5DAC9CE4C2CA69C8F04AA033F5D6D11DC1A5667FB352BE6BF88A9978AAD37B01BF8652A2C475E8516AE1A6E56F8CD596B9A780864ADC65A04F615ABB2BD4BA97301FB0CB7D9AB5423BB14C29030DCD5345C54D556ABB116051C04D79C81402B70AA9F32CD01B6C06FCFB416C4CB7709CEB12DF3E8BC541333C90E6D991B24D7D1D98D0839AA86614F3D91ABBEE5DF138A9DF2C0591204FEB3D9DD546305FD017B72FCA4DF01A7C1728606EDBA07EC101D7172971C9F4ACE7D6D09E06BF9E8552A4CB3ABF6FD84FD350F60A3E1826BBCBA484D4B5B284E2E1EF2A164FEDCD0D22AE77026C4A6596ABCCEBF6ACE68C11ED108BD3C"""), - TestUtils.hexDecode(""" -a3426182a616883300b2c714932258a288d6f9d23c8339e1639f0cb6affa7245fcd901acc5612dfafe3e4fff1171e24db746e388f629bf6ab0e2090deeeef36a3b3c610ef0570193067af930c98accbc0d6830173136316ac7d5459e4a2cdda6f26f6509c35d1232af44470fddd0142b6d584766de939dbfa3edc9c905189e0c861eb16667d53576a9d4a7df0073a5d54058500e1f54d3898faaafc08b116336669568d1d18004d33c2b71acb0686472ad04b23a667d6d3d7d0d9e3a434e34d505d63f17b26933b4427931701aa35f2f6864465b650c9a6673397ff4aeb6af2730206f1049febad306ae06f30c856ef643c8c8ae9e3cb249a10a4646f9b7d985bde15103d57630cdbbb6716f41d0b7b1064346ec31907531bd35fff03872661bba13bba7d9a03031ee4943fb2aa549a208709a528555da3a42020a5c5827b06e7c917eb07c02732f7f559c122c545fc36cd006f33bddc2ec1a2dd67a60355c971e699d400110aa001a442fae92e24d05d1d091eef447f643aaa825d974f4b049e6e0f988ece4d510e79db57ccadf9b5e1a564c64b029cd265845d41474868afd6554996e7dbb2b3e92fa5f544de6f8840e841e886f7a5b77d1afe3b29f74dbab86a3f68cf223f9cbf41715e6f1f14b91146b64475a336fdeb668b27ea28fb87321f340c910b1814ec7305e11a0dfd0eac1283c0d0131092267de75cef5b2586399804afe72f7da133d04c02f19c2289c17bf4a2ab1d01bc2830b34bc77b15edc8fddbd0359587fb9316c3ea1ac8a146fd5229f86c38920907d77eff0b1c581f6925a1bccac2d234c52d159ae44f6d93a11d133edd6d0f6683f5165abf5c7197a50827fdaf713eb3bcd562ee9055be72e879849b7e4105755d0b9052885195e100ce302d3372fa4e41e3ab9e48f61a2ca054fea7132ee7ef77b62d61e02bd8acf7bae2b56cbe5f0224d15c3ef29fa051d2f27d56b0057b846fefa044ec57171549c81d7baa27e59e134c28cf6326d49fcbef62af5937d42953bf5662b60729ffcdb8471733c44cbf34765996a58430c02dacb23c6dbd9d8550eea2dfb669e1738fde0c9fb34f0051fb99cee29bf5ffc1ee95419580dc56c9b2118ea80a7b34c1a2231074195f45dd778dcb1426aa7feadf475e065f9ecc00333d05ec3ca0e0cebb2940fd7ee81e8a18821b59341582acc43ae576cf850f8e7cb040d4c4dab557b2a80fb3891669f86a00879c45c73e6a363ebbad67f99df0c5fadecd53494b5872f902e20f3d41e4be6b7ceccd89783ae2464feaa9fec596440fefa3111bf3efe416481f5e739fff33e3b7ee1c90064acfe18528b8ad3a9f3dfea879308521416da9f6131a3279def7f9ecf8a46373352cd14a0765f4e28ea8f313a988dd751d0a15b525c3f2b19ef0d098298014230bd7c8a042afc6d6eb6886e22449a36ade8b5c8e114cd408dc54ca4554f291882272645f8c1c10eee4ee4d6206525d0656867c0d2b4a134a40ea26019897e6f2bed4b325ada4af846b1db43358d140d54bf61bc8ad585715345aa2fdfc6ff62453bad6d00ba9ea11b053e776d72e0bc28f54056c7e0feb06314b3dd0023b257eed796bfd594d2a2b0ef19ed5eedf68a6dd19558fab24c9a751021c5fd964872e4a8eacbbe9406dbdb98fd505870ce79e64ed57c83887edf6ea916b29ad0c1c34d02f115e9a81b76d70ed6bc0900ada79fb5f7dc069fd7fc2f87ef9ada6be01f3e5c2e87ce02b38bb4c5372fe69fd7cca02898618d952c6706c88bb7a8b05a3ac163baf9deb64a0c5523ea486825f00cc298da63274b4d085b7fc6324b984d86d9e39d2cfce97c2e2a3ad8c3c04399e23af07f4e4c8a49e58971f8c379c88258e7ba25f6c6e9bf8c090eaf06424ace3e91e3ae12bd552193057f2542c6bb89bf1d16b7039395a8f8f54bce4a67caf3baee88af88a4a34ffd0d3673710dad8b1a98aa7a7678675f87da138971b0446e868fe1a39ef268252fb06366eb194d1f69c7a86b7e805761ee0de00c7113a2e1c5f405cea7207ec634cae3a43308d6d3caff7a9baa0670c9256fb90c61a116abb81910fdd638075283bc76928a82074255a4375872f02cc9ff13b75240609fc44125d46e8071a94cfe1e8fc68ec03665daccfd0dc385687c79e5537661bfdca8462d3fd86ce26d599f5add12e57c49c0ab1347c2fd967cd62b6e88613051904a975051309d5a43f9782ee31fdba8ca641f8d5a27c8cac9131e33e24bf5a1425dd771aadde8bf0fb7a0b7b896dceba013aa5c0687e327c27106ffe79e545f2249eaddac393a6e062dc296aaf4496c4936dd0365d3d248dd2811a95b2789797fa05e33cae686819789fd2b1315aa90395b0afb2f6084836ab2c78216b27ba6a65f09b23006957522679a4e372369aa65a3bbbb8c8af19039ff0cbd191ba65c0d7e0acddfb468a253f631c4495a808083e945496432a10195fc221535e240fead5672421cc1ab3010ffd3faa39f818ae105dba8d6a6fb621f0b86ba9abb68dbbeffc24b26e55184d4f21d8ad733ef0fecd4c6cfd5a403e551c91000cb9b6a26c3f6a246eace5717c784921cf154bc7fa61da54cd0eb55846c086a6a134716dcc49f44b55994217d5e92523a07a28733a95efdb2c6ecebc6d3ef790ab10ccd113d4fe96144d0e4caac971370d78331fe91648d32c2373c595ae848ef70a5a786c36c61d5961195b8a2c287608b9596224ee165c22336c07643b08d3c92aa5808bdef9c3c35bb3a5004f386dbff06c9dddc925fceb7f10ada52c9b5e100ce0e45fc23869f18ac4b3ca6561f98c148a86ae197d17066da6421f4d73ff4c16b489e84c4b09afe4c1e8f728f9dc4e4563c36ea110870a341632a390981fc1d114052eacffcc06d550c329bf38d7460c51a3ee0342d87157450989c43788b508e9537d08ba1017bcc0dc4c5a8d99ae5591d82fa8b258cec35a1446054aa449b48371db2f04f25cd618636309b5a40b7a32e589c80b69ef5cf19bfad44da6687abcefdd35603f32028fe079c1e541854e5b0b56998b4bb02ad89b3ef22229c9a8da7a381fda304ecbd458c625c779d7e52c8c44fcc45322a21e7a78d896417b513e298700389d0de1a50c7a3b653c87006bff64fd297a54fca09a4662d9710132d16e2e38ff4eb2a4eee0bf9b9d59da5d828da4cafe77262af02a279fc22a1a83aea33f9887880542e274c950d707e766eafe8610b0cb8aede80cf900f6a36432019e4d1f561f33ba1d273573cf1908a9dfe9922804f9e5ac279270b21d3b5edddd51c1fb2e8aa8789d0cd75c672eda3b06686ff6e8c7f5cc3fd67d2fe91aeda8a22e73aa9624b7b18d0060a64d6ce2ec77657b1d1a878672d5bc033aebbe3b9a7a224b74d859d47d89a360e2f7a1b03a4bb1ae92c063ed85d5d60391d9553e4d3776c5d4628146aac13c22eadd0ac57c46e65c525775ed3edbf0b41a01f83a2758aafb5324c1888a284ef0d47c12b15c6c5d68affe6c330110e0e8bdfc2b1a8f2fd67617e76f975a7d72630cc24e98eb45b5e9c8c442a5af3ebe4b3d3809db4abd88e49004d339a36265898c5a65bf5263d062cc9a307563081ec6b0c46bb45b92eade67a15449e0ba26e280fcd403cab8c29ffa15d306285b4052611ab63ea0549e8aeeb037e29cf23dbf5baaec582754768b2e357187343b3186bd6e1128ff92bd7c707f8b5f7dd9eb88915229eb0c8437d715f1b59d1e478b696da3ae27fb756db092c885b6636f6c11abd70ba3f0bcaa6340aff1acbf2182186981e74490f679c6b619522a85441902f9983231c2319a1420a2c3e050fd62433631a7d9b6947b247571303e22121d25c30c130e90b73fcc0367d4b7747688ec709079d9b28b981576e0fcf89593be1bc2868d12cd9b2159244286f46d3c270ed38bffe97bfd1d51e0254313703439c148f495dc73c6e534d05d0041c3a4f02ddec5fe88842b4ee59284a1cb2dbc3ee0c4c5ff17a5fd6b9ece5b23f8f9548cf537c4dfb6d231c0e8ae2fa7352d2c6df9d78865418415fce33cb613593071d83bbc30ac710d2c313648543a762977d43979b5f48c2608a68769b2abc933046762736a42a9b319c78e98be5500fe55b9dfe9976654e95999eaa2dfcc090500c8155369f49f3b9d296db180268de2bc26e3fbb428803d9075a20582e075330aa8d84fbe36417f9a3ffc3204583ff4d2731c27ae4620cf065acce9df4e8c728dade6eddfd09acb726d27a7abf9409a49739f84044d6403f5b9d1855da0daab9d54e2ac26e4dc9c71e63da692f60a755902e9930c21ed5c3ba5d1afeeb892794c5c948a236a2e01066892cef70267bda3415ff51a404207f2f681bb72fc0a14e2720277558dc201958eab0acf7157cc78ef8a9c12266932d2548a559c401cb4c63b36600638a61cce16da6005fe9d59f6a7ef14fb2a4b860fd7b79f0a27b8a7d631075f6ffdb9fbfd8d2764b069f0e10b78605b25fdfd14bfa6825db8c46cb6aa0c976fde81a5929c92240e0b5dd8d664013e561cfdfc59bc7f09bd499aeb45b8623698ad7242808e50f568d830cbbe864aa4bd403dad6a4eb67c33d7db2180d7ef9df51b91bb946bfcfbe0d216673ec34bf2dd72b2656344311191b8b24b263aa6852d1fafbe14b45e803c2b6d0b6293d4f58de21f6ea849f3e8fda46111416eaf6b8284de908f28e7f07eda6d42e4f6196af945fc41301545a848d76201cb84b3be2be65d14425d7cf0822177be934488a439bcd1120f3131d5c78c213df7bca4f92d39bc4274bf0b984fe7d6a35af08362f07250d98e8941d7859fb19a2fda77481d13563eb44b0ab019801d3535ce9ee1b8c24170196a8d42549345bc4d8af3d7a12f66b3dbab325ba4451c345588878c697f16fdc7c75a0077c31b2542407d339a90db740a9f2f3f696ed9d8729c61d296e0eab52a95eb5d3d6f1a9207cecb9b85661128ce3fd6f53b205783c95b11f3d599639d66967729fabf5e0dc1d4e24d7126c73ff941d6d996592cf26a6f124b5a08272b88d6f9f3869b10a7adfba87cc683f2a99e695bc29220b611203e82f67d80ca3275a79004479802182431d2d7d8dc4859820d17c483cd94b0ea11c286fddf5766a048456390ec48b2d5a94d2a59a236ed193f14a9d65f30e82d3df3571bcf7883da9bfb2d95dc6549cd0b9dde70ac082efdef59beb75299ad178cfe7f00679b9fac03adfd44677b8991f9b2da8e3a74b47b4f41f9a063886073a19a43408362497250e8428cd18ed437643766577306975a566ea499ccd3b78ab89382cd5b0bd9b84edead83285a6954264ab6e602e018e69754776070566408719e16ed075d9129fee670113899015690b3696d55b95b15ce290b2a9e8aaef3b869c215de4e1775a480a05be21e2a699717c7c568a755f4411bc2f05800841284939d08bb3bf552c2630f541cbaf3f5e12a12f907863afc72172bc56166c0ebed4e904c05a767dbf47683af7f8b98a16c859180cda8ee3d92b143aad733bdcafc7fd88fce16c39667e9ad26b73a496de9f5065eee7fdf2e7babf2ec58ce83d3762fdfcf44f76aa8c48a32d546761c1011e785fa09bdd5b9b08acf3e5f407b1c733270d495005d5f8709fbc3b3eeaf3b4845e437ba8d2ad2c20faa5c7f4de572ec1357e9c8ee7fa2987529a72572b59bca31467a6b77720acc272529b0e00ef04331e143946287d0ac080d80240d2b31297687f56a7a199b8f49a727d40cd14b61643b6548aafb0d760f3867829bde610960df12851e32c8ad61a507ce824fffa4656e92ab12dec825104c5a19379e11a2eca89165569d0de12b25a9083a355172c34e4a0e26b32aea3ded77f04bd2a6df6f951e295a6544871a06c4554a645b2e29216b3131832b4291230a0f85af29c1a5bf84e38c0753d8bb381bc5414b458c9c5568837885431d5db43edb64d81ef9bce7c20d89a5e574f376600d3e9b356fb1a819b73f6bc16491f7f0af200b787359e5de299f35567888796ae99b3a6c82e2b579c8338da8ecd499cba4a1ea92dc8090487145ad6965e702f3d9ba5a09f32e18a507a2ba1b40342ea2e3c4e02c908c99a2ac2c4a25d08387d8c444f78a4cd6237c047bc605afedea209df85ed0924489209a3da321dbe671041d827e022dd97ced029b73f6c8bb503bdffeb6d326c6a4cf5bd3716fb01a0d3cc43ee43dbe5692049591171209b47b86154d91cabcb955646479ce9d11ea660c39d7b4bcf1ad8b459b4f1589bcc7e1683bb4966cfdecb626ae1379fb66539a3cd5b28e24a0ebd290d2f214307f3d39c64d15e45d5aa17d339fc6a09a14db59e1dc2f07d16c97b117712c468b1beae5037ec65ccd569262fc9b8e250f6951bfaa7ec3b0511eee88d13001c4fa091efe03e41be5eb09e2a54d56b166ae26b4cea5869937801359193aabe0d17313460697e82b2cce51936393b6ce83167c5eef9131b2f7d85893a464a6bbfe7072fbac1f74c5f6579ebecf3fc000000000000000000000000000000000000000000000611171c22282d35""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -b5ddc2872c67aee1328b8becc910a85ebc35da9cb9ac8d19f282096d0022bc51dfd6718ccc09f953319df7a435f6492f9ab11438f6007646030cfe2d41849d540e6ffa22065d712eb7b36a2974a7e566e8672554c1d5ea9fe6a1f122a6ffa98102dd59d43193333d38fc6a1be550672ff1bcc4bcab186df01a9584c52047693c35e998827c0d855f0274584cb09776311470523e6d35eef3771e1b8d553e19f62c31cf3022113314f25f322d6791a670766f95d3e21c2faa57e714b2d8dc03e28d77bf8d6a102cf218c8a4aa4fded4cf88ba4c9558c66488127b8e52cdaa10487fcf90515a5216d0ba6a6e89756c664d31cd38d281ced994a1b1c72369b82c2a49b606e3cec00fb2746ab6f2b53f7b4ae4ed2838e9d7d08f9bd1709d7cabdf1f3f4113f06a0c8f0c8c8ecd0b516b3d47d9133c3ae054262c7190f23c802fb760c02a3dd60b182be708cb158caa516165a0919fb0738f72bbee1a4a270967461f3c707e5e03c76f8139a6976a5602570f3fe8bb15843301a51625a664bb45af4e80f6beb7be5b30a93f1658443aef86ca794a384a8e391a1f90ba6abba29702cade0c31aa199f4d5e01d4f8f26605f4d1dc03b33e269f27aebe4eca4fb85bc99043ef37a2be5fe91a9c273e1e06e1b38d6ed67ab34ca81975f9e1eba3ae888cb339152b9bece9e90d57154f728d0511aa8d3b210142d11de874a12160d7d61d73c176f35f547fdfda27bd5d5ef1d6fba1aa881e7766847b920c49bc389732fbf636fe3d13440207699b0ad309f7ee917b84b281e9661f920cb8289da2a8b9bd17fa75db956461e16cc494c3a3c46e4f7e2df3b5b21bac9ff26930be68c92315ab527dc603ddca5d4a12f4517a20785e791332bf898e50fe3292c4f1b9b9db4b41c5daab37cc8c75f90d5a586d97d0ba0ea01d9e177cacdb3e5f0e6e9287d3f2fb28fc0e4561139cd41266fe6c861785eeeba1ddcbb6c7bc03a4f268e9834d64c555ed30872e8f0b5643efe0f62afbe2ad9efbc4843c5733838ae72006437c254f968022745a49447365f39d1c189b7a7bec75cf345cc62dda809e64209f2302a3942035d0abce86f627fa07065d064428c02d9a48dac5466175ce9b83bdfcdefc9364da1ad356ff962eae2c22d580e915c8a003a62a20fe204a7fb03fef5c0fa56bff205f4e3cc1cc54d0b27df5450b93261ab21f1e056b9bd913f10d5c57bdedc888a0cd8c3f61febd456ca9d6d9dcebebedd2b732c80d6d5a2a2db403e8176826d47d4e1ed7267092879e5a4880ac9a10dc249adb18dc763ded9275a2dc580da01fdd0d4c60a2a2b918f163d91f423e4740f8d92a1422494842b36189dec000118b468456f43f0c48930065472f71810040d4ce3ccb51c800e62e164367a05f80c3283a562c06e4a8f7017b81ef0b0df71081a672454ffadc60dad337f4170a056935aeee88b0f81f356302e8a577d9cff5ca1e812f9ea7fd01b97d4211686206868403ccea209dfd24b89bc2d437f9ea81e1667b09a2e0893fc9c65f99d7a99ac266ab92983b3c443675f680772d7693864e75071ae430ebf59b56d6c73033e6b00476c0f0a596351fa2bad14517671f6a73206d0896712b824590fe2ff7ebc591fa6d556252c59083622067a1390427719e6301b743199cf14471a551e8962415b4c64c2847f76013409f6504238edcdb4616bb5ae54150b339499b30bcfaa09db9a30b612282cfea47c666735d3ff2994eac8dedaea997c337157e34afe74c563ae5997415ca2d1e59a32a29be23f51b0e5d763a5b0151f0abd44144073602451380ee27524dc89016dcbd5685dc34b18a41da3c483c6610abee38055d6668e9a4d5548047a10128877e57a9e55e3868393814e8e44ab79a099b51694b6196daa5e4d7e8442bb59c53c3b13e899727ca79ff9153fbc9e2810404076f07c60537d4ae110f2fbdc6fb8bf2e73211d5ed153589799db063be2df9378a14ba8704770c141af838cca295f33593739a6f94187827032704e716736c3f9b0af684b485822cb77c87c30f2783bf3fa9d4e1ac2201f8793d85e60049ce8f6ad2c4699e5364f3bd3a225b46d713890cf3d1f7e591893c9563dccf566ae6f880cf87d198e6f2ce29cb8683911858b3518bc4406845393f0e7240470119af07f4a5747249af96cb074a395b21f2a4fbaf50a780e688e8acd342ea93aed5fa9256e366506240738adf50369381520521538a5dbc4b73caba8a52c5e8184d9c40c14f5f0fa8bdb7b93b6e95aef7e1c79491c90b6225307c3fe7727f928f85f728a9480410b805496cf605ff284ab5a160b3fcd9c97ee4a8249cc90e1def62ee4621579ca78760b63ffba86d70e32e642cf4d4bfe3e65d221ff3ba11bf8c5fbe3303d94dd464d08dedbbc3b6e9c223dddb17d84f800e4a4002946baa6e327028d7f96c1299f7b3c8d630a0c56df6d4724d1fa14158f48b0b132eb56a73e8861c18ceed8df1b12c11c1009be26415c1ec76752c60bd8e850ec2337437fcce7e54cb9d0725ab60e0991759e61371ee7f3e90214ada3e2804c0b41eb77910a567a775bc9f548d90c51b1c7cbcc13b7de64dd0912c334f5b0beeb47b8e5bbb8a256403a66354382ae881d794e83d3254423816bed41456acad89388babd6b6365878438066cbec43480d713e0a11aa85cfc9b4937dc962b67d9d286453974cc85bf6b85da2dede72d2e42ef6f02e3bce340a0109fd70892661cbbae2a5aee9a17222e713ccd05e4b1671ee0c7baea4930837083fc33038843b95570a190e60fe1894573dc3e277bf005aebb27212fb4c4f30fa3148840d1600a9ea9b2a2356f1d528f76b0ce13c4c0e700f6192518c324ab0ae21add8f3ab29465e4eba6dc40d8c8d0c03c4f9835d4a941b82ccb86f021338f4297ff378fe6873e582434c6da35d9b854db0a8beb1725e3895f333309ad31bb23a4fdd6e6dc323c2f83865ddea3b60d1d1828c816d305494be5fa15df73b9723d454221e9bb262f2671c412e60e1353f542de2aeb5d379f552b963ea65b630a3b35e4d1dde64583b48e6651b4891000da1339e61f5823390df035f596c25d8f8028b2203b446ca4f35a979f9dded0268222cd3114957d087692517ced7dd73304e1a3861cd85ab9abcfdeab0179f4dc4f58351243ef76215f989d73882eddee5c83751684877353e9c4c55d37efdd4e9f8f8a8e01e8910c5721ad3f2d8cab4102dbd604d8b304090e21afffbbcdf48a87b35499441d8ce0d9680f7f2cb147bf4f28d2b3ab5574a5c51f2415c34fb4fa9a2e97badb824ef46753b012c439ca057768e7318b1bf1c7343955b6a8eb434ec62a236440d83c985f47692a425619e3d6f197c9b24b3720b20dd9bb21858d14e00f577d37b1030e5c39d4b17a01007c32d4fcd982ba4821db371d0bc9a4e13789c8f7481f9a687af04a91a5657a190ec75a12cb973c6123dcbc728d1bcea67afe1d752d05ce6fd53aa510d541907276305066500dfaeae4219876cd42e039e009ecd79acd6cc2a3e4270f1f3b8d9615c0825a13227130e3fbf4b4209ce1aad976a7134ba93455121be23cb7ade9486b9bcb3414645fc1075785bbfcad4389b0eaff8cb54d69a6be42abb56ee6d5a2505fe3658cfbca5d020f824febd71baa578c3fd67e4"""), - TestUtils.hexDecode(""" -D46F4482D570F26C7E9F0F74A354174CA145033097CED3896350DFCE8200CB9448F522B118698DAD51F6C672E1B12A412DB6B7B95CDBDAF6205DEB631E44634412F026CD95440258FE5F0C72C5F3E64FB3FD13E545DD856EC2B7F51AC28C0D5D698C66C700DD3E409BFD96E14A9DAE1677ADEF2CA2CCD178B826AAD3859E569541561073095EFCA329B5B216563D956D8B7BB918224FB479FF7025FD8168F54D14ED1FDF0B399130C6117B5645D0E8DD242C3C7AEC6A8361361CAD9A8FC3B5A40BF7E73F1BBA9AC7F5A583A5B0EB95AD0AB4C1360D0145FC2C3A9AA50186D649B72B41DB7EF392E663497B3166AF9BD0C1AE21650D6CD04DD36532AEA0FD1071D6E9554CBB575B2C1ACEA3DD4E18615FE83AA211F8AD330C78FD32D920ACB40627CA4AC80F840A64C019124079484B053F525A5403383C21B164D0C6BC1B462C0E1C269A1EA0B2438FA64934CEE47149C4EFF566D9C2234E656969C1C89A0B0A4DE124EB920FF534B934172686A18A1A269960C725940D3307B8A913D56B78A6CDCFD559FF97E225B61AFAE7F62B060E7D3E2D4040D8D9233A24827434AB4EB31B0D528CB0085953D9A1A0FFB748588A2DDEBF241F93B41F5C856159EBBBC6571AB12F4EB534ED3C624CD3F5F836A99C7E6E2FFA0369654A5C07C19D44BC9FAD96983660E4D6F95DD9C38D84DE11271D23A6158B685CF050121425AF91C6FFEFD0B2061F54CC4393F99857F3B9775F81B6526444AB705F9CB88A2D276AF2F530B646FC3D93DE7087EBC1FBC7F9A8DB3F3C8FA186F7B636CCEF99FDC4532E54F560519C94B79B1158D85BFBE23D4F36B64F8056BEE7558252DBB3D9A43748E2E6A338162F5E2BC0934E89DC79091180C93D340D3615F82E7780FABF782E5FE2B5D504F3BD1874EB5DB76CB616CC034D9B2B080319FEB8EB97F62FA4498878FF049FA97C56ACACD2414E0BEF018F25A6254448F02E64815E525AA06AEAB53969A66D453B732891E31C36679B5C0A4637611A5983F21F6D4ADA1DA5E890C909A9E968F947C686C17EC73A0F9BAE5C7BF7433133F35F22D2A0B40CC135A7591E2CD216F7D8018969940EB9A5C4BF21579C524C41AFF5DBC0E141FBD02F1BCF376DFFCFBD06F9CD4384E128CF1F03139C853CDD04DEC61EFB8F1DF1A6450E4ABDDDD8A9D85BA79479562A08CDF06BDDD2E740DE7AD9AD1016D72A649A73246E8DAE183AFCD6FBDC64B6B6B2EFDDF525F3B764CAB39BF8D617D47FD3380B4A30081AE6C3165E9437B2F37A73AFC5E596AA626FE5A32D8873712F99910DADD0DE296577D4749F88639D07F83B0F6A05B1668D8008EA749580EE5A629FC2313FAA2F8ADDB5764B242B6B595A39AD76CED4CE5BC34C580069071BED1F98CAF4BDF740A5B1DE3FD30C29DAD808537CB16D0EF22D937F297F50E1681C898375FE0374ADD6EA1B84C10261DBECCCA8E1D224A4709497CE696BCD2BC1369F4135E815A781EA26A055DEA28AFCFDEAF6AB1117085EBF6B8AA6845FD4763FF9274BFE5FC6E377B9F9DA8263DC1F3D53C83F446ABA5EEA4095AFF91F3BE30022B9BBC2C74FC52A3B15CC76F29E541A84C5BF42D499F9B5EA134E24F01E8D866FCD20B7F7A302120B13DE636F48FE8EB99F17ACC153CE4371B266CA61D13E19793CBEF12C0EBA9C728096A3DC6A6750DDB0F52E3807C22EBE4DC6B2407593A1B7BBCED799DC3EAFCE50B483818D903765A63FF572F5D4481357CD6ABD89EC260417306DA1CCF71DA568240D4FD6858BB7833B2C9C98B9E7286FA491F9E318F25D0459071848BBA0D3DB8D2BDDFCB7B8E9C64ED67B4A2B5E1E49B55C6DCBF93394010A078E6F52065AB777C7F6D831DDCC115CF316ACF3680BE8766B4E15574AA383030EDA83CA45B965836FB2374695B50472C4159CB7980FE48B58B40C6CDD2629FE3C6DE6E13ED6728FCE45024C96402B78BAF37E74A1C071F4BCC2A1B84933C872FFCD87C02DBE65438A3E770903A04DF96C569FA69828CCC32D13A0A419FCCE454F06EDE43A97CE5A9A169C6E849F075C66BAB418791778ECB2C158FC19FF5927ADFCA90BFDB3B4216E19BE11157E858610BAA373237B42F811EA97EEB93D735828B2ED092518160A2ED894BB108AD74AB0113A8D5882D99A06CE2313BEE3F902D5CE9CECC835974A47FCF6FD1648C635FE56D1B2404927C49EB53FBD625E0624D5AA04D6C0D5A082C37BD67F477850458B8672C408CEADD9A55CC268B75BC51D7B3D75668D52BB701BD980ED22CC20611EF618277B82624A1192287B46BB5C4468F94C68D96F3CA3ADED476A18BE6CCED70924139F2E16C8A54FD6C9F6695E624499AC8E9AF86A430AB856924A0899E75C1FE4A51DA0DE1588E66044B2465C04809272B2A5C8EDBCAE42B47E439FAE06938810526DDFF4B64C515787B41885BE369A31F90E2D6F6C71528412572A67DF6E155C3705929EB28B80DF15345E0E32540BA9AB7E1D1CF0C015E50C9180372C678CE6C34BDACADF45B0172A1D3082565E16938F57CE6B55D9A711CF72E362A2ABFD45B7B56D48E89A0079E973F597D2E457EFF423E229AD439C3193C264E0BF9A8A1FB50266AE4E0BB671817CAEF10A3BD43452A2FD2DCBB2481D63BB539E0C81F6986400D3A619AA92F250ADDCF661FFEDE7617162B532EE2088A87F58E1FD071F5D720FF1F72335A5B4582F1BEB3BF19DBC9D51A62CDF68A855F7F6DBBE5FEB226C9918E7FFBC8A38079E411EDB44177F843EB8CC1F73B9765A0EAD825B3C43F6760B5F03BB75DC7469701AE555C2B7037952180255612DCC9CD35DDB31F3A9218397E1924791D29C410D2E4C3F5549B7EADF75045EC78D579EA7948D121E8297BC5A3A9F7AA2E2EF5776CAE3B9CB73316170F9B48B657BBE365B352A8129130BF1E718B386AA27E493016ADA86C4B3D3D116B7252A747FD50DC14AA28676F1C25150A86C9F4547189523280A3A897F80FDBBA073EC645C9953B7F8CEC3BD08BC0CA5640545B08F728AA38A860ED38C068F0D"""), - TestUtils.hexDecode(""" -4e4fc796e18a11fe191e08e2e59c8864e0040297897b07d4f62d8a003c50f26e7a6e3d6aac87899b27b308c206efb435b7d48b32a6384e6c733ff5f47bb86ab493d403027cda502831dee50a116708aa01dafa83fefbbbb7aa7411ed417620ce6b035cf27cfa6ad1cbe7e1979f024a436a39fb6a6db40dd21ec16b90a42f61daab8b86efd38ab87121c17fa77bcc761afda7d9196de6d6e4a9b45f32d9cc64ba40aec6c9ec42a4350f841c1e280d60fb1382540f5ea25ad4e7c72333d4a6a4c911a9bf142062a50c2c7f61329ec502e4b4295409392facedf088c321929be05caff934dea89cf0f13b771bbb7832b956aaaa329c666e5582d3e4c51c53bfffe1502559c542f5cd0c6961f1a8a6f4db4e109818519c85f781fc8b81ad4db1a2444016523d79f33b9deadc30030a453bf9c9f48b8bfeac3a563038544141ae621961de26af46860e0d80d4b66bb47607a559dfc34cedbdadf7903ae4271ced072c49c8b91aefac658d1482c913559325be77794481ef2ee6007b643a27a3eddcf29a89237c340867dd3a8bdbbc0a1c8d07586fbc8c3bdba699f08afb44d728376d12aa7547912fd9b8069d5d699773e426f6aad6256853c65a896b5266475b283c17e60dde89a3b79f6b8c262d418b219a9aee8de0718f171d31c24a632e0f9db87dd6ccde3e295241a1f85e439f09a8e17a8cbc8d2e2c5f68147c3cb0138a6b386d42652efcc71315ffcf218630f96734f0c93d0f7ae946a71ba6939401b7d60f9fafab00021628408c3cbdc4c25e2eeb9af29a16871843d124551a4437af15a6042a9b2ccc227190eb7b22eac650a5ff9bdc1bbe867e0ce4222b2ff68d042772f7035ba911f2c4e3f8aa094290584d3902e4e1416f11c313efe437128761e2c9bb160aa58be7f2e3b821c128d69849c6fbd2a4ea4662477491e48c482051ef8f9e1c62fbcb03ea8fc25134e59cdc995575570056cb57fa0460731f3a82af5441759ac4f7c1ab5f2b2f5207e9d1350e1d47cf338c7be3aa05bb9ea4ea2632eac008ec50d7980d681bf91d1bcc583332c949674cf42de62632fcfbed112da44fae1845ee2490801528dc5a9f14f226d18db70a744e5bfe097ae1d17d6e557f670998317d64b45be39b9fae81adddb53aa5c451fa9d525d8205adef6bf5a500adc87a0af2069db0da6dc56a0a8807cbf19172bf8f96992c3c0d2b4e83722463e6f6a702abb058c0f868e9d9080760f2c80a1f85e30018642c3c88b1489145de6d53d27ce3c9f1765dbb459e865d3f8c05afa507d6421f303080c77647486a0611dadaa0a9a58d83d0859dd57b492c941d47f97529d962863821455e52415a231e3704e8d208c15ccd4a1e5cd0c2b434bcf9f82495f0d94f3c91d1cb74cf5da019d0c2a42fd45580db8545366a56febec804a944ade29a2cf87fe5772b3c969495e304c6a7ec148651ee93e2d894342c830849db83f40d9908d11ab2c919704ad55c74aa968501a38069ab310945f0dfe253d1f58fb8dabea9a8160a9fd2b5a0455b6d899a22386c8e814cf50c0aaa35e4b0420c59c339b84332047c9f193de73a9cdaa6463ed2bbc81060a36dec8b10f002161dc56f2085ac03475a6ed6f7ce9695f8a0f4fc044d2494d632598d778afe58221e5d435491ebdc30c2a719f90ce17ec6aad77df11b50232bf1d4eed0195765e3d1c636ae13f0cf95984581fc24a699640ec5ec9374588f8d74baaebb831c219b4df35b73eab7e6e15bd5a17a2803152c0053f3f3aa8096facd15a4ba1d2e0d90300f548180cf9b9ffcacb0cab9d6e4877f7a63d2ffda4d9697149b61f8ccef1daa976f92889c3090c7fc5c69bd87cd39d02d2de8ce16c6eaef9ca623872cf4f91fd426eb23ecc9457ff881da1b25373f1f6959dc4986cb0fbab15f7ed3497896621dd6b45bda78b7ed75c7d38cf7e74443a53ffd456ca84ee9070421b796285e023b5165020d3dec38078e599ac79ab1eda37a09b67d4e20fecf31c0244846fe3ad9b5ff9ed2b2f1400b7647a1a12db22bc24a2a5f1becab6bbd4a911e0faa4f4758219c19d970d07c90efcf8f3de432f526082f73b4a6e6b9b048e00e9887c164a62f3758b8b2a7d0ae30ade451fb5b405fd3a7aa2454a70ac22af75b986e03d8de972814b25ca0ffc3335206d30a7b748a10ea20149477610874348c07fd45ddf69c65d1e1854e3eaa00f6e6e0018c7238c7c311285f1ab9c876c52d212781006a8300bc2ce4c3729121b8b2edff63b99a29a8bc8166351b84ad61b66620fc7d0d5760b6409e42450d5fe58ceeaae5abfe937091d2d2d022057b2bdbca1ff2c6f1413021611e09b3a79455aaf2512c6a3d2a949e45db154ad328ef646db243a3242440159f05ec72ee2f5cd2eead4885f2d6dfe23ddc70ecccedab451645e61b17e88cb39d6bf1f1600b2272e3fa523ee9b570e515d59c8e04ccda564ed5ac3651d206695a0b8eea30a097bda798645d6ce20164a2cae126154fb5d50ca5749ec608db68396d9b6ce620cd8d78b701d6f9dfc701a7900db628fc9c25f06e41a70ba6e9745c4be3c0c9b0913d2c584fb2630582cfa1d74fb598515a104423124ed855a9a900cd6985eca4fe1a921a43188fd87cfa5e9defc046000641f58573a70222f6bc22462fb959df93d1d5c2a2266dd4bb01ba465e4e301c26cb9f49ccd87f92b5d92a30c4e7e4583d95a38ba2fd2fda90c8beb60ea9510a43608b817a51b3c5f05275dea1a857e581cde0a5751a334c9e233353a213bf3f7fc38d6843c839cc06df3c6e76b4b6df73c9aa90bc24196f9668cdc2df584aa10dc8ab41882a532bfe758cfcf16f2e6d0e7ef2fc900a3e5f3e261b4062b1fa3aa49422c7c6baf56d0120710459b949ce7b21089c02a14d5907ffc10c53557477599d59d83f368d5ba349c3f3693da678f2764dc4caa11a669e5b703a97a908ea7abb18175b1f208e448b1b05f1cb3deba9b4f244c5905f4659c51f0152aff9cab8bfffaa61a98150425f14acb154e4db9aa03d73860973750377284c275405d726dd615802c8f4738799fac49515f8c04a9b2fd693d083d3ace8b5e872413767114fcfd32436181f30c25621bd6e808919c0abc67fba98af581aa4383133b47d7d8fb67de035f65d507aafb8e1908c8a3ab305b0b40ebb2f70958cd69ba48c3d0f94807f0159f3c3205affad6b2e48fdd54be8e5a7e5bfdb3f1599f62a52c11819b0a7852a3bc1a424596c4da3b1ea7e6e7989d3c403979263424397ebb5b5a739137c1b3d1566ead912214341ddae970955904d9a5e79a002e3cae156694cd895873fa5559a7a9d21f090ad77d09471d0d00f3ea2238043fbcb76e5ed947a3384b05b838a796410b87971f95910bbee1c6815dfc9b3752382f980d48db75e28ab8efd094046de4725c802e1c3de5fee6503d383acc450ca7d637a1b5a68d7f099ded08791a3e845b0a8f6dbad10395b76745a4576bbb66fd6a8750a83616fb5dcedf961c2aa6d90d602d0526974a93ea30b26b01245c74ad5d060f8cdb3476e2a6c155a676ffe0e4939790daac867517a48271501a702568e7b349507db9383f6001c596077f82458291ec65813d6d7306e8a83c36d76ccf76e7531823e8ba7becaccfce8ff2e25504fe2cf86434d81a43b28daa7d479ade72e302f82030e240bd61a52b84b372d460d606fb4b2f649bdc51ff2cf379274e1c6bad82b5407516b792d7c3cb6545557fb2db306945dea8092e7ba6d033afe77833375214c816a4c463374cf36cbeb77a12ff095e9bc4631a3b459273bd3494b1cd49493a712bafd08c6a4d2c866958fbb773eed52f7398275128622b7436a39eb724c28d70f55694cf22fc3ab311653fc7c210265fd6eee872add33250ac495a2f54c9bb856d1ec8704c1c9fe0208a312ef3a08445ce3e9b4db2ea1c4b1ca4e79aa5ded13ac3c7fb69612e74255e0e6cc3a063d28b8e883fcbe3fea5db704e674497fecf7ca75110199434d79ed8102c510d732e612a18a8ddb3384b60f19aceb88e4cc35cc4af247edde5c8b26101db84dff825f9878761a6e96e104303441b9954091e5406aa9cf5d8e4010b4c075c374cddd31f471f694b3b9191a1f3d7e399693e235898bedc55628de4fe245e59fb02ca5fbf1944ab74e2783d9c9fe59f0e6f0de1b2bd70ced8f5e87c732c82bdac560e714546afa3836b73ad16373b72eae416e31b2ef999b2f3fd13f6f52deac065d0de6562cce840ba490d7fd1121d8fc66a53a27d3cab9db374e5b96d44f64b11232b2859df9468286f268bd4f186d434ed3b3c807cff498d1140d7d4b018a03b7b2b86be6c6b3a76a49c94a821989d2372744b1ed2e93e6e978c9cdd5564104d6ad141415ebd06a2559887af6b20f6b664e0bf7582d0dc1ed3e66661ceab0533f4758ca9d9c20211adfbb18a7eb7ed460539a48a131c59ead08680e8723276c1926a35081573d4e0c057457047e0a8e031861e5305e04c0619a06867be34f58200e4504919916c0f85945d19c7d2b2fc20af7c058e5f99fcf83206607f561e9619219da8867c73c933896e24f55363c0deb0d258c3f05c3ad71b3c03e2005145a6d7aa4546d53dd24109f20f902f7b77c8c475538788d3c0d0cd7cbe07706e144ca238c08b3f95672b90076ed237212adac8751d335320d2ee0ae94e95bc7f5c27af3c8da67b8b5d3630c7c6d006ae3ee184b5ff781ee470b7a2a9fc87f5d64187538100fde4bbd67be7a2f9c25c4a6f8e0301595963c280457395883a80ca695e98af29f0ecdd33dc3b417d09d0b2d01c5e074cc1abaf544ba9048649525f59ed02df6b9baa0b61871c4605678124cf5fd1dad07e892d2b8c0b14c0a9bf031493aa304bac36ea200f8247305394bef54f4608efad7435ef3ed5d5f5393225587e1ac3123dc1d92ee383e17d74f0ecb1bb025fdcfdbe7f2d41d0708f1ad2f766ebf69f4933ec0f8ef6f65abed4d883a38e0127530e8fd6ea36bacf454abd510b1ec49dc1d3bc31bc7d2b76c949a24cbbe7f676ba4677e19198d86ce72628e26f56b7c595cd07daaec87602c78a7838ae0d7d03a8ccaa8f90fc2f9e4cb9555d096bdfeacf4619eb3562d91a5414d2a5ccc90b565453f03a0f08d4ab41e6542bd2c687f62a9f41f348a7382bde0561e7c03700b0102962314b014b83980eb887783858a0c2e7818e7c7435a02c21a004360f29097eb414eed5ad78084a1f3cce2112639ec7f9ee6efaf166b3e31aa4af7925e6866743ff8c22d865f28ca97e47a3c979d0c2ba32eda8f862db63e07acda1757c8c7aa4b61d6011f5169f0fed9638b3662af701e486fddf0d599892d4215ef4252dc3248d9fd9f5ba3b5fb3fdd9ed601ee2a1b2192a5e01373441004841190d4a3b44eb80ead8bfa9c541939732913eae7904374d288645f4d5832691e338c82e2fc2ced10cc75e353103f383cdedb81e22ecb341ee19e400451ad3bbf0d10181a796c3063c66b1db825ea00e197d7b41558eb05a18c8e2accf0592a331055d5d09e436983efca0c334919d44f5cf729a26dc9c2abaa4c9086c7c0bded5814de50b86b86408473172e0e90d5d32fd6f93621a37abe618ccb7dcc2df0573d4006bdc0d832156c82735bcfe95527dd6b10e71f38e8b46ecddaf6eb7175879b7f843d821c7edf653b776cde1d389db91c3333a1c733dc45ead2f72644e125e4e2c7694dc4a80b4bb594cd052b470afa7323c5d9de044e9de8fc307512df126e794fcda65d4906ccd8caa5607eb203d4d183569d9cc530bf8db3989b331c7b4372ad0514614de405634d8cd1dc603189bce42e53584dbd7412dc3a7c9fed69f194bc753f45e24a289db30970a9a68245cb62196cd8a36a02dbed39edd9c40f4f5e6412ea5d9ce4d92505112f6dfc1fc46d0e83916693a35e01deb29b5c0d08c9ffe75aabcfb9af18c35e04611429e52285c5936f782c11f2b849280f009d83911bd6ed58b7c0ec9f8d822a538db8492e5f410020973536cc460861e41515c2e137d1f373e6687136a5057903e1afa8aa7700d5e39a23be933e972dcb1cd67ae7edd452dd3d229d957c5822fc1846175d48a5dd25adbe1963048bdcb5ebbea8bcac5498e7d805a0746a95f6ba9a8386c387d4ef863c424d62276a90c847e9019eb752ac6d844e0e45d78aaaaf567af013c3bd313ef23e06f4fc751537561ba52f7ec15cd460d8ab9ec917e1e33f175c3c1f38ec99a09da921ac62dfa458ef2d0d15d4669aeea8d797ea057ccc86431b4010f56fcaf4e7894b97d542bfe0321886333608e9d56674c8eb885086e9f312c6926713ad129c6faba2b764e4646500b72ad52f4158a071e0c0697dcd50bbb17b4689092a36bca28b1c6c02d39dae78e2484ff6b00ef8b5311cdfbfd061884d23dd65d1b0ca4a9aa491939e13202b515d6c709ed4eb0b86c4ee45484f84b2c8d5ec485686999bcbe0e746acbce53977aaeaf400000000000000000000000000000000000000000000000000000000000000000000020c10181d202429""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -dd746786f61c3e55ab5c50adf85106c1e6b427fcd102ca6495b52558626a21a4fb55fe9ba5eb91b87bce568487ebcc93e0a21fedb007f71d08cfd354477e9037e89d2a29f95069de968d619058963dba16a62b6dea9d773f7c1c269d889c622240233a6a092118c0545a06ffd50ffcb1dbcb5750aa4afd30458502c0d0efd753e7c86819353c71287e31de22e48a98e69c22cd25875844cf29e9a3e19749101a7a0dcab9daa82954a7a9106e274ba1da75e46f9d80ef302b52da908eeaead2fcce93be69c2c62532f0a666d6621a616767f2397973949d7b434773bef0a03c9481bf2574c225b5be10edee03c612dfe8adf07a5e1e6abda7168e04d128aa900cb82687d5f738969360b03626043946caf151717d27a1d3d0172696b9ba476c215fadc652d25298775fd4d7d3e35261d58d081d5393851b955b8f09aba98889fa54f78267d4289043a041fe871521e7f6518ce67a0c3e83ac47895a3fab018425a0532987855d4fe4a549ad372f1aa9483e3c6fca47beba9e2e217d606684c92f56709758f3da75929c37eeb99c031a9b446319e79f07e5a676275a59ad658738634ba8b8a7f8ce6d29eba2889c6d2b7d1914220e60137eeda3f6277f1399677c149fe6cdafff59fe1e31b38c863ba140e35c88fe8e3164b9e0715ee9dcc0815a4e1b3f4ae5b0ef18b1b76501f05d1304ae1e444c62899e74588cf9a262ebf2721badd1f3b684f56efb78cd38845dd3b0f417bf3b3157464b96c04946cd825b2b02278cc88173b7415dcf35ef6948087c84fe130c5a0b28cd6b0c45c3989050afa72c5b406dd2dc4d6ecc65821c716361cc8735d703073c50536e7aed7430eb35be8ee3d193812846ec860b9a0d363b83a3ff8415e2a9512a09fe671945e5b32702e477ba1870a53abd27544af0b431353d2f09f323a6cc69ccb5541da3d29ca3d6608b98640bbcbdcde5979b4d6b7a5b829c10b891f1b4f49eafe6e7464d78ec377b85290889bfd5cb5aeef23c9d6628834813867b7969b6382b9c4a18d81723c8c68d983009b03a1a8c269030d8eef2f84d5b860e8cbad943487ef691c78027e41be206c692e3214a13719b45c2273843b042711c58ba8711d31c0e6055ac73527de16afd81ce41a2882633a8b03fd975c3579fe4beb04fb6530567f5985954702e45734918adfa15431e33f65e10b8bdd9a7ebeaafc57562b47b1db5fdc8436f07c00d1c04d598cb6191c0e1fbfdda1549e5e0fcea7f27b6d4d34296eb39958129dde5b7e61eaf7440a75c07ac5ff2c3c656cb8d424dd992914f530984ed09c62b067f419fcde877e6333ee1875ff5188c7c35921e2e803f3d6abf93ee58326cce90fc22de31640c46bb44de19c20d72bc7672d39a02025eec9010defef580152c84b3763227b1958e2200216e9983dba36009ab592e2a2c9a80084a3595816098e53c424522fb89c154087e8da923672a3a9f3ae7c5225cbcb1cf9b0eed8bf98633da2b4bb5bbced0c08c81fde4156c9c6a5f8203bf52ce662343df25b5dd04c9fb0b814603274d503d6c1c335f71693830fdcb18f14e358d9bd49ec412201713022e00496674d43fed07068409cac95236b117943822590a3b756d9af2051ace8ea5933df1fcccacec0e291be9a4c65ec0e2b30a27768bb41eff2ee1f862ba7274f0a473125f9182461ecddfdbfd8fbe891822f088659acb0f1f36776ba219c4bf07c2a6ff9154f98c447cf0292cef0b698cc91173f5d94a629db45ea1c1ee1de5cd4b29630756fbf5b5ec7afb33dea594d45e7d37ded62efcd6063ce7a33068ebdeb4c444accfd8915bb24eacd7c5e537d4bad580b87a6273f1d0fc76750df29521102fc83ca432b918d9b66327b661ae03363df65256e4d642b55484dbb5203223c957940d3b059c822aa036d6e77178fbbc54fb020df2e81296ae6a7360ac767e2e88b74a88830eafb203ce5837e14a083c46de3bce7e0eecaafa5e7de831564191a8b9166c36df7d6a60343b837aecb8366de91509b54d973c9d6d8b5921a7ded1f2e431fbaeba893d4e5b9363d4bd737ab270cbb2c6d5655b8dea2c4a931a719428f3e9f905e03d885ca15f3d1647cc26a6bf91b7ca400eb3ae4aa03445bce54634cde581b471e3c03040413a7ac5019a113749918c1c8d24c979e7914f677f5135a84fb0535b6781e5bbd96d7ee1cda0afcaf28b1d47ed240cab6f2388e3c826d34fc13adfca7c41d6eda4ccf7021f2121f16057e70a1a68c97943dee4260e783babc3377a9a4a73a4393ca57ad398904f116e33fd83ee291c92602696c5b3806bf5898c4e56216be8a7691cc80c2563cfd1df4a06e437465f8a155a795880c61de03492bc9aa3dc9c6249582ce894b7e55ef06376da4088ac64c4bc227099c2ea30963f99ec6c7149d233276f15f2f0e21af7fba63c8caf54bd96d674f824862417273cfa7547cfe89692ce254bd6986a1cf52f480ab6f4cf8edfeb676fa4bccb0dfb2ddedc87c41cae31c5699a2a6cb413434978dbfe44025a0294db796a8c6e892be55220fe5e2be391366f7506f78cfbaa16f7cf43384182743fca7861a3d4c7af134037e297a55a5f1abda942dc1acb5a4874e5af451465a6dd2840545e9dc9539fffbd34c8db9834e7a7a9a5dc368c80f33ae01ca4453420dd9de645b209c8bc3dab783d7ffad5da47f318bdddad918d4b15608e7681c695418345bb64f67f5c1270fb97708b39973d8b4aaa2dc9c66efbbc6bf7239d781bef6885b8b35f11ee4028dcaf58cf8e23ce27a1b0426087a6408c43fb97ec56565d7c9fd7291ec8d24ef6b6c857f5f830d3a032b06a89f2ff23e62ec34beaacece7d4bd2ec04d70a2586694e208909d0da2190a03915b853bfafb36bb6eb6e9b8386f7d1ef8425d98c0d2af53f50cccc33a7fc4c8422e202038e320af2edde374b80d310f2972cf1cb80c279cb55668a298c9fc4489dafd79361aa4368c8e411b360f5c40eecf727a1850fc8522b210e39a4872a3207f2e73ea761e235031a1c2e33a337a6c1e1e365379fc96c3599bf8ba1af7b4b1000e7b64ead57893e24564201a04416bccc1ebdd8826933e0d7ac15f0ed8e70939c9660d0a23711b4ec8c1659e658e1165d2eac42f99751b4c0c2ae1a444c0e61441956312e279ae940914edad7297480fd44ac29b6a71f97eabbdb7090c3cb45e4a78e223877867227a9dcf8f2476f92b9329cb674b4bfa14079fb6b0acb38ad69dfe947d13424b0820e7860654d2a48dbd09e8d29d2ac1a51a6c1b300a536ea30aab4e26bbe287e47b2601a5822b6aecf3761907924c0906a1f91649b1bab2ee5e6996515118dbd0b77016c1a5622496d2a22e40f66be9963f6cc8f7c85dfbd3402b77b4ca78c59c494ea8703d5a656732279add7f0350bdf0baefa88216f9a09d065a339fc2132a07eb0019ef97fd0663a4b68ffb809f771e95f279f57e3d70d0bef7859ce3f22facd32f4dcb1787bc8a00f0e547c9d40940bda8aa13455e8a82b0a5cf4e482aa422cfe55d163d638fcac3d4abef3278be141a9c67d1588441f5b8c5ccb5930adb6d323fb086834a1cb5c6d2feaa8677e22cbbf992cdc742af799d7d17f0b30bb0f36d6ef7ac3fbe41d696d4896269a4c64825efb9b412d6fe4b3f3ee1386f2b5f1750"""), - TestUtils.hexDecode(""" -78A2B7A4C8441C36E0A9831F65D41773FE6B81B3FA6259A320AB03D460D7E38F4AAB2B93C6142FB0F9584E4D47074670B07F3CC4513675A4367EB8F7F4168F2EF7CA26AC45C8F23B2FD3E970068F21D9A3F7EAF005DB5A7157715CB94F5E83E3C955DD68E0EA689B6F419FACA7CD159237085678FA5883D5330796AD64627CCE7F913D1C2259E1F970E44988B08E78ED1EC01CCC2D0274067100C1C1E3D880B9CA4F3A1FBB345354D4837A6E5FF4D5F5C87985E51C471EB9B0F85075ADB57DEB53A87D85834167A4A538134CBC24FEC2756F7760C3D46248D5BD6022D8F88CE7D037935DB74A6440DA49B97E8FF376101B296E3A9D4D22E70634CFE88142EE5FB6A33F323519EBE3A915AEE5BB687DA4A5E264C657438B0F6AC977A22D0E56882F74E70D981CF37FF0C57D285D8CB07ED7FDF6D7CB1DD39EB0D84F2999DBA9273E0B716CE754A29CBA2FE32BE13BE8B9F2117DD7359494A0E0CE623AB9ADAFD3F15F644545A39055D42C6C5FBDB46D121308D649AF9B86A350B70F77A977C8268FA1E04F4EFBC2C95A2D72BC37E558F0460BB281D33F75D2AEB240086CEB8246E8A44416A5B31EC58AAA88246D355591BF7C622CBEB1CAD3B785026CC04C73E352DFF28D77186CA93870339E132D57B11F0154E0CED426DB31BB2E125C5635BD489B52C5E77593145D3100E48CFC8FE6975FC3F60ABC7FA4A4D9030A2CCADA3854BF9AA213EF11E2F85E9D4E79CBB434C65ADC378F8A7DE33E66B4F8588B73FA7F79AF4130554173975280879FBE0A59D25B969FC45AB20401CBF85463A83578E63D0C8324878F5CFAA191428E7EAE37BB17A18D0459378CFDD4C8C0B23B1429950F054DF5C67174E99AF9FCE6B0D8C98BAA9078D2CA87EB8A014995FB79F7F49D78F2674839E14C8F74588B45C28E4769C439A930B2A187764D87D71200E841263EBF74F7428EC554C12A7352FD3912D95C96E4BB1D325DECEAA9D6FE360DBAE7AB897ED467A300A8F4C6630F8E721F24860D1FBBCFEDAFBD94DC9B4237B91B243A01C41D5E98E67B52B4A8CDF0F1C985EC0EB85131F5E970A6DD6D4E1F525D9D94530157F70B333F5E50B1B95D569A012ABA959456AF773B59BC2891D745CC036D06238AF3F34081A20F00A831422CCF6E4593EB56CAA3B7DDF44B388CD54E5EF9E3FB8A260847BEA5EB5FF9665530A4F4B56726A4C5E669904A933AB1E56C020967FE61E72185D56B38B03D343302712FFC1DF9D857C6F744E3ABABDEB3F65628932D69C65FA112AE3F7D6ABD2B4C3CF572EDA73C959637D0C5C188343415E9A26E698170F8E31CA45A8E6E8E96BD066BDFDFF49C98C491149D61AA7C456D3DAE0C017A32B81CD5668A400127ABD4316F3DCEA171C3F6A3E99B398CCD4AA7E45BB51963C82C43398050B8923CAE2D4E2A2FF5232AC8F2C770C9A775F29C261E1C7DAF54F9FF606560F869638B666C90112B29F469C3620B0912622892A432EAB443F8A93E3E7953235EE78CD3FCDAD3F1391A2487DA621526EE92735284C347853D5F65395ECA2B50B0CFCBD988F99C86B5AC56ECB82813A93208096ACA04F22AC015CD9860889E9006DDAFEE0B472FF7FC3D5677EE089B0AF7C6C2FD5A322D60BED621B8F099C30C2344F453320B6FF405639CF764B101E1CDBD312495C2D4FB30E2FA7B3C345B9935BB28EFEA69C829EB57BF2E2E5E42B8515DED4C32F9C84C33DEBDFB345A4BC592CA56A769533FBA0A631D5D0E07DAEEDD2FD588FAEE648B6391422924D28D08B4CE36084C20E827E6E73A97852BDD7508E1CDC1630094C9D3A2C8517A25A244FBA388EC7DE2CFABF139888EB7372E2BE3BC4FC71788AC3CBBB3EA1CCBD9616E76F2CEB356C13257A8E5490F3C4F7DBEBF942BDB941937C956DFADAF3A78903B49C5DE34F5EDBF0E98E3E04E51021B686325955C14AA335427C4A116CFCB3B89349B1258B8E0E354F13F86C86E5E8EF8F57D7B7501C5D75B1D9615D942B04E1FAC4EACE0FA10E6DE9B9721EB0651EB3C9DE4C61EEAE7D7E17C0D699EBF7EEB122B8C1A599A2CDCBB9B665DD9A653698735D5572EC379ACC6A8470CD7CC8245F871C83E6FD92111F5128A9797AE802889E4362104775CDB69FCF37AAC22EE4532FD0B5ACFDC4DBD56D9CE8B9EE2A8B923F42FC512B54204CB971BBC9677EBC49D287A3F68A31DB8AA49D6477B287285B88AF298E68C6EAC3C73FDEC94F7062D204AB310686144168C155281627F78C883AFB49DA50C0F5139E2A0ACB9A9CEFCCA39C6F4F0F5356D2898A4F5DEA78FDD20B79662F4D066E73EA4069DCE6CAE300B3028F15C98801912A86E0CF34DF53F7F6E1868DAD92DF22A238C710F471596A49843D3E60E4C381F713C21C3910ACB1515E5E30252C94F040F00A9D1A08A4FCA329DFE190B5464521BBAA32932022BCC5E119A96DFC941965CDF3B739F53DA156553C6BCD72927B07CC3CC945FABE44B7348257A9FB41EF85AD5423304E016E74E03D5164D9F15838C3A4BFDC29C6B9F134054B53B29183A6A145CECACB3EAC7C18E31CB4BF78BC8FE60A3B8EF880CB6C1EFE7EFA8D77580CE200ED96713E32FF23B86CF532D8EFA2FFC8DB1A9E65A78EDC30090E3DC02475D84F8D9F2BBC48B114C9E4A01FA79C17FCACCAB1FD304C7F901942B9EF57C918588C9CCEF0DC5FCA7AC84ADAD547982EF9E855F6E88D02751E8E7B8B76C3796F94C9F7B7C6860042A3A33EFFA55AFE1B94C97D68B76DD240346355012F036DA9C7E025C3633CE867510D54CACD36D8638FAA8EE47D315FCA9D5AE4BEFD6150086DFC368DCE8DC623ADEAAA07287F9B291252628F1BDBA5FE6DE45129509651FB048D3A686FFAC5F2299AB0133FCDBEEE8445555F5C649598649678847FFFCE6E0DD9C4E75E2F6E77B1CEE3A1740A94E678C1191EF46FC4D9648887DE6277B11D4C242DC4A427AFAD5459BF213E0A20EC74EB0C210D0A922B9E690EFDCCC2C160E011AB94F709C174F22629969B6332738654A133E8A13EF7C914CE75ACA1C37DE05A84708DA741161EE4D23C025B405CDEBBAF9040A1CB7492294C381FD069C4622BE1EBB0113F25F4E1D5A415C121055CDE5616662599C2364481BCDD35F7E498E80D2350AD3B34C205C5EA73F1B923E6197E07C502BC6F4F4288EB46013BBACC49A5DEE5071ECAE62B192294E904BF3FD7BE08F0C43E3EC6E23A7F68115FEB285AD388A0F8FB94126EDC0331834179C1F10CA5EC54159FC256D7E0AB3129B22E5AA5D662C6A03C7D9A6D066400859EC2D5B091C37E35DE31365F5125793E7F653013C722045F7292C014123246D611A7FD59E9B09EF24221C7EAB249330C91BC9F4D3A223D9C2CBF7130C5C057961BE89894221AFB1EB27A4604BE310EE3C395E479D852CEBA4C2F74D4DF416C8836861BC13D0692863667AFF8EC89BB9194407222589E1C27B9D59AC49131765273228E79C2933445B83D07E48A789FD6E406064593EFBAC4FFEE64614C5AB34E5C2A717C50AFA79A96161203531C161E46D71F447FD28CE4AEEF197A3DCA6BCA306AF09086D6BDF35A861820C469A40958923BA824F3A95CCAF8531E930210BE46D66CF7156EA0728F3448292F47ECF20DAC7C5E78A2A0AD5215FF37594D37A2AF4778B15BB1B5C4E0A44AD5910B62CA3FAC5BCAA4CFF5BF97C8B8CB239126CA09E92492121C9E6977111E6E5248661AD122C87007318BD3D98ADDFA1B2CD60F12AD1E072643FCF82C630C2093CF4A75B2D3F809A0496727E04AD60F14CADC7331B23D9CBE28EEC92C68C97E597C2EBF99F2B"""), - TestUtils.hexDecode(""" -b9e56f9dfe73c5da4ec32b02af5fddebd5c84e216deae6a4f8611a876fa4993b9b333360ee00007dbb16bdacae8af597cc2d3a82359d8dca6582fbf9546b31867497b6cdf6f42ed3b09cfd094672218c40a24c8905ea468ba91c02c677a45abf5aa0421bf5bd398fad978fddc4634f6e9d36a03cb3d6eb64ee2c35f85481b1c4bed1b268de1483ddb4896a89bd9853c8f5beaee8b760c8202d17af8012a859f30c3023507d6bd8e41476174c2fb24fb1c944fc525b35c6e81d090c69713836e236b12106e02792ad51000aac32cea27d42c197e88f500ad336bc6feb4b79dbbd29a90c6e0f30011821357d111ec1cbb395212cad14b339a40fd9fce06bea1397369188c0d79e112f8c453605aaa3e28afb24730578eb8bc738d1c8e699fdf40438a16100e30d023b5d5be050a934d84d735a5650e2f599a52d36d1f9bdd91e46316bd62e774bcbeecdc7f43a89fa59241c12d2788ffa8e7277707c7df292da5141167d130aff17369c49d978add54af557dab19e746391c9f67157a58b4efc7463ac0615368006fb12c3554ecf35902e5752dfd7c34c97846547c3da9020ecd665487607c084ce909c2b7719acd1c3768ab6464c07c17e1329608afffe63a4ca07f6c9ceb74605c02772615de81364524121f8ffae29360d69f8900e5e9fb628e9ab0af8200fecff1ba1bd01fb6f1470a3771ef57d9b8e8103b3c2201d233de6e6602d490ba822b8eb4ec515c46b7b7dd0bf95cb7eed44573cfe11c168217e32961180d74e4f10463a5f38404540afbb48b21c878f1e7cecc13d664b03fddd6a33bb4d8c89023bc54602acc1cc434f5886906b5de13e89b5a414ba0f75d8253bbe031f2d82863e4e2f85f882a8a64ccc90a663ec9b6abd7edf2e8992f9aecb12a24acb52e0b05dee0803f521f833d0c0f238b06dd530c14bbe9a64a38198ce98a91f80358e6af37fa804710f043e7fb8cb5562f0c093d40c57f1b2c476520ab60782702d79423c64c874ea0ea0f4d9bbcf029b54b11bd114d50ffd80f38b21b4caeb54e9b83e0fd4551b7d56aa89ff0ea546433abc7e2b71a1a73897c803709a85b9f2c45996243445b089d8b3a75fce6decd0c42d622b52dedae2dbcc83181fa23a9d7b813127d58457f03b5e0cf4326188ed9bb894b9d468044897ed7397bfb6634808687937c8dc0d9883d9926d1cd63e0755ab868ab1de5a6d8cef72f72ce4e183d626605d6ceb6da8bb821161f3ad12eb124a1f09789b67f71a7b5819c3a285b7a8027d1cbef580779444dec21bf6509f27e7286c9d8274106cd3ad0baec6fc6f40fa3bd30a96c27d48280b8f051ce1679ea89a4981d270cf34eec5ca1ac399c422ff114232e68601d328f4a4c23ad3d52843c963b21f106f82eb38a379442b0ac389c59992c4326c9a54573b54ccdf1358389346df8c5d8c4064dd216f1d5e8f5ffe31205da0724de69187349a54b916fba25bbc4fc9b4518c57d5b715bbbfad14e50f8f48c81baa2246712b02cbc6f83cfb0e033ea90734495c9f82d185038a843a1f2d0a40666168a4df0b8e7c08973f64c4af66006109fe69a016242709877801e73319e1b2409825f9d827fccf2001b4dd0a4f455a92a58d13886f5ce9efe226dce7f3b4e817fb4f2185eb328c3b20192cb01901d5563b83fd7e13d0fbc3cde890cfccf91abfcf6c93a8c9ff31bfbe12a592e6337a0451983fedeecb6ed9ce67b6a3628fe15d9d6e8281097f8200fbd8742eb1138d3e6c70c1ed95c18d156bd9bb879610c28e5087097dd4a40a102a400b7ccea6babd3c419436024052a8a3c6c4233627d967a91bf700e10687a30316b67379fed8f4d208e27cd811cd27021abe8a295245f865655d2956d60d8564902fac029b65a337aabe99073b70162027995799552e779aca9ae9de29a458d6eec2f8d2fee0102786381b4ebe8707bcf9400c0241b83a4724f81e776b996c112226b8c7e1f5c1d090e9fa9b88c26445367935ff26c8d3c08a2347851a8f40b677b6fc5503a48f99782bf182a177fff9f28b5f2224b77454b545f018a131f8a9df7c61f35ac74edd7481a4bc18492cde936d5cefe03c96fe2f60be3edbe53d7b5d3f8b883523ac6235fb777f1d7a41906dbaa1727d1defeb67504a482beb8ac2ccd9261aeb746f422b5e9a11cc21ebd22dbea164c46e59b09bfb5213576955089ade4ba711d4f03646ae86df0c5495e0b5b5356d55628f40089d4d78ee33ba6f0f4080aae73fb20b47e979ad7dafda20c69925ce818ae62d2a534727d146d8bff6276eb02a52b2d56712da8cba1c0b48ed1f3e180d1bb4c365d6f14946b5f76147aeae4c55fd8be9d11b4633659df5a6a2e6dbcb56d32c7bbb88fd102e8515e959f322db8b6ddb21bad4a5c345d43f1b9a244a24578c75c626dbafc3f10e65e023783394a8357a6d5e005962af2e2f8fe8757a7cdc45823b50a0bcbbfcc6a46809d46ad639e918c97d1f038d7a3d9d87fb67ca95023d40793f96aa31c4bd3431d997746d305579495e41fd4d5b08cba5176924025bcdde3e36ff0c7b04b1b157021522d76e61ac37cd4fd8afb8c86609afd86a521f42b6e1892cf64cf278b02a7df422953e45c49cd07b9be6a0694e977d8e38b582c353442e850d488e26403f42fc2b533247eece1bf8dcc3808592ca51e100e71b50ea0714652f15c308b59d2b5936168acd227cf1a069e607fb6fe0fef48d582811106aaa4eb93ac836466319ba1597dd6a21ee2221bb0a6c068aca48b10a71ed42814a5273347e176c860845445c6f3e8dfd85ec2da37cb08fb2fba67bca6ecc5616e937e5f24464e22e4a699f27ca0aa321162bc5dcb799d4eba8f9725f9240dd2a10e1057e625f286bb999db6bad91f53c7abf54ef8e8a7741d5528f1adcff8783e69c535d79f279cd046373a012da01a3530d65c5aa3d0772e773dc7e692d0b8e17892e4808a24188c0bd48dea755b98a92ed4d8bc9046c81c9bd9800d8ebb100baa447a3432c4de07a68f666177230109c733be367d73c724a118fb665c858417512d91e993d83047622a9f5594a9e91467608b62c27bc07988be98187ee0ecaa7120d0ed54531fd9ccb17329b033b1b9c771c32a2bf99be223271c91feafc475656cdf78b4acd5226236cf50e9a4e79d7b4b4d9cfd14622a2638fd2c634acd4ee0b91977802ba013a98fffe5d6744d75d1a20a3cf3c851387d08c79d9b6b4dd418965eaff722b926c02f1a06563f0d963a2e6e99f10228152fd2a6bdd6468fe97955d4e81d0ad1f0ee301b1fe33c6935c3f5f8d4f7cef773550d32825b7ff05867c76e9797c71aafe5fd6da4767bf4f8c1a62ccf588521157c252c6d5431c5d4b1f15fe45ca0780989a9e99b7e1ef1d73cab9906a27f7d92609388d11b6381a9c21da36cd5245b2c9193dbc1c74e7967ef694a0e928720646b90a296dcedb5de5d90541641220e03e2abde8c2cec28ee3e7b04ef380dc913ba595c7c3352a5edde20b85c2d2a7525035e5f6db59d82a01768c7c1be0c57ca4eb389d958e0c96443e60fc6ff57a1e37c3bd0571215097fe26a87b835da2ea03c83fdf607ce72e5c76ec4a89e1378cc042bd70effa1e823f2129feb64e5ed7ed216c0d37fdf8d42a5320dcefecdeb28e99ec636f01973df6610767341da3233f1d2d50a7d922e93b14dd5d713049da206d3f31422f9f8d88014aa6091820525b50d1ba5e1f9d33f084bd2b5b65210c37f352cac249bfdd0c9d38d4d62e6c2bbe3541bd692721458b3743f902ca8ef6a150e8538d9dc348b704475d45ca3480bafe55265c578f3cdac8c0b0e281a6827687f391775f05979791d3e673b2cfb1bea5dcbb1cebec43a32b34b2e3ad97493c179abec83d02a249d52dd10edec00299704f0daf869d28c2bd29597215aced1e184d5e587caba773461499b46ed8c7a036ccb433982cb89af1a7e243a3466b1b2a9243770e427feee9dd64a96a3a8b526bd2df6ce6ce3425a59b7147c86997804cb109f862df5151e94a734020be056df7769e3f164de280bb45d7a5c43da8b8dccc48d4b4bd3400f31aa5c04a76e863fcf9c7d7e7eb04f5d769aa3cce83251a40e3e32f0d437ea9a279fdc21b4331286441faf0e0e18abcf11318b127daab6c8e2a8c2d67aebd6fac6139e5cf996ba502080dee6cb6fa55aed98f8e28211ee175702e9a16a2cdee3d08a7150881ba3b44f785ab768cc857bedecc1ab8f006a1377043f731ad801b23e6f18d6404c58c0d738cf5fad7cfa87cfe6446eceacf44ca811e1a48fdeefd940324c904fccfaf2a36b2bbb2c2383fb8c995051881a7e9d96327ee92ac43832f98932997069b21bb0868403c6c586f986949a43a42fc982d33b5039acff3d3dedd48ef05e61afbecc2d113de784925a101552d5084f05720230b6fcc357b63a72588317af5fbadeb229fd1221c5bc5f7a53efce19ac146d677027a87e0d49876e12830b43392f1f68069d5702699ea0321ac7ea78c18e64af520c333a8f3f591a1835d4b34b428abe29d1f0377c9305e0aca4f903e5127a397149d4be75369cd42135c7415d0298610572c6b95cffec5b0ae2fff70de6e12386db711ec9b676ec483be1cea8ddfa0df57bc60d2c8a76fc87d273c6ae4b724c4d8d3dfaaa11ae2da40f7990f8591adf689cf800ceda9ef2c8faa96de3290a3bedb2b73350846de4b754d3f7ef20c4defed3d9cb5afeaa6e1d686a3d16c4f1b2e65ed51b505dc3fcad64aea1c491338c4a33292088b60bfe491e1e6ff0314252cdd6767e983b53cd660dcaa4fe83bf0433edbc28b53a5efb2f5e6793ab1177f29be6cbe572619c7d191117a7bc4dad806dc102aff25067eb47a5bbb1d492f80d37c5968c2e40e9d600e7910ec77a0bafd7d8fd938ec3e0086d84926a75f9908392764c8dd8a76439f0adc99ffeb7af9d0966bad2b0a924184a5e9415c1abf791e15c700a69c0e7a62a854886797fa0d5c7a42519a6c887a23165808a608d9bc625f7775fe7635b537b5a35eb94eb5e81fd9a7c0b1c74b27d0af81938714761081411cb484ba7387c6c233bf7ce09091ab8673a3f10aac3f126cbb090f55336caabbe31d05695185635fc85d2ac59ed0066e51b023350083b2b2408ba874b19b98bd360c12885d64634d3c8c2f19f0feda4bcab389038ace498af6e2824c101fe5b069f6679044aed84ca5dd4dc2817b3c3e6fcd4e2f1874f6011ad05fe9e6a5b474b6c082e7ce64f3ec5d276074af695b6d3ec3b158a99d6de3f4237592abaf05a460ed2437e66a78fbabb0bacf03aecf9b96b3ea916d96db12d7cc6f8bbee54183459748a9c8837824d5f7c6015b564b146c255cbdf16ca894186566185574273344098aa03acdfcb8679387ed2c98dbacb6f2e6150306ea35f1bc05694110d83394fc1a7b4b93557a969131b70890933c530204ffc2371cdfddb7c6342a06d87c2229473654efb2b53f0826a349ee93d90fc4d4ad3e7e3ff8c16d74ebff6faea4b07dd5e88999bacdb1b51d8a9d9c0b5e5276153ac0483b96ca76dda17b931c526c7b5858bfa793c166bb680a44a0c0c66148f81177d8e9bcfdbfb64346c9179bf45390ac550db7af5d9a9b43bcc168ad29546e0b168cf9a5b44747a36b9c4e1f630c832883f9e6d10e2f89fc436de0c59f3b8e23ee0c156cc395de1c135a9de0e24568cac9c2911b21a0a9cff405a8ac222a3ffdc0d9ffc47aff2a3e89ddfdc6a8cf60cf28b3c7cae78b6bebea7bff5a8a47a3b707f24b8b6c4441718ef88108ccc26034ece28f80517991530273a5888eb1e36352d45e917b0283534830e914c5f083704e87e3c4c4f2205d99e1480d3ccc44f66a5dfb0607ec052a5a114c73d7bace17576b9345149325614c0076d7f044ab3f34482091be999a269a266f86a95d11baeb907e636f85fda7439cbe8d31839816ad20fa2fbac9b9ed2414a28d7e70cbcfa80f8e4e059ed003add7553056f7b94cdb4459f3ac54cc2c003fe60d6a44a7fb6fd0520c50f5c226a2bdae8b6e8eb7f18f94ee1b2692675f1b52c8da3141e5f859f7468b88e25a7d556fe1598137e893ba1c07ddd1af840e7f568db4b139f1d9f791451f76261f3948ba69354b16187cb77996848b629fade50a4d33e5760673e7b7466633f5426b17157e7165933de8547163903aa002df55a20a1a90a5c7c93c25bfb53f3f57e0045dbca341b9f14fbe2710532947e3e1bbf9d98a2f46bc526db5455189fd359f4a9c52dd5e5350650b010cc58b6ba0d5d11bebcd9b6e512d3c2faa728456b7053485f24fb351de898dae7893f08aa5509f808e6d0cf2b3bc46d3a9d3fb73633de694a0ec1d73dcd22e818b61558be653590663c3c66cf008ce3f74f0cdb241a9b54d59e426ec1a0436ed7e7fef471fc927432c09c8a65591531726723e0a46527cbd28527ca0bde9165860839dfa2e405b71728a8d96a1c3eaf516327895fd14476265777e828792a4b2f230638790afdc0312214448b1bac8000000000000000000000000000000050b111d222e343c""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -846d5071be9f3c8a2a99cb9490b9aa8c794e568b4c2da75439df54fb42f6182850b620d6efd426e4a843d6d7ec259d33a3631f45f153b2c1ac14fe1579c5aed8566f5ad80eade4ee8290e3f2cedc98290c92b83f94e0ad6910163f734ebe5f92bf6fb3ab56e03725a86593c35a9f7fc5bb99664beb330b3cab837772dc2ca1fef7747589758898d62e0c53373097fb2b2321f8f8c397d2631c4d0900e9ff7d5a8e3fcb453034e1c70f3bc4451c649cbb31989b8b0a2d3e33b9f138458c5eb2fa76a2b27f9aa34841e8c108daa5ccb0ba3847d2847055bd1553a467e8554ab3c54c0cdcc439ba7ea6a39795d7008239599f09d5c7060410a8a12301dd5e68f65865b7cb636d7cdda135436615bca0a20d982274551e549373f43c435729c98147f87bd0b344411750da35ffe77b73d9d429bafd7f2c7d6f43fb6a00afe8492f45c0be3431db3aea58e945303c5d1d4d4672727848d72e32bf2f7143e2de29e3c00678b64a7a9c275322f1039ea4f751e4b5fbead29b85a823bce1d4c0d1cff1a5084f252b10d8281764c1ee8aff68ababc78567c759095fb64425d4ff00a5491ae6812658478e8b062742442bbdff9ac8e288af8f2a64087c2dda5c116edebe039135c5ed850c190ff60cdcc64a10b3a849a028e0c66420f7643e98aab79dee9d943ce7438e82705dd1d7a8f7c45cfe442ecf3f7b474f0aaaf1891f857351a2438f2d688384ddd33f0821167189edf67908c0f9ab6dc928fb6e0f69ac40363ccc7eb1bba1c38726eaaeddd350f3a5b077800c2f0557f9bb1f116f0256f99ae103bed8e8250f2f1ae4c01dfae76aac4f4025fe9897ebd7baca7a74ef7d6eda19e80c5701c1dc995f0de8c15d7767c11c572d4c5c4af1f8155d8ae1e196f83035d5fd89f2b6e4893d5df8b16b70a36a674892f393cf4f83168c3b12e428e1ee2a16770ee7d4c2bca95763a0ca91452c5643835196ae0c00d6bbb8ba6a76ebbd198577cfafa536b71c8b837f2b501ec08be9470bccb69925b625876812e02254b17ec5a7a7f2aa2f32707bb84831775a8e49ae31d82b006e76bf4c4e965ed437f5298b985248261df1e657b6fdc51f7340be6a56d3d358667f9df996bf97fd6fb4c7870565f49788e600e9e54fcd8c3a487523c6ba49a2d5f0afa819b01f00ca75b846c0f398df771b34e253db4e6f7748c4630b1d32e047b7686bc201ce3e850faeffff7a2a5efc3433a6e5a386fbd8204c18243cc582e9f3ce606be436b0f957ad73dc7cd65b3dd0c0b336556e4d9247cb041aa33ac5e7d8080883b0e7359b7128ff0c6ba39d6f392cb1f7371e4c496bee32f0785eb0134f74ad9bf244a6ef9f1cd67175795b9a965b6316fc008c1c02415a20f44713724e1c9a644a6b5d1150e31cd54c29368afaf2293f7c2ff68906cf99f5d32fea44b7c4ef08f627ff91627f8a0a2d828803e6af4b93905125640a32409fef71e00837a9d89e776b88d50e2c0415534223af6c950bc2a2e8a7cf852bbd21a0f2f20cd03a9fb7e8214df84a3dad03a3345dc44a1d15eaee127f50ed2588269f1c6cf55157b9f96239607cfddbcf55bcf1d24ecd3953e20a54a073ff3749c8882595decd36d8b0fdfd0571807e233208b34324c244a2887adfe1cb5daf8b79440a44a019c872813ac2dce13fef6e58ac58987241ece2a3299024b7adbdc89120d88823e1bc8cb8ce2217b443770e411ea969459c8c56e40346b2899db2abb764cfdfe82c7dbc1ae868baf4bfce840f68826e41e627df189910a780598cff166be972117b5c61c02dcede2d298acc8eab96ee718cbf4614d1bbd93d8f231dc6d18e4d8f4b396b5474e70c229e6219c3af9b41b83bb5525c1ea4f415fd06da7787a9d9d318c298446071e13971f7c742f3ff61d86bbb9a2347e0608fa335f006db2a618b43c2225ccffd8e34d924f8dc60bb1e34c1822bf1860a64df7b8a8c0d09e78a3fa17587d50aac69a6eeac1204a23fd3c4d7f02635988fe5555ee85a247c2bf6e952346b8ec11e76149e672a8be470132a010c73ce62171da95cc84bc086070d13eedc88840540f81d2980fea2cbfa94e5255e475c51732fa82c7a8795df3421ee7e55d391cce70e7daf7a80766a84d23063f93f75119a70bfb8086d41fe9b2840b4a48f0157f6a0382da9c332971d99805f2af01941b654cccafdfd95818131373b3746c00cb663cda6592e913558e61eef2eb5a2bcf2936f86ac5ab935d525fb0202b116e4ef0ea063643c7b58a172923aa8b312ab64be7ab8dcb04dbb35136d7d7a15d9b77ab3fd6ea1d45fe3b8c9f7286456d33f2cdd48c5f777769e570ac0d7ae56543ee4b0c6997041e0c67d82cd21b8b6d6f4399a7372f95ea0b580254704cef65e8d4bfb2ae556cabbc26f513e02c2be2cd9b1352b925dda37310d72df63436289bfbcaeaaeccb84a34ca75552f7b545e97c75add87bc3b93c8c7cb01f0fd813dd47eff1e40ae3e230c203b7d982cd29fd22f2b8548b98699e706155539b05d052c7ffb3150abcb5d990c9171db4f88ee7e42cf56d10eba0cd08c17ae14a7b41da377121902564c2088e647bac379e062b04643acf9d07750d3b95f7132e41434d4e3bb73ce29267761fe66866db875ad5d798c10bd14cb7c382132f19b577f3c24b1994b97bf488a3b3075a1c20c4447618694bc25b4f92283819a6a445fe7b3b389dfc74a544dc26a3429502601d19c38fc7cfdcf5d0aff6c28264cef679daa32d0bd0b80532d02478c09514118d9ef3aa3b093983c1f800d048454c7ab27a8220fc00a4285785230e7b97c415eb2cdc2c98131fb49ad4a7fd96d51b6077ec872cc95935aeb42da23e5e23342d0c5459603cb948d2426f68be756ed544a300474b4de646841b6ebdf4ee27e80d6820212335093eb29a5224ccec99af8cc84c65ab1b648f24aaa48be9c9fdb91dfa44e071a69f127e2206a00171513404f051a829271380a1d0eb14493fbc9ad99a205a2b76049489bce56af1946873a0900ac6294c11acd40a026abfc366198786eea707d5c97cb1bff25471125295d3e3ef6cf9ef7913a71204d162e00a614286c06325439d45ea06fe03e07d97566cf100b7e24ae606ebb7681679003517be905e7faa97a4ec9e57b97793d91b998be6c4d78b72b37dedf10620d57702445655b36476e893b3e212c0dc0b12c1a84b163189f008217945b60108d058029df8affb251756001ce79d5d8b917b20c4cc246548011824ea921d376ec7edb15e35d5e5d66646714244e228bc2f7956291a38f2f36da55f1a2134ede281026b32ed374c6023259c43e85437bc3938a869f6d5df3a50df8f2fc70622e1671a4ea290e36be376a99c681b517aa68bef04a252a4dca9dc19ce11e8a75c8a9f4146d670771855418b2c19a861e4bae7e73587a4aa9036a7d99a261ee745a03a32e5a13008c9b81d0837006beea487668296c8b683c98a44f5c155ee35277a4b97e7beaf690a21c5cb208cfc53d3c7949922cdfe18493efcb1426e8bc5707aa7282ca81b00e9d3d86d33d3b6b3364abaae0d25ff027d471b03abef975e27df7d8aa2ce5f657e2f9e120ad97a6280836754f16e86cce203c1246cffed258b0ce9c1848e05720663034019c43b2a43e25cbe96ab2fc8c7b58485f9bb105f"""), - TestUtils.hexDecode(""" -B5CD00AE06396DEB95C9BE213BEA279AF0D10F1423B5A71854413E99F7216D9EAE76C8AB884545496559B14AC9A69801EE3FD2EEECCC557D7988F34B82D244461388C7D4EB16DAC3C0FCE0783321A1488DC16C3C688126754BB4C26308054545D2E46C6BEE26C25A7C3B701341A0323BEBFC50C718162B7FF3B6FAAE7156FE300F2219655D8D44DE89845393011A2B466233B907355467EC49C9F832044BDFCFCF722D6DE7946FA503861C80037549ECE8FFF95026CDA33C9000FACC334765A60456084A0614455C83E0D5D991F7ED43952B7A69F1E326D7BD33822CF1F286D85FAE78F0B8DE186368EB334CA56070122DEBBEB920C5547C46C1291E78AE48B72C7A39020A1A2E54E59A2E46606C99E652FADB39AAB25399B0830AE733FDFD973294B93F47C30D0824686C735E05FF51A95C1C76467A4BE6BA80C5182353BD510E8D4B60BD43436F7021B3F5980D1A769B2E3BF04E0C257EF577828B327E2AD85E0581787B9B7FE44D6B826BF8405D3D0BF8974D2B1C569006C7FC3D2891DAF38DAC36F64A256E337B660CA59D2B45F1B4AA1C0C72B78495FBCC9EE9CFFA4B5A101F973E3211E728040904B0B2515DA4B1CB3774EBEA1324EB6907324E733C7F17BEF6FAD0F6BCEC1F08F785DC6FFE02FFED5C0B7A631907196835EFFD0730FC8FE020B0545C920DD7B2D705F22D8D205804397F6FCC60386F4A576204949EF60DEAB269905707396CCCD8DA9B895270CB39839BFD3EE64149B0085B96FEDAAF8C738E449E585ADBA037BD560EAAE978A6ED61DF432B6A9C2E50C2EA33A8702A23E6848401F85E2C18C7C767DB15920C9B3B030728FD9511F8903DFC8572A3679F986CA1B684B3AAF489DCD93C622C6C4D475DD60F10C390873B09B5A352B6F5A104C90782E053F8121317EB8D1D4C0145E04E3B68446B69A0EF81097CC6BD0B756AF78963724D9C83C61B7B79647F0844867B605E2B60988D2D7AD07CD6BE2D8F904F0D269187C141AC67C9DCF9961BBFFDDF3BF34D9CC5781D1BEA348F49EA8FF7750F7F3E0624C16FAEFAF1D8B6A818AF5FC5C04E2504A0CF4C2DB54930EFA759A292A2AECA1EC3A08918513D95C44BD133657FF043318A17BE4A5DCAC54B87FF38869D017A4B14DEB60480AF1C5F19A9F87B94B8EFE0DF3F931CFADFFD7AA50AC86D9CAF6D434CC81E6ED123711E34B8295A446B554F6DD5350B44C614324D8727F1CE501743043DE6EA085DB5154AD8E30E114A02CDFC96BEB4F2718033B227CB8638BCF617C73BA4473851E62C8A287CC4F9C659190E60AEC468DE7EA8841E3CEF893F3DC79DDDD56B63102EAA5B2793711A0451EE1655C6768393F59CA6085866FB41541D9997C94BB56F6ED5D731585E7B25B1DC853830DE5DD75F66298BDBD2E505DCB3850F96CCE0D7274633234EE2FA1E2782DA3D6CD8F5DA2C3063A923DCB6A2F82614527CA2A88C1AF21025B88A08C3104C679175DE2CF00602B13E58FAC9376BECAE56A60A6A8F144F1C98C8FBDCDE6FBCA4ED13228FA77CBA5CE631BCDB368AD9219568777FB4397BB40485A9AB63E9E3FB343154108D8117CE25BEA30BC854A241745FC6C26AF0D64124AF10BE4BE01B8A3D842FD9CC4D805B2BE26F8B7BA0631443F48C7F74207F640B215E0DDC42B1954A1EAB2C68E63601DE3AE3EA54E16282BDED00FC7665A9E8B098BF034F5E950ECDC46CDD22210244F102E41E0930FDCB24AD6C72507E5AB6FCCD4D6B2A2703C358EC1B51AC87302A5F507BD01CA6B5FE04EA2A5322EDFAE8161965524C61956CD201C4BF2F01B54F008F5F4B6770D0622099CDBF94D6C41DAB4A5362D630B9BF9CE240ED08D698D1AABF29E60BA533697C3C830521314F13EECD95C7D2600E2A756AF19AD94D9EA39FEEF0E3EAB3EB401225C2E55B2F2A8D7D1A3AA77A38BF9BA31399F6E6458F3F21DE354BBECC2E29740FFF91FBB23E0F61D7E0698CBF82D439AFB018DC5F5011B7BE98993E8B655D83C666FC0CF84A532C7655365746FDB97874D62329B1EFDB0B0C8A46056A85B60E38AF8979FA4910D2D9CACC3B5C1E42049D04C44273953350E0F756081D2DF6429193768802577C381897BFE540BC036293643360C848A1AE388CD17781296A99AF0CF75F81D568D0648C8A15436BDCB16FD83287C6A54F88F2F75E6B28E1C5A3AC03501D6D723AC5EBF90517D194A596F7F95947CC169CFF2A65D2BC9B54CA6AA45BA9E901D4AAC81FFE9E62A479EEC5B3F9BFF24C69FF56EC52F1183B5AC48A5BAA90BF595990B6EBA5B1CB6D88511C7D0D165FDF2615351B0343918B966ED1CA0CEBF6956BD2CA599E18619E1A5930E47CAEA92B8E9647A0262A2B24E955040750E6C7B935982CB742EE756DB65B462F677AE09A7521B0D3A42C2E97890C47148618FA6089975F5D491F4D3F69EBCD54C2B53130698A1F4A47505194F675D68F2DDF5983B008E498AB4A25956CF724F5C1250D5F9C75F3DF9BAA696E300AA86FB4B9378EE18E79D015CDA55D6ABBF5B0BE819F9EE58B49656D3B112AD8FA6651A8905061A8E37760C3F2EBE6DA611BADD44268975B5000051BDF7158EE3DC200B47FBF8568C9F22719FBEFE5906444DE9300689BFA1AD167"""), - TestUtils.hexDecode(""" -fca242816e6b98578837b5592bcd66732c06ac3794932640ca3b71112407c8a4c0989723966ef76b5409a893b8c2981d6b72a1f5cd92d81c12b9cccfc75547f44c27a56431f324a4f73ce4f91da398fdbe6a97ce171f4483fd0c1cbab53fb80c41963798eb10dc422ea82719a0770ba82e1491512bc40d726b83b3cc1887b5648204b00e8231a654b4a796d7c1c0304e93579ae6ba4f0945afcc0812b86cb8872842ee8782ede142087a46dccc78275aa2e52f2e9344a81c4a0ee65d4a9b8ce1ad020ef6fd1e6cbdf8d5e56b1751e67be662b90fba01a983df891eb2eef4886a1da0b6bc0cedc4b44f33df8ad946b68e5389104b46e213690ebad5b50fef7dbf2aa6f51b125657e779d9718244aaeaa55ad0bbacdb76dc66973e331be8aa3e6a13dad7d227121e5fd1edffdaadc6bb667e40d49c1d95c6db663b4cf374a3b93e5f270139c28e98fee799a3ea015ceaafb881807058b199dcf0b447f46d263bd43d02cf232ad1c27c3ca8e0cfc1c07541aece1980c9240e77b9f134694be94bbf05eb6710797a2ea2436cd6c10b18a260bdef24530eafc2618d17f86922e91c9fefe7528de98bcfca9194e53affc13da5787124dfdaa0e95f3924fcf6fdbca78a61aed2b5125c6b94733eab6a215856185ab31106fb293d996c9a8e80f9bd1bb2287a88df24f7f127c371d5c8503622b3986206acd99395bed7633e5f73a918a45362d58c921362053a0d2133a1989516cbb8bc29dd2fdae2dbb94669a122e81ddeec46fd04ba600d149cd728285f2836a3023521ab1362736a8d33635a6fceaf6f9684af304a557225e4a80ca403583b637c4db7e9185df6bb77dbb3b09ff915400bca75a645a8ebe36b99948369cad683c56f0030f4f8b8f6610d20c7662f538c855bd1d08b719df8b34873c4dfed8046372063ef58800ee7abd99ba66b60098e0004395c2646ffb158411526dede3d9c9e1b481a2dc5298f27538c6ed535fd0e7374ebf2ebf214eb14bc3c674f61c1baddef4435344ddbb08d6fc8240ff5e41b817e9795670f399965cee0d8a4540b795580ceeea3a31c61c81e3613331f21b496e8dc833ff7494f50e81f0366718622602759d598f1831042a5779ffa9ada2a00c79b0419ecb05d3ceed113160653bb7db0d06a40fd272afcf7f20fa18dcef490387b84dff70e761dd1bbec5e1b25eb30fe2c4d18135b3c5f315da29a98855f81f9b1e01450557ce6fde5b2471dfc90da07207a6f6d181cd71e33af713c0dc353f7166bd6aa7b90f82eba2c03423144fd12883e80538de76f02a0e12cc65051b981eff9d25a36ff79b4c6c84ea537075886e9be23f700570e43e76e8d61f54b49a576a99a57b464f2be6dc8c993c78a1330ff3580138964a6cc2cd46006ee1a72a268ababe373646674dfb4bf33126fbb8f5dd24f4c79596c783fc88b393a75355ccaaaf698a45d678b01f175bb31bf7d28bd44a766a60dd8d2510f55bed7fed53f6718578fde622c49d17fa64926be1a084dbdff206c025ff726ddd2adeea11a021680f3e75b865bc364dd7d752d3b62b7b240838c5645f5338326897e751e968fca1b99c0baec1c9fb227d6f1fe61abddbe26613e5abdf6bac54d658b22cbf8cd498114019f712027aac6e7b1fab7016aa96ff61bde12a44d540e33c30bcec417f11fec1a0536f61eeba565d4faf3b624eb1205143e3b6e6d22b8a0ab3767739206a89eab990bef3f3d763a816cba5aba2b2d8390235a197362382c2487d80f9f47f0714206b1aa9f40840098c6f94d920fe21950274f7ca9d22a506a76a328cb28a50ba569909897b15ac2964a111ce48ffe137d86c5aac313050e25f43b9c041c93dac0293a8694f76845a7a83b8e14db7fb2a724df1f4e64a772e6c3078e465565e1eacd56c0c4f13a3a90b53bcaa0451b44ee94be4d6d23707057b4eaa6879203ba81ea953090eb450408eb6a9dab8c5bca27c87cc302f286e703be7022044e0ac4559d4e861f4e31f8915831cc9b81dbe937c8b0abc02b61c57debcfd0f5f8ab3d7bf0b05a5eb7fb0bb587de8c2bdc41299e744db3c6f92aaae2008a14f965023f17ea55fb0a5ec6c884c478cb3a95722844dd823be55f15a363354634a1b3171e349ad6c69f1342bb3dcbf0cb44efaa6d06932e064311057a97fccbb1430aff5509d0f34aa57a7cebcd5eb5e9fd373960065c79f52a414d16ce959c97c1fe0101e4bea038dc6b27ee847335073f62a91d1d74ebcdab4965e1cc501c07cf4a6050c406028f6250d24796fd4736144ff84616a63a2136fe4b8ac9652d95965659d55b67355f5de40f6f11e08fbfbc2ef005b3937204345e03c07e67803a8c378368a7cea377f53318bb140e0760bf79fae16f4132bbc88d8af335c07496fdff21e36ca375889ed56faf2622377126d399fd76ef9b2746e1ab666461a949c06727d1ed191e197418ab7574bfe292b92ca61e7972e4d0fbc6001dfc5438f95b54c9f226bda6968fe5e5df06e915fbb58c6123799f6c8624a40b18542c18cf82b89b606ba532584b1542f0b0684be46457fd6f295f0a3e79ab8634b8fd747d5bb87ac0b33902804f691c16874f881a3acc4b1f88183dfc3defe276968bf7f7ed53e59e2e5fc0db0f13dbc772286f6d83cbd47617bd067035c93259ba9daad2f229835f7c9ce8759109bd1db0e71b9d015c55ea94325cae586fb1b50f4792bc4c57569c83c26ba4cd7a809e799b5a45961ffa5387f91d9d653fe2cef5783312e12fb695a1b9d2004bf5d73819dfb406a7d3243613356b851370fa34bc32aec270984c77cb373cbf6c65d1774ef95539d4b4142d50f3cdfc9695e96cd1a0a3844ff8507ece66c2ea7bf27bdf020ea8fa95c6a7cd0dcf37a591f2cdf7a6d7a04de5a89583a094a53f68636bb57fc83968ceb47a53d37aa7099c76633e23b5eb1b828d2efa427fde9cfa24df7518886af10ed7734aa278bec197a60dd8279df60fd5012852167e9038ffd1388f6753af0b75800aec92ccdc0feb08684c28d51ad1ba8a14b33eb0a13ed08020f8416c9817a63dae74a2ad51bd9c9db0c187ba1df3deda995727ee0e8d78c9a3d70d2bbaf759fbde9226646a412500865e2391189e46a671f7a9b2281509c412e5ae2cd89ef17a42414fdaa90d12e39b07ed4744217e4a461a48aab8e427eb7cd1d07cae97886ca0f4b8d2c88c397c96436b0540aad3e6962c78914b3ad092b1a46cd1aea2cadf236c9d0d1e7669bb3035bf8354ccfe5ca70e7e6e6acea47396800a8407017d64c4199cf13155bdf44b06e01b92628836712d34e2ce4c8d635cdf1c3ce21b7a2ff1268c9ee9df0792b79d35e466242f25209bcda6f68f07d80db030e244c479c66cfe823220075e9c08c2f8406ef7a5600677f4a0673b0b5bac9d5e388dda323cf3e2d967cc0b3a705a456cd194c1833855af620952dfa2fd1f147d6a58ac35231377956e4b91ac100e3f9d8b966db4861ca45ccaccc6ea63b0d2d71d4367bfc0911e106ce7cd73f31887536754c880b54b5a6abcd3913c505c2145fbed44a23dd7b04280410cd648b59e7ae00b10099ce56a3d615f031f9091ff00c2248ce6cff217fac3158aef781b88603ce37e9aeb4efabafdd59f0a460859b1f1a1b4369043869a27cbde6a8914d1d3d88e440927af82083950eeb3bab126e9507c8baadc1fe98353f01022df09d8848142ccb7429a5b4a7669c1008d61ac50d6373b258f8afee8d830990853b9cd18b869544bff788f5cef93a9e3debae6afb138bce6ecdd9b071dffb5d629e0fc544bd909bb7bbeb3597d0a285e447eb49f7ddadb510dcad32807d3d0a571a731069e22aab4e730f50e295357813cd46ac3f34c4fe2d5029fc19a772f7e647cb18635fabe67f1588b18a7cd0ebcb6994cf4334316f6a538370887a0f009adf3348257fe9668b7d784ea64e8e9931fba22bf2f673b222196eb5df852ae2715b58cb9b737583c4b8c1003178093fc288736c246fa0357daa68e89150cf7876928b9525a264625991fc403b1b5edcf4f9a58a570925044c669a3f1960c06f35a21b826603086e7e889adae25db3eff02f990af85efb01e1bcfce2eb1520d2846c5de1ad3caa65c968dbcd8af5b925a13871f19524f1db6c914827c818d76b1e05df95ba322ed03061eab164cd501545d3b4ad2c4f9b5d7abe1dfd3d92a422a114ef56a4b2b47d31f5df38fa7e3853ba5b1c1e9e955dd4a294119c3c314fbe4ae14362a6522e34b7fd467d22aef1a31bc8bfda12025701df52ebe6fcc52c1fcfb8ff94d62d2a7b0f1b8db243391320e7fdcc0ec40576caedd0f327c5a0a950ddb2994fc389fa77e54f569217f4139b91e545432cb7ed0d11e1d27e9c4536a9012509d9043557051c01911393c592f36a4f162f131af522f978e940774aebc0b672fe88c590ea572f39dd5c87828d3d9d16e78b9433e54da904418c5ab6e8db7851f4807d4c93c60503ceecd837bc068aad6813206e382e84b6e64510f64f1346b9fad25c37d77be5292f1fd9d5463c640baa331ccd636e7485b752db11ebdebefab0cd9d8b9ae11f724439525661fbce8341badfc03ec2375536876a954a0c553e274027f9f53582bfb7d20520e1b8ea9322fe0abc9179711768bb2e78554eaa5b0be9023e6acd94f5eaa7b74a98adafcfac88fb21d810feb9f38dbc0c8cc006618c771c31fc82aeffd693497bbbcdfba2028cbc73e49ce074f425ca33585c891bde72455606aaa252ed42e2edc7ad7aefbd9ede2a51217f2c6e1ac300f6868cb8d0fb6bb5ebcdab839d4f63255b7079ad483a6fb383c4f0acb7128c500da9fcf7ce9e28068f265d3e266dfeca0e808c0cf8e98de0f61fe495eb160888df53bd872bdd9a7b8c89ba1a5517ae69c2b49753dce1fa1c215d6c1efca5d241cab5229ca657d28a57d34aa16c6fbd829b0aabb4099e472b922387022885de324ca45a8eb9245ad53923beec04f245e4fc6147895e7e0fcd457a3786db95174d8480701e2d659a2131d89ac98c627357851bf57dace645a1d00b3636c45374a5c2229b002a0ad8c9aa148fb6521fe35dc4ed09e3e0d5cc6bcda45925ef6f5df442f1ec4da7583f63bb2381fce6a7a9da4fb79d0ccaf2a4bdceb6cfe584a33b9cdfd6c9f3c4a8b71d4b3da17f174d6fb3b8c48a6a6f6cb78289f3f217bb377d7d210845e09ba7543fae4de9d397bc76b3a46bd7aa47a93a891775898cf4e865c5587746b353ddf1edbd0b6384512e558a9f346ceb265cc3c4d7d37ff83e6f60899f3768c495f49919ae6e80aeba85c4cd34b7d90d311f03a1f4356188df30d402031b916530e0e9da31b17ce87537f0b0b8d918fdabe536ae6bb6b903173f834921f5c998b39dc5cbb74a7ef677d72aa4cbe88a8823a8a0efc7de88713ea127c7e8fd10bfeff3e19334c7fecef45876f89a6800de74276920fcb6c248263b850b5c7a945e1a3a5129e774309c606f6585d037c15e5f824dab8fb74a9cfd49b659c98fb1c66c2484761cbed75343db437eab18ed7b56e5a3c0cc150ea98447c3b5c08c9f9d1801bd6b6ba15fc3be608aacb92c4abe8f3f506e75714b6876f5b2ec036a1456627e567c6e488cb6ace2cf54e42ddd41b6810bc93f83270b40fdbb79be84ce8e60cf527a1d04f89f22c4b936353015a8e05c23799cfbfc7fa58405c07ced8fc16d50004e364a6db3d3d11afec9f6f6037bb7061ae0b0f4f4ba3157728d24f819a3d12e237421a22c0efd8ae99651437bfa486c033e833e360935dd433a1d5aeafef73c71b5326b65d6df9994f988d00a03898d2354f58e3308b3c73b149c8a2b0165309d64ffe190a4bbf89a8633f30d674d73b1910811951b25aef8313e510cebc2f8e4a5c4286e2dd4db0dcb40b1745358f511c29645a0cae474954fbd907345b30203a32ed6848f10b5489f58914397046796e143bd412a2ea5feaa811e0a7ac8a756ce752d75eab8b6606d8d3da0900d621fb42b90e94e3aad05e0c42f9daed64af510f4846a4f66b1782d9d76dce9ac84fa2912808851c9bd23656465a64c5fa582e7bd1fed8c38e7200b601d0504f2578497be90818e69d1dae9a86fb5c2772e891d699f002bb4d579d3023df87651ec9dbb06ee3bd4a9ced0451a1c5e0a658712d704a92c2bf21527417278c8c105671e68b06aa838ead92c6a8566ee5912a18b995e9d1b6f9978fb6e378eb0924143da6fa15198686b8f5620b607e25e0540827f3454ca9dd085adc6e2c10763a20d6c70c5bfe0bb1d1b773bd267ce33a2b9c08a04a254d9c844475cc013c4276f947ceacad1c31976898d198c91e5ebf2623ba825e762665caedf1674775d15310972ddded3c75178dc3fb715d75ed071a292040223fcddf82a3e29af547a18633434534b15bc10334bd1c8504e210b104100c3a4e596573b2c8f11c304eb88ebebfcad0df1b2f5361676f899eddf0233b5d6f80828410172c36397f9495aff2001f4667a209394a585f607bb8e0000000000000000000000000000000090d131d242e333c""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -a163f0cce9b86d8807e6ed09b486e1aa12807f2370f2cb6d886eb2ba3978ee84b7929d54580b5a86b0b7c29360399d37ac01374ee32107c9a97d857a7cdde38bfdd98150c2cedc2f10221a9061eda3b576958b8350cb89e27d4a3c30fff090a550643bdd0075da1b9831f971256805f102a6d59bb803b3201eb312924efda3e379f7b6130da6814c91529c23031ac3909d0e02e2110ad1f9d56abe22a1d359ae7db28ed5b6adfebf17055803967a1127d771f4c9adee662dbb277862240e03f2fcb6915fc99436775c91fdfd84151cf571a728cce6c4055ad18bb9ec10e39e6b3c7094ed3db3193256926a102cc94d2567a37f665dcf052e20863e9f8fc66b56bd471168681fef3ec42b641ec2eac3f42f99f702da13d9aade502e04e41cd57d5b05cde8861406b99e12e37a482014dec0cb4a6b90d97d5ed10153a23a86093105e27da2d7f3f34736f1613c4e86dec37597a85460c104508a5fe555bb77e951eddab081f9cbac0487c76dbe00eaf1c1ad87c06a4d7572c57037e94eb60be1ee07fa39b343335b16cf487f327bcb731f1592db0ea833121b21c2712374aa0fce26d676ef67ebbeb3f220e4c5caed17aadd42f09cef9b2fb7d5b5a6dd983eaf15312bb69186607bb3144dace7e4a603d3f82b7394ccfe67d555057e822c86e68b6ce0f18c218fc5a0145eed4c32a792c3cc8c9a56b6cb5b80fa444314470d72d6d84bed3db7328153899cdc04c2b753285fc44e3eab5d74e77977db248fb774166086bd37856f0be4cc7a0503a901443ae965b183dd75205d8dc86349b38d1b58ca7b8415a5f3ce70fc6fba330cb5b22067ff75cf074d91fc57cd95e74633ae348eb89efdeecb6e2f40cebf31122e0ba834cd30a35cf52478bb9e6a2c7b880a88f76ecc534d928d75f59be681a181d22fa5661a7d58cc9748eaf8d789c1a5741b2ab91219cada5047d815714c1e66e476dab23af40c1275408f3cbf8c8d7e591e571885f64c6548a066eaac99b9f92ed7c5abc4267fa926e961deb28a98fe0492085706aaf4810518bdf965ac32c6666b59eee893e773febcbe5de8db551f409593600659428be7b23951359d5394875f00c31fa7b707929550dbd62fd2696a193c49687f872936907feb2bbde12b3fd874a4e9d72d2765508f9ce08d9fbc2964c9abc93e83556a51f1e446d9b92a2834e316c822fa5f361d44c05948740ecf776794e453ca7057465e20e6819d617c8d0e245d2588e15c71e7a7ddd5cf3613f35da272c437bc8c334d6f9fd186d31cbb9de5a9f739258d44497086deb7e564a0c95d6a5431f31d470a1f872b20bad7af0a8b03c01cdf71567324efa383eba0e1f15f8474bb4e205f6e89f9a85d66eb57c6d9be0e50a958dd4b587ae9b4c3c7899d5bbf7d4d2945598bce9111ae4bede064d57f151fa171736719e0fd27625ecd15fc8b46e06477fc9c8f29c01874eefa8f7bc964ae223ff1e9c98814c01f5ec513509447cdabbc73cf7b96d06166e5524d2d433315c4d4f2e9d709fe0f78e88603336d47c7e301aa91a3fe1dab1eeddefaef17ac096017069e2ef40e3bc17035b80709142d8eed4c34637f41c4045ebedc268f6fb20c339dc5a5e89584722a4a156c26b04ea424426d70580bbfd9a2e095e5aa0ebad35c825d19df64557826f0c5c455107a5c06644afc4ad1115c1a08764d3af872ed3487a2e40e894c1515b16c953d07dc01ea9f2a54b2f2502661260e64b9a58c5000d4adede0347eb75c6af9add72e595fcac36ee0a08d7cd2da6e0bb3a3023b772c5535c3a8e6ccd52b3aed80a1f50a86906eac6a552ba07a8c7b16eb17b62f63f423dec086262bbe90736a47e4d5501682c5147c03d06a8060166790ed0673c2eb8bf54e890c579b2fa77a863411467a09a7673f5234c5213321ccada607a58a55229f8953159d3b67688305268c2a7c799a619a7d3fa69d4ca86969d428033b5adf318db78818f136f651f2696cc3aff43c3012fc1781aacf3de7973b165655f98ac9e7d5158a4edd4cc4b33064bba97b57f30908630624c13dce7627823b9708df52389bc4f1742d86b244f74d48dfe67b2076723294eab5cfc8539c21401480bcb1e745c1fe803e6e1fccbc0dab6273abf1e2f27155534f6b9a2d06aa82a7a7aadd1fc574f42214f3442422e12d3bbf7b2857fdfb8bfe4398b16be9a225f94934615461fd9a430db0c5e50c25beb3e3341e91dea7e8b3f2b05c25af2c1e63448fe311115758432cb09d8330d28398d9cb360eda112c245144742b733f524e8e7368acf8c48c1c1a3641822ff56388f0db4f3988cec2888bdee3d67a75bbf0ae0e6661582c7975e9a05d3b7b50c86359aa4240573cf27d7a6011cd295d3edf1bd0162290c0ea094546dd36d470c63166fcb4950a96f7272cc0b05144ff5d6342a27523787af5f23dd985720e1a8bad426f6dbf2c5f42178d8a71b7f473a0c9dbe278a0ec837da78b9cbe74b230db8a4079b2cc2c49539f78d55a1253995a2a822c7711f46c1cfd379ed523fda80ea91af7c5d872a5b6119cb70cda9bdc3fa8c4a83531c71f5da27ce6d876fe653e2e808eeb7209eeaf4b492c09d47385763775902afb05ab939f6406d582442ac3bf1113f172601c168b1407f701799d16b56c82da29ae0067d6c7f48c2b4a6b34d53fabc300ae7f55ef5f7094e403df40731538204b47f8fdf28f855722263e3c3f058f53e585275dd8cc5457003d60fdf32dc3703696c23fabad72cd64dfe195f2a5a3a54bb5c8e39443fc1c621fa1c140b5291617974f6f2600f47420b3332208c1f39f6155bb0c2502bcc942278ed27434077046d7a9d393ea87ac2990b9f3c7aaaa3107f40614a1fcb5711151f85f595018e48234d567814674aa0ed81a3a1b597d8c410124cec8a45cffc4acfc8a9429ed52008fe6fcedaa856b5001ce12da270aa7b7adf5c079eb88dad4d640064cf3ec2eef00934b75aed8a03cf04bd154ffa5804dc96fe81bcc2fd48b3b59ee470c4cb841b7b73e21e3b35a3c6aa8c793b97f51d552e66b8a5dcea3e138666f957beb6c64c3f8200f147bdd2714dc60d605fc6e47ba644fbe648f5cc8ea2bf52251242bfb4796c6462e48375143fc4f9ddb0543ad0ab15c54bc029b9c95be7da19aca2235085a2157b3a2968f987b738c395f99095c490f8a3f3ac186a86f2d09c8280799e6810c9fec0af33bd5b27b855c70c3b6ffa6cf85b6f76d32f076ca4f11878bc38d58e308676e8ab1587f9f889df68c3712394478987e70c3a15ef5b5249293f8e18ef6024776cf53b10f3611bae24ad3e3a4a78319e7ee8ddd478a43894a7c104e42a5b0f8d0f0774553c4efdc2bf72188e23d954032e2dd1dcbe5282e800057ae0f170e4ea9aa076c60cd4840ea1ee2d887b9a1c95aed4b0df041aa3c88214d47107f8e11315b9cdfdd2f488c88baf8479a163ca994880b3607c99625e1d1cbf59effce1661a520943242c63707f1b1ee6d331c2834e4bad510d04d96159ffe1e76be6ef380afc6234c530c479ebb1431a0eef0dad3b909e75977b25336b76899ed0ffb50897f2d523e8d5e346adc4d5bda3f647bf624b85c66c29797c97c579290f7cbfd5bf20539629ccc65648238b02ca58ebb2a8fc314357747a95d2821b1b04485320d"""), - TestUtils.hexDecode(""" -506462786389055DE2E4AA2A7C80388315711A7B5DCC73F2039DB99380D48D9A3DD8CC8B929B0AB224DAE74EA90808C302197EE9D847261DEFF4136D3B2A37CA32533384443B9D935AF2C384EA63E7160BF4BEB89EC0EE705D10C72F2F65A4E75ED2B1901F14B8C1D21DA9C6B8842DB62443D3DF12969CE4E45298FCFD6FB103B87B0817190C5ADED4D04E3BA4D2C3F60CC49FE0695D6366EACB9C79F28C9121584D997B7A3A7AC3243C3C75FC86AF81CC8B888E90095051F7825294CF7E1A11464BC153548F8195522FEAB9AF5AE93C5F6CF80D9ED76C19A0ED0BFBCFCDF30FF6EBD0E5C20EEEC4992765FD23F13F027E2261C38D11FD1631846142541ABCB82C0EABEE5D675EC130861F9BEE9D9E02305F168C85201DA1DA2E4D21CF1E4BB8C2539BC1F3706194AEE7E3ABB2D7447EA531619FD27F0CC7D09E5FBFFB0DA81432D173321C433391FEE90B92E8EE3F39ED492E78327D8A3586B7052602607EBA79CC9AF21132C7D3A9931D5DB4937FD5C5611F79C722E0CDC48564E416DD251C46C02567C4059A0DC2F59A124A4EBAEB9B1B04277CC47A9F345FF8AC3F8AC844A668AC6F7E1BF1C9889C3E42C1142CBC31A46EDE21CC84F230A483B5CE23A901375B27770BEC8F0AFA25F301B7AB43B714C6D0E98B009FCDDFB75C0E26EBEF7C9DF5ED04CB4183028DFADFC09963AA8CB3A9A1BDA047F62460F2B88FEE1C05D9E68D646137F660B68470308225FFC097474B2B2BC5D50A025724FB2CF70873BE7D04C05AFBF1D7DED56693AA4A4E495B1FAF9762DB83DDA6E75F530ED5351D171B7BD06E5ADF46DEAD06AEA37CF262AA33D062141F8E394E731B3942D084E583090F9CADF87C2B81C4B7F114D150C221A12393BAB92727B828C9EB86600B969E1B80F33E1304CEC68A1B3B474762175EA19A4D67220004FD4EB0B2C643B69C00FF3876E9AF63BBEF8AB6BBBE247668DA8F2E3CFD0B95D6926AA3A2CFF4587C45DA60BDB03DA78DDD9758FCF9926FA1F080A61FC0FC7660BDE9B4913C40534887B04E2DC666E981AEEE38746C52BF46FCE0E2233CE02C9307262499BE567C150CC54FB9D96B81D3A3E200EC8F7E87E28272E7B956600DD7692799473A8C63AEDBC8F3F43542B9E399398349B896BBA16E5F26210558DDFFB984FC924E1B0D272CB8834B1FF641A894EC113460C65C66BAE86248B48F675F1313EA76EB4DD0AB6EE41014FD7589D1A7DAB16CB8F113A3FBE7E01EC67B0B3CCD81C0A8C7E9824658C926736A574E9A0729C3BFCC34E0D4BCB1606E93287494577A6C4B1090FA6B997DA098C6CF555B5574473B1063B739CCD139C2541CC3F962EC42BFB3A40F4E64D322836EADA5F574B48B5722D7809A3A20EF1FDF5F3EBC000E466BC4CA10E0CC6A1390FDF159BCF0182293D9C408A8570789C485DBB977642074C869960E9648641C2A80D8A1C4E474FB98D7A3DD75D7AF01D2605945E89493699EB53E30EBB0F936B63ADF5859D9EA1DCAC44D0BCDBF2A069982BE907F1B560AD8327BAE013FBFE6E2709C9FDD498491F1D8603F9F6C9B1A643F6FAB97DCA752D9BDA1DD6BDBF52B03ED7768D98E46092D556C266E30C77A10E68AF76AC3D359D8752E2453B2E75DFECE6F66E6AB00EF37DA6E6A367FC808E1F4905339F4FA73545D13DA7E7DE49CC0A2A63639A96EA039C4EB643627B7EC4FACA1374EA800A505A80F554B3AB3233FA492ED6C17B5832BDEFB3A99FF1C64B35F1531A023415290124EEE2C9A7E34FE8563528B6A4B64DE425A8FFA91B753973CF0C96FB2A8A3F71D58B77C93C5866DF5CB5152B3A0A32884E349C63870E9CACA82F121EC2ACAD7B6052B0D74E9C28B20C76A7A821D192E11B59A7C8059FC49662C655551A7356046D46FCCCEB4DE1F5FC91F35B950F630D743C8218A10AB25D2FAC25308225540FC24CA794EF171DAD7258C2B7FCF43297F6E77A6E83184114DBDBE408EB644ECF49E04FD79769E4FE9B0530F21F8E3913A51094D0E49DF012144EFEC415B8B2A34AE2462607E7B89BB86F0C733A5553CAAFF9B19E0799A1901657BF4FF5AD6DA7886B477358E90D56BEAC6A963E0669C38EF47173503B0E9255AF1F153E673813053A899418E2BF217D01D9162C073F256CEDB73DC062D201FF6056180A8A6887B286AD6D3BD6B1462231D6223D0DF2BBB7299FA6FEFAA9A297C56ACA28E163533406141EB2E65F0C94A6286A0579C76A3A8EF96DDDAC9DC6A550538AD345FC4AABEBAC04682D4AB0977D439CB14F02FB504E10252C1F3ED01A7C4BFDA6E689D842D9B9086517A84AA4257D1C8CB842E15DFA615D2E3F2464E4012C0067EEE60489C044F43050E5B1AB3E54507422E1368CB3EC8CFB03A887DDF9695AD95378F875F14F7DEECFA54A775C60C6B7025E5D6C0563E0E76C05C93E33C3E5AB6D1E1C051B52D2805D3BE0A4D3E8F0DCE6BBA1DF04C7F76F7E13D8C3CFCB2AB04A1E605D4DAD72A43D5223FCC36EFB34D999095E742FB9DD7B69A28E070FD28138B403DF1DCA75E00A160ECE9562C92091DFD3A24C53645DED8E17B39D8CCA4C20C96F9C9F9D14AD3B45A1E87DA75B831D400AC14BF34A9840936C3277A135BC0E8C65E0F5E670AC912FA586FBB4E149B09F64D338C8C886BA65730039B5DCD0DCAD9D6EF11C228213438A1489F4FDC39395E8447212599BEB570D186883E02B442F8BF97884EF98D3D6E59254B3DDB77DEB8429D110F0689715F3E0A4F65908E5EEC867AC7BBF27CFB965727AF0A1EF37B21EC18CD60A1C87287527BCBF5249596083069315699CAD10FFEB2D87810C4DA090074FB26978E56B7D06186C48BFA4830A0BFCEF8FC7B95E73F64EFF78043E8D93F57EF6DC636C8FF612ED22FB21174EDAA59BCF89D1A60F0E1C15C5F8EB8E6A39139D500E8F28A5DB86C125C6C76A99BC47DAF66E679121557D85F5093806B748B3EA65CAC386B59C0A372AF2FB7C84111F0E0FA2C71E137958239534C4A012B1B421435B7BB8CA577DCD8C8B0A798902BAC9B95AB87B6A0735D1839DEE336996C2357C748F4EDAD858C81E2115595ADBC173782E36D4E720A5D29A5681231F9BEE91D455554A8632F7F02FAFAC0FD9D03804B10DDF4828A69AC1CF0581D2C88877BA30EF2982E0827147766F8B71E264E82C3949BB87562F810DE835CCF78A7E5FAB219E64B1FC615E7C952577B9B482F78C0D0C512833994895A125F43EFF066CEE293004E9E0E5288A61EF209EC52233EC64BC0DE76C78EB2678559724FBC05BB5B43CDBE86F6C481AF3BDA11EBFC0FB384AE00F4ABC212B0518644638F01C38030DD05FB06A7EDC6406CA18878DF38ACE8E974123D3699613ED46673BD04ED51C352F124A8F89DF8C13D2B44245084B7FA02677D5287D22102AEF4A4A0AE046BB1C6D9FC9733AE5066C69A10589B0F33780622C1709F179D4E8857564804BF5C4D83E03484FDBD1CC4D71C6A2421AA59043DA85F0B51EF91FA5DF9555072278331BF3102F5147021662D135F3011FA48DDA7C97087F01B7F86D549F41E244AD7374C7C1F698801CEAD305026D17666435217799A4A5FD0ADDF9B8BF6E31E51B654E4D697554D5F574213CF579EFB1B11CB2C136FDB9EBC0DE4D16DC9DF43E17D88EE22EC88326F65875439066CB47E4C656A3AC59BD9A576D05ECAC5B3E7AB7B1A3C0C1C48807C06F1AE4881158D6BAE9620B08BBFFCB9940B6A6D04396014CFD54E93D863156D16F6F9C1556DB1E13E630326C8B681CAAD146F32B6977200B204B632F6CBCFB2BCE9670D89A9CE043E2004773913188608455FA715D1577E03826A2471EF0143DB3C39E03D890F0CBC85040D1675821D282822F80EAAEFF5CAA49699B68B89422D1BEDBC3041AE2A3D6D5205C72123991B21AFFB312F5EC8F96922EBB44D7A0F8ACC2E390F9E3FD82353276D73E85FEC904AE6319B140E5C54FD5B6F19D17E65DAC5EE270DB3E402534B0F408BB3C554D93BBD32B255D478F33BEDF4A192233294B320393D38284D7D9987708C019742F2FC023C041219FBFE2B603501629BDABB9C4223F5B751DB78C144CC50D3A35370EE563D6DDECFD6D715F08E14A00FC265D8433055083048396F1BD4E9F010EFB974D6102401B2FECD972C26008A4B94952EBC61C35DC846FF7B3E20DD9C6E033BF1185F35A5F02139068E1D4F30C4778FF87057F34CE1D2D40BB61423EC055BB57B56C502DB8D0685B0ADA42F9C52B590610CE2F8237F92B71B3AC2AB75D2E6ABBDBAA1E554D99CDB687B72DE98ED0FCD618AF5D2B0196F1D3C19DB77686F01228C3D1DAB1F171A56DF9311939CCED0F7B22A1B77F473E8DB65C0FD6E307B6F7A0F0FAD69E5C1F87D01EA4699F4D5DE39880CF2D8E910313AA6026C17941C41252C06687A085903A502048726AE8EDDD2D8918B71A19B807889B6C2E866FB818810F427D2A7B6CB137D94746A88BBF068EAD31216A5511A54D81031D36C8139776E0FE29EF7C8A5EAA730C3BBF05988BB892F699F72F098F2931F9B4DA17243404F64C311767A98547284063D44AE74735DD246B0C189DB322058198F1D176EAE6E076965CDE68DD0DF2B284D23B94BADAFB8650F21B148B9C990F7044A777F9BD229F7905B242CC2E267610A42A5C3185C64079DB340D86598C589F9A96F3741356BF3E6D2A811B6551850F917E07E5289A07382B8B506C510C9396DDA81DB336179EAC1F84DB9D0E7BF52B906E82FD132647A84A299BA202DEB338B79F976A8D257E246B2B1B60425161C72D534B04355B2665129AD8A44C09D73AF51DEE7043228EDB62B858399B5A4312DDD7ABDA09A846A60FDA8D0C00E0ECC364A6CA95643FAED93D44BC8BF1264FAFA6D98528CD3BD1BFA352BFE1FBCC202F44496FDAF9F9EC53007915EB67F9F8BFBC88D82100210CD471C48F5092AF4253302475F9E60C287F0A8549DA00538432A342814E1F6043BA4355D72268F6E84A43264EEC3CAC024DD6E79143EB502A58E6F8478AE985797F00A295E84A0F669BD9252A3AAC6B2AFACD7AD398DF546"""), - TestUtils.hexDecode(""" -fdec4bc58e167745f07a2c4e30f8d8ecf9c7a6eeee6793f77c27353dab270398dd811c611b6191d597edf44df73fdc14bdc440529b77ffeaf18ed94a613fc3f340c55dd156e8d56769d509416beb75167dedc3fa35281ba7913e94ff5a374e0647a7f6bc99ea6ac30c3e477e69823f663e8748e8b5fc43f1728612d109a2947019331c718ac31e663d44041f88b7861e074f4e1c12ab2077dc59587fbc451aafd29e9a7d584b744d83d36f794ad034c014bcee229b847e8bdb120407201121f9f58fbd0e17ae318dc1674f1c7d9d3481629cdf02fe819de516854b2819cd6a9e97bb92662757a9861c113f67ffb191a086cc6cf612d13f0147bcda5fea3c05fd29115359bbe08a25c33a58a3b38c3214f8e4379b64fbabb00a7221fb01181c7cc2dac81e6271550bce192958a93f2f5a11035b411a00b610728f704d59d7a7e51ef2b06a2000fce618a6f82a06d18a899f7c59a3d12141979e8ba62aa4485caedbd6b8ae8f2dadfe21b7e27f911daaa80b6e22b91012ee5fa16164c5a734265b81aedcbd820b8fc5c8802a5e7cee4f50adc824dc0f0ffd626aed8fc5173b51ec373dfde19973df541b031dcc238a7fff8c01b36f8df74a0a5705a13880f1b49bb82cda0faebcdb8445048ed05cec1fd95011316a53712241f837f7a544c99c631422072ff58f579e5148885f5df4172044aa9ac4bef20e852b46ebba4410b05a5a8cd5993203f44075b0b96901fb73e1e561fe40b0decdc4b719c16391891957f97bd0eed0ce3c3b82f83d0afc9658d84d5e64bc83b2b68762b00eb2a0a474c2386fbbc87ec8b2dd03432506169f3f58f69f0dc62f140d437ef524700ff0e55e39264aaeeb3fc62940bbddc9fd1a13b9d291d82705ec87507e28c1ea90e15c8d3d6e94a66adc386b10a07c81daffb2b8d1176b958f61370ef1f0189285a49058a31c2257939df230e1218693f3dfdd9820407b509f7307cbf02b1dc1f182f9b3aadebfa7c73a6d6fe4aeffd3aaad272443df14939dd94af7543aae1212bb24dc7962e9e96d70f85a17464639f2e89344cc9b6867a6bdcd4191c91da327a003e62c1117af999f2f027ae14522bfb753bb93def9153c2d6c2a6fb8ffbe7923701e516c6a9c67ca2b2b5f66cee09864b6414716a0684fd2e3c2ff1f1d09731237dddad175b9debb722728049ae1a78401b7dcce662fa33fefc2c647b116467f25a42a932abe1742b1f486df764075ee8e765dd139f58762f3c61564b5fd52d4e511c900eec222116d27ad9dca25517449bda55b1509569677b2f0bc99c4d22de9114a8469a4e401f33e7576057d4f735e1c7661a8e986a5aad28026f6af030242535fb87372ef76023761a2b46fe30002e947a0b208f95663b34f8e92f72f8c6b58a9df690426c3c7352b8100c87b48639c072f0ad37f66d2b0e6c84fdbcb7ff506b911425a260f2a4e3ce3d6abf5d42af4fda4f37d0d4d511efd204c09fdc42d868cb8e036ef79b2425780df904fbef6e22f5117434da776e99253f0d444d1ef9cfb10f4e0782d3a5ae10b1627f7b71b040f081c6f5377dc927e65965bec75a5cbaf4eabe36c65ce71c75476c0b962a278077bd765600330570474fb68a30e9e427030825674408c0534eb2db8dfa2e986d45f06072cbbce4b3a2e03a1209fa8a9eca591128166b40bbb20419d31bb82e30b2ee7962c9fef7e788b55be7b9bac11cfbce39259ec32bf200d0b490fb540e1d218b52d04dbed8c3f650c8310e257d887c472e24ea02d3108712fc88de316657cadaa0d8ebc417da228dbda1ec98a61d1d1989dc7f10a0b4fca9f6dd2c614755bfbfe26586fdf8046bde39a2f8130d5bb9f55f67db1c9d9c7e626641a97b09d4dbc3178039d78e92b5049b7a5cd637cfe35d6c6b86771db2442040d15667c256c6beca875675a5106ca68ec6f7a01257c9c7b3464e01e8146085cc3a9aded04711d2c363cf7f262ef90f17c8ea28a0c15fc2eca9d970b33ab22fc43619cd42839f7ef53660e9aa88a32fbdcc5a74f370c6696922c4981048cde02342bcd5182f0d633cdc90b383068178de2499d41159d32f6c22989d230e0802ef40823a64625003c29b0b6c1d9eb39d15baa69947508c141dd169caf1c617a2ef16149876a56c6b2c4a92be4d48b3d277bb5967fa9931611a57893486fe3b8e8b92a8cae0496b0808b49b712cc6473ad44216ce3d1855d704561abf8988ca52cbcf7cf95d6b071acb061f03aadf2c50c4159380262edda1827050675cc375a82010e3e3299911db2d93727497ca0d75f5e539cf75d412177469afd91b1a8c8f36a2e4ac5484020eb0c7124ec570f94778e8a43e80d8fe145205ade385ea279d4bf6c4ce8998b118147edf888391488596f2737bb381cf46c939db876de724e141dbe7066f4a13c35cde58c718bea1e2b75f6b6d9600fa08835abd0863f2e3fb8f7d776b1604fb068f0c8260672fda6062e5585c595b087e399f6a6d1d26857425f600ab13113528bd2de7b8b78e933aaf344880e0aa06facaa7090627b4bce3b193308f8c152eb82e13573770e3a9171b2177e9593911ef00efee1237166261a38111f07cacd74f6a0c2283757f182a508ff531568cb05572eedc6e5b706c5ee3b3e8139b7ff6fb42a9b87cde81b21ff2e6e48d0f89a8adb77aa4be8db46ebad82b4033e857f6575c1bfc0500ae6b95c4c43843cbe7d83e8684a1275ee586e50b7241ddc72c017bd7d4aad25e468b824a043504ce3950b79a5dd2919fe3411dd250ea82ce01477306b09d0cb9a789bf24d22288e73909a57ffb7a1a395be080518d4bdb46e8648486ca8af29cf0311548690a2800648cff58534afbb5226c2e860178308236beee319c14811354b6b05a324115dbe53ea9bf37b7f8284f4b39dad5ffa4ea97ebd9bdf35d593d63026667da30e0df76941822908f6df732a8dc018bd2a93be0a21d64e33da01292fe3fdb5370a0fcae68f860af88dd8a4055960621524ceffc2391dfc237205efadb78f1df769e070b09431fb7206c2cbe3319312668eedbfdadd9cd246d3d5dd648d20758882ff7f3f156412394b7568dba0150e27fd442b6217495d2c42108e9f16e9167684caa81366cc25a31766e4743c49eeabe051cbccf225016f067939b238fa3e9330e4a7443d36134d7df29f8b260d0b7a3e14345b497de4816cba4921e18dc9dde508075da67ab8c210c730abeaddb040cf4e673ec03bd8d803fded05e1256d90d3c050aea4c223c174dc9242de76e95fe9ad0970c3ef6eb5e7afc8725c77c5fb8d265699779f9cb2bf8bb26a095472c939bb3356bdd218f0b2d99b29f0475a4858dba236123ed647e94ed485a1aaac64b7c2ed19d98f2d24019055c5c7ecc88ed2cca17019388419b3f9819b489eb837bd3c7daccff555c7daf5e5fb5c75694c96f566aebc5ad5a48c6f272f812b4606e21473e295c006c190a6430f7137c9ac20727e68b0eb6fbc8255cbab5cf3832938b7d85e6a4c46e7f7051571981bc3f6f86b9a6b149ae260360d21587485ca40dffc6e93c78e15b875bc82d31e04538863ad8bb8f736c23bed9a9698b51550f91caaab6731bd6feef0226fd3e08b3dcccd33cc6f7c8d8d36e8ac344f851c3596fe6f432017653df0030a64e73b1758322786694613bfe06cf75586e12b92ab563b583161292f328b56ef3648b050f75fb108102f0e28be8c4cb7dfc4283f68eb6bede47696b1c9156194c7152b79a96cd36639488215ec9d49f8abcd5264d89b51d72c447e31ac2011f7223789a82c702340a4ce59a298713aa95e17c6a3e92011f5ec81a3a9b6537f1331ae446965e58c2e1aff4931824fba76940c5f0abdb079f4ba8b32e169e3947594173832dc34e824f296e93099ae8e20437ef564da9fd48d6b6a2cb938a9cf884fcf3327e1ad935257157d0e8e379971cee3d5df59135207930ec1212b7f38b324aab2f172726712a9d60e40a0054f26586d5b3a794edf8f33819da983c209f9f4b514875975e40f72cf9ac1ec28811cca5896e9b4cccff414650d00e71ae2e37c4bb03274df43ea5edb923e157ed3adbfb79b2410b088c6ae9f78b10eb87b0d336c5adb19db50093a7b26fe1f39cb7c6b19001e4baccce386684acd8850cfc64aa0e16ac6cd15625e73b798651fd44828f2d6c4179b21af6dda2262c79322f41a49b9327f8ff0381fddcacc5d1444f449b54d8cd0103140c292aa49bd3a807e5af3fcf33a0176a3bf32ae337c4e187cff519a2589ec5a75bc531ae8092b72fc906f1d82735070b76818d0d5ca9266e7c0f4b9506f8adad55bd8f04f5b9baab4662d20eb3cfab00ab81bca5926b6909b5fd30b14c5581152aa37a3a275642f790913aa9f44f95161bb00c736eae908f7b3c0745514b595d947f97e67758cca97f754cd359d5a4cafe7884c10f379c9233e8f9de5e1a4688dbf92d92a256eccdf06819d7badfadc0f5235b3fb9c66cf65c6d755c5aed48610cea135d8e1bd748fcce6fe74cbea0cde943ef57d26cb7d0699f9069ea14ce1a66a5b57fc442c123409b896535283cc724c27240850ea8b9014d01d4ab2d8d151719f3b2421b60e2ce0792345f88bc26f2e3d4f9cd3a69777a114014ab481459d5c5d74278cf1c0ebbbac2919fc1a77e0997aee5ed24560563448b471e5679b13adf445634742ac1acab6fa5a0b6a0e8e285714c12fc05031c0ee83ed821bfeb0bafe978f785ba36392aedeed53e4cdefca5f4026b535d7a1a1c4ec9155b42f79c8224d286927c8af6b24c0d87e9089d2becaa48f11365e40df4810dc90e12ea6288cbc3cb2b84ac36af1867843be343c3c734eea10a54519d9c6bc0f04cd978360d5eef8c5fff75a3e4748d4dd37735919a1d6c7c4c48f5aa34567737d3084686b1fbe2f23e4a639542cbbe7f99c18a80f97033795a81c9ea029d51e2111e59c7b66a2c78629a1594db70c5ca13f3a55cbddf56f1e66fc9f3176bd073532db09afdea26530bbba27ecac9d5c164ac88f7fc3fd71781dee0612ec04b790d66bef2f748e93a6215408bfab48c4932277e3052dacb3384588456dbf15fde73c3a2036123e99d698ac5785f7027bdc21a130e875870513c1acd7802959f29cc2c3a27c1d9b97256e48666efe178bf7a1b6764cd25a4e8e97f0f55089af7fcc40ac1c3174f9e9d7c2601c8ccdb7c62930ea25e3ad4b63af9c2dcfed98ec7360e85327622f01fdb3617aa4c47ceae1dcb3b64471cd1d810d03540685d2a34cdf58ebed79b81aa1b0d2157f68ffbccbd4e617d61eb23c4c77c5bab60c1bc66e021c67a26e383aa01d3b9f53f20b9ca367d1e571dbff0bc8baf1baf9a934f7cfd06103aff1db525bcabb83b254460909151355d60303b86bce2a5d0642e951a5f1b356fedc9f6cb84fdc9c30e39231b15ca1d5e26730cb175803f4f9df3521e1f15ec7ad77fad4664cc1f96813c119874e5390b2b3b04682bc5ae2a81788426b185f57b308e3b061df87c9e69b1629dcff9b4104146c063143a40219e4c0844a58d2f91cc58dc9012de1b4c7ad6afa9ad0741fa13c651be4f27b09ec40d8bb47196068ce43e9585b1813ac01825dba7b02aded59d3df27ab5a18a7100b5df7f68b51d0557a5c26d794cbe0a63539a16e1c3f612d8a30965271ffc16a088c9b70967ee3229e2404d793086ca6f378cfc5d0c560f9de81493cfebd6349b7923e16980d2f04c5c48f7f85e56853b11f78e21900b9d9dfdba973b87c1db5c860a4c890292c4aa4760cf5aa9972a1db9ebae714c93e29af2d9b3ecea7e9777e6d4fb2550f3f952666686cad6282e0dee72b88d1b68bb1ac9021d89dac8a56a01c0c2138fd71883c7654f30117019dc70c85fe42cb57c23a2a37060402a37f8fae690abd43221fdcc23d992150de4ab217d35aa5752c3bdf2fa3fdca3202f7b0edfa83d6a0938a3e2349c51d6ce1680654c38c8d6bf2659c1885f8ead0bd687cf56144f1fa6f32e90e08f059bcf34e3493f42a85814c24cd68103230430567a960618dc99cda88cadf09e854acd79a2a54dd70dcaa5510e0cc3e4bd32b86bba8f8cef4e08867fea37a14d3412ab5f2c36c61e6e96eae2a00ae94dd5f27d7a914fcc2eb6f88b8a73fb0ecdbef7a4e2d15b7e9263a37880d242f8c230afafda5a7e919260b6e14a8d65381d73878858b0001a581e7add55c06ce1d8e30caf6802b33805e2b78d4b8eeeb20c747f7cef3a27cf17e3c1be070e8fa1adf20ddadf2e46e53d8702d75c637c2e9d9b244e12faa41f1ecabc5d98979dbaf2f0a00d061f1bbd0231c94fa5ca97a75b93a48bb3d2babc9cb0a589df0f8cc72265971e49172b588490752854f599ea4a97e71b0a6d415d058dcc875ef3f09c37fa7e4c0f45045a7bfea8fc0bd9e0c1eb36a0d3e7e03240baed7cb5d3e6aa8ceda0a0b394584bde43190bbd0ec6ea5fb3973799db1f0fc11232c3e588ca4aadaf4f7141831468183a3aed6fa4caceced00000000000000000000000000000000000000000000000000030a0f1219242e32""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -89ad3b5244d66fc84f3dbb02bb51be6fa25bd2ea3deb3bb6d964448351d9821f8b1bb2aac85f6bdd7573795e228fc04b4b30dc6940c3d6fcdd803035a8d61344515b7983ecbafa0c23e961ebcce057ba857d058576d0cd929d9e5538c5b3818c2a697677ca30faa37b887f0309a8f59ebbf7f34b471abc65f533955172ee610971f85662ce59db9b4c7e49e75c5b03239533094362b94d5d399ae4b7f94d0cdfa51e0bd6d720eb3468c177273c3c0afb7569ca5514849053e433464a6136b160b35ff19406613e31e7c3b8265b585792a8e69d53a83498b089da59798b54d62cb669ac1c917f77901392fa1d667545e3103902104103c2ef080025978041f324196cfa0de5d9f4e2929b6a9a67057fa479c9484ce55165c9d0a60265b2ecc69430e3081b1dadc91056c8ea701e2ea48495153c86ee3b317ba127aaebd85349b94cd8fb60e28a4fd027ff1d96da4bd2b8fd1c0ded721f61168dc73823e9b68b8f6dfd3b27769e3f737be70a19c20b5dd06f91c5172eac3077c2273aca458315bceb77f3d2e84e4ef8ab66e26f8194b8fe666e66d34bb779406f1f60245e4014d4aa8b6d265c9ac85df71709d9d09cf9278d1ff37765698879fc3fef617139998f37630fb51e76b47dff86c367e270905643032387bc4fba84a63c539ceee7247b68e95a5c513c43b8b35e2f1228ff1c06478dee9461eec9763a227f9bc90db9c20796dd98c5d178de643df332e229daa52a1bfc0f445e2aa8ea64f233aced5d7197a32dd2954eb8ef28e8ede22aad2edcd334ea41995355eed254bbaa46af4c00c33862ce3c3f88bb2e60f6b1b9997769c91e4aa6e16aaba35688751054abe29545527b761e7b84a25a7c932706a772918994b446e531e75c94a00c1e4d5b2fca578664ad492517d149d656de717c834d6ed62bec4b78a6a7290497c0f6fca54de83cb42cf8480f67e83d0226f5b6f99562a024962920e75d4c6f766a6de0d16f7965d0b68b322743ef29f84dd1f374eb4e2be7b6deed0ec99c778994e2b267edb1b198e49a27d54306a484084d9906425be4232edfb9477651660876dd3b234c16f30496dde0704004c7474ea045ddde3ab0a13f62fc5367a4be561e1ff50a4d035e6360dab880429471ee57ad84898732d9f8f93763624ab53d8ce7e7d03029749ea625d424da59d22c593302cced4b7da41e9727cb9ee5d4a5ff5c7e6e4a2ec98520553d90afc6d0928201576210ed2dea2ace73dd5c072ece53068bbffe6a0ac44767df1433b4353540595f28d0238509f52b4588be42d9eccf8d3480199945e2d83dd64e279e25849e22bd4216af75045c5bc5ace43f3a5045bc15e7b6a8e099a709afa8c86bbb5c153d6d5cc522c115b56dc6eab85f76dddc857369c3355c15d9cdea649208c7a7579380fee044d98f8f1f6b108589a89877ca10d5bf94bda70d5d218efea9a24b9b6a6e724a056343099c04b2a13477d6d87c16817ffbceb55ba0046d1840e1f9d1e316fe35c6f06b4cec777013960a87712e3f33bfdfcca8c214bdb9a646d2eaca0f8ceedbc230d888de849c37035b550f17a927129fc04d4a51508a36ea478127b87e04116076e215aba3a925facb757bb5947c09e1cee47b4987983e1bbff5bba5432178dcb18b4f58c4aea40732ded1ee98858b936998fa5e7539a81b8fa94a852b44d824c3607856f1de4f8bc179673e0370cdb4f57f9c1a958174dced4f50c1f7eee29f8cea9518b48986e0f8867d96b0b497fb83a7feea379ef9fad3792c60d3f0e08fd70f09065396c9e2b1dc3072bdcd85ca66a5e541ce76426a56ba840a1a14f080dd3efedd7b4c1aa80aaab9c51a8878b7d7ba79122fa3356cd59fc8e616587e3214bd925808b5a7ce4dda34f42c76aa8d2916d5605c1d265f9abc7228b680aef5ae5e71b2281cc3765ba98ca9771dc2f0992263622232ae9aea0c790ffbb765028f17409a2e19a9d3ad5bff30c1e82bcb584245183d70cca5b2707384ae504f3ca475d2daedd1feb8ab8bde4e25f25326fe9e2f69557394010d346b025ad480306d46b259329a84d6b9477910529f6ebb7a92c9a196f495700729d71ab94890f1ca2d4a34128d1807bd2987df2b37cd490e7ebc91167b9dbcc34fd896089b748c63d6b6b4c8cc156b3e554f326eb08ac7170894b2eee348c9478f1f2ba488a1c3ce8ff7aa19a31474a8054de2b1b14bee71fe4abb259fac2da5e7e4a43f5b70948d44d03d3be1514da9ee932b4e4415f5f70de11f5ed3f437d2d0885cb7e4131c97760ddf5014b137e25869daaf0302dc26dce0b557187d418799392490c75dfb0d40469eff1b83ccb0dcd48ef1175e9c035b29b5f6c93ac5fe41b2cc2fc2d7cb8912f6a1f79d38ae7fba2600ea9a91be79dee4550fb613a8e29cd90e575cd55b54a3375a10bfe6de49d33f0d1a3f70a9526330c97e191a133a07d49ee12d9fe18c7c1c1ba5b6a74ba57c794e296e95ee063d615d77048e919977011087c419118deab38d7df9f7e79ecf51e45318df85820e2bb7c2d69a11c17d31ed1e86df304a4845bc8cee05d36f59d610a20bdf9b16e428fc267f585faa573b779bbd6e540b3e32ad3d9cd1c24a818ee83de5a91008e33e0a46a511c26a88fc61399efa2fdae38f75d1634fd57f9849c5a361b94f8b97c04cac9c0f7109bcb638775238711867f7b32b852feb3ee5653b0cce063415c9fe9dd7f8add3e4f996db03ba5f37a1cb344693ea95e35357772c68d090feaa3d2c61f4156bc530178b70e4b9a8e75aa1c3738a2219d3fdb5dcfaf5d9d77b541c944eca7c9af42a358222ae334ff5fa5f5eec2367040414d01b4c6876b79a78c006afb5a357a78b96ec3d502de789828b04eeae19cfc5fbfc01441da3e86934c4fe38804751e2d3b47d16c5a9a246ac5731186e97c9671eda1fd0f68ae37c00065b8c4092640153d30023a3298acee9550ada9aa5315c46fa879efa35280074f80b3a689f41a3408881f8b9c42eab59dddb4358776dea5d7a553545ac5a6a9de2ec05f70e29d81627eaf1d3e23eb019f1921752779b71c2a8f24fbeb800a12556cb12cbf7b426d3aea37a32b2782894cc23b5fad1f1dbdadd1adcf9df42afa30a2e2829b12f6050156d6c5c39dbabc32a02dc4383e889b0edd16c3061f730679a7bd95c07b197076675422e480d642c7b1d1865a7c472b30c50cadbf222374ff392d5a9f72dd8441ca3f3d688366e7f918142bc00e5045cbfa5df33abafa9f22a205bbcb1f3009b903480c5a72f804afc37808a29fc5a732fa606cb4b9745dde61e50faf8cace5b203b3c24828aab5140458cb4acd31d4795726dcbe47e27a48705062994584a7f51c3ef1d2e3e64d1149da353fea5ac3fdf544b5faf728e675c77341d0c6ab0dfde580a0cfa07ac93f4280357886c072b2afcae3c0c678c9003ddd1a0d2d9b9a04e93789cbeee7a13a58981c77e6f8b6190895d629606bc1c0f38b2ba1b1507c1a7a02d195c4ca2ecea6de3f793eed2541fcb96cc2ef03f82ce4b23ff0b5536d64c178dd6d24203409f85c8707a319cacc11ede0fd14344f7348908ba8f9179fef6c7ccb52f81c5ac8621467ab977d59ca0ad4bcaf38d36fb2776e4ca7e2c082297905d4fd95a7dff36857b3a4d45025eba22f3a893c748"""), - TestUtils.hexDecode(""" -701B8AE25CD8187095349A4D41A067D4FD48732E62547E491D38845B3507A7A6AD8F8AFC53D139E47FC5AF2723B1BB057FC797519AC93CFB18DEB496BD9735455CBDFFFCA5E69C95990EF89F509728D1CE41F36A4C0364AC8C30E3EF67D3F3776400BF4C838A477231E455FF76C92CFCCE1B69B00F99451B0A8287ED59CD79EF0D6E697C93F7ED38F20204921E6E2F141D3DBDE1C201E5CE7C524370C339753676746DA5DE4A398CFC2CB1F568C16D4DF34A27CF04F0637B1447C6CC83E965A3F86C538CBC235E440CC2D1257CF916421EC75928DD6DA3CA002AC93C8F464ECD522EEF7E048C154D73053DA7BB63A5DD845512D2B6B7D1E7EB5818D170D14A4A698C8922D69A98319A10E0AF558E2318FC390ED990B75ADB50C6199DBEAF5D53B49235DE7CA116932EA38A109322AD05F5D681CE25FFDC9F6A05C4ED2EC6D4242173D2039318EF7D0733D86D57C4E114B3476392D47FC68796C9F66B1F1EC70610E1D57436614D5969564DEB8673686170E40BF5CDE506F7E70964E07258D4551F5EE0BF2651F8BF3D3177DA76AE90FAAA69C4F373E664F0A1FCC62F208A8BE130C499166D13CB34D77FDB32D5A7F3AD38856BFD3A0419B8744DD2F186D03E18634D826A5BC87F1566FEF88D9ED93E74ED4C005EA3EE2EB22FF5DEED283132D00C7A0B131BE1FA38E30EEC68B748AD533BFB23B9A14A936F609D4C560163235367B0D64C2C796F1106A1A9365E8F507B4BE0514C849A81E2C7388C8AF300D98D444BF808C4F9338C47A853222D5AA8ED283F57DBF0689E5FB89A456005B6B95AC3D791077C79BAA2BB42B423F93A7D0D999241AC5B9D64D65274817F9BEFCEFBCB4D5CAA67427F69ECB279553EF0D33A19E14FD4B284A72081F949FBE2A7543497F314CD7496EEE866F33102BEE5CF9C706426EF2365EFDF1AD141552BE65D1DB4373B0E8D449F3FD1733AA164C1F2C24F74E240C5096CD201A11113D6BF5CA19595C4B0A81E1153A4EBF88F38F1812BE517158787F2B378E8E32C9F97432BC9027292E5EDD7DA64FC6A32788154B62E40A85701895E13287BB18883820DBDD7647AE4EE1FC1D43C199EE69B1A2E2A7067AFAC541A8F44E660B2A7C114F402E2054DA7ACC41DDDEDFD7291CD4573DA22739C7785EFC2240B27A90BFCAFD1AFAB6C2B0EF5509D0DDF349C173E9A6C906BAF5692C39F6E0D1442F84AD2FC118A14B12C3AD5DF8A79056017F4FDD76603717B080E3AE560D7A601EE7FCAA36DF7289AEEA59EDD0B73BE91782377150F03C2C2ED40F33A250356CA17E153480A7E848F090DDA29C65FBBFB495FE9B7A2BEE342C7D422F28631A8C9CF643DC76F07F162DA1AD3F24589971032796BCDCD262F55A8C34FFCE05FA9DC001FB35D6FEE75B42DB6DDD2138C0517D003512F0EA8E982C2ADB5E5BC1F19B8ECE67E4AA1681383A97976B6A8F2025EA80B1BFA1796C27F6A54C583711E2EA46D85C515EAAD22ECFD68C5D02853D688302704EAC4863DB1FC69F8C35411EC6F4A9F0A7E7B3385ACF6DF805447BFE863181A945E8E7944770340496F5A19CB7DBD0D9010B7EEA3C585926408FD40F245D852DD208EA97CDAB0C16C1EF80B3E5BE77D953A04C1B6F53A23080B54F439705E417B9874B3FB524794D26DE3DDE88E9DB9FC36B1508754EB51D389FCC46F822F50FCE199DC14E4B4468B8B15A2460EAD05D0C47668C05A2315748897AF99D320E70F2AEB96936D7D739F72ABAA6960DA6A3996988F6A3F7AE7772D49915753B936367E022179E69B6853E1A83B429B42BE19EE03520A5666124B657D2FD6D15447AEEE45AB1FF4593DE9A2E6D152C64DF45C1F62AB9B67257B2A2115D224850A3AB2FA028F8F9FDE7C9A9FBA2FD291346037A1B4E00B0642B07ED54BFD70F3DCA3D1B8628627859611006DB2DD17A351751F85C60028DCF21481291526B1DEEA4C7CD2D3230653E6FEA1DDBDFE1BC3DA93FBFCDC5A405975A5DC68DA0D8338EFBD6CCDA1F2374D72FBE007599E81CF7D5C37985EA09C561A1EC40A70784FC606FB7C3FCD981F112C599C78B15B7739AF4DE129D489336BFD3966C10363A60E749162D1D8311C5E850B22910B999080DFC86D1787C35768CD5470E9F7A51D4EEBA71241DB57021D6569ED2BF201C06E235D6621B292B686D23E29DA4E81C873371593CB07B3DE46E91FAA3D4A2AA6F62FBF6BBF1954647E731AF4B99EEB3C0FA6385699F8EF2D8E1D7F75161129A1C7F8C7C68B906EAB8DAE8BBB3541FBC65F36BB67ECF19EBEF54BFC2EC4E1130A2E4F36B5644A73CB0E244738B6E5788A4B4457291B57F1FDAD2C11FE5C7DCFD4E742A0AECC460BB660D7BFDDEE4CEA074958AB94B6FA4CCEFE02FC7001D3A2CD013684A1ECC2E2F6D90D246726EFFFA99C12D1FE4AD10A6BE38D70AE3DE5C4843FE6CCEEF587191B56F666C1662F5C6FB03955C557E1B4CE247A2806DE39EC40CF8B97835EB0E3F2D829E0FEA02FE60C934FE72A25930FD6692B9ED979F14536F406F04C3CF0BE98647A5967B81DFAC353A2F8236FE147BFD7D3731C49476C3191981C9AF239AE8C72570C6C53E7AADD48E721E623D6CF11A1E386EA7C30F070E7AC4F63FB42AB74881BFA3FF3E8A35EBEF04D39B853DDE0FB17DD9DAE37A76C96FF55F64669CD9521DA3900B7CB297E813521239D87703CA395CDC8D8CC4EC21CB10A1C672493E013EAC0298F8076C8E0B56AFDF9C31EA01CBC1BDA4AE17FE103C9812E940A34EB321BE7BB288CF8BE7017AA58AD528C9DE09E269B10C6FBFBA5E8B6883FE7E08A0D184F8561FE3F43582CA045DC25CABA52C0157495410382A048BA67D051EA115D867D780CDE5EF512BCDD14489C43604F86D929F83D118B905C63BFF451FF3540E9E220851A402BEA0DB1A7CD94DE0407AEB9CF862BFA3FA703924D0A4803C463AAA827A04B0F09556054F27DB98E22A96D07F81662E0E910836B9423968C3F002E605BB688720FA7CF3167140BC21398B5E4968804F3C3065FAF125BB6D887C869FE3FCC27D88E048FFD0925E748C096C74BFB1E54A8FF6E2C838F16769FA4D8564E5CCC58DAE3B102EA300361EF89EEC689FB5BB0DE16C5CA98A60B8990EEC0006A147036871FC2A6ACFC6A6EC907D28E18A76560A5436BBF9353789C8A5DFE559FCD68C117066EEE5B00F349D6591E104295E78F445FCDD3D6883DF50D1DA6A04541C7E8171523FF36A9C072164147D14985BA30FD449667B580D73B06A5971B720A8B1D2A6896FDC5E4D4DAC78353ADC3449AA53919AAD15EF250AE12E9E40B8487F66AEF0B15E42BF34AA816F559062EEA24EBB01BA369747B29404DC1F1108DEAD021898298E72F4BC1DD821E4C88329D6F03F971F554A87FEC87F34430ECD1CCC6627D8CA49EEE1D5DA6704CE960021C847DAEC2DD544D4EAD2E2086058CF131296B7F4FA4B71A1DC6D6C642A256AE0C0EF9D1211EFA3845B12243BFBCB4F423E913A2976C1015569ECCBC159AFE70F1EDDC3AFAAFDA45CC02EB60BA0DB9EA83EC604113479BE848F381FC63C63B3111DC5179A637E0832A26EA32555908D79B308351CB104C43668371DB32056BB63540B9C3E5551A063D2B525F8A016BBACEB402CE7D7072CB9F37CEC13E1EAF7D867534C013D78B9DFE01C13DDCEC7A3444AFF9E182F12B6901CD9A70F21908FE692E4C0536B069C89685BFA9D973983AA8C1DA461D18ABD27A6A717D9F2122BEAA9BB1742622F51FF616FA2EC3A6D4724A3A9215D7B29A1BA372282CCF60DE90B3834FADE6E3743AD6B2F9B7344F45A29740DD7DB2D642F94998579A5DCCD2EFCD2F7D08486BB327B844EB19ACE3B4FB0D85F8A24FACBF318C98199A0B2C7FC2CCA59AE84A522890E22C2A7207CE91623362C7DD8E9F946817C75B71FB9654E2B7F2E83E46E75ED5638741E414D7F8E70914315F0E37B5B4E3E1CFA8288B1724113E4A00B59B7764C2D61443537849E77083FD13BA652001F39DD9BD4B20AB77CB945C5EBE686A0627ECC52F38A852BC9E1AC8D303E3B96D9D086920A19E5088054DECA635E802385600F673D3BD0A5CBE7A5B9BA8B1C4B73B9246C1A1C1071E5F98ED42041037FAB67184C89BF4FFE3CA0AE2A9BCB020F390F0B76DE2B8AADBC99268D3A1D467A024184CC9A455A8F2FF287A4C9DD1B0C86C8E176BB15B12023B291D44E7FF0C44577F7A6D788D82A75C68C9F5BBE504E7D64FD2AD18BE209E85C45627FC045BC81E3531A2B886173F3C3029D1FA98C792501A4942C72A7A892232F390CCBFD7863AC38D837755011F919AD8934742D0795523E6D48A958BACB9A9F7B9A5A9D914C37114CB111CB536EED3D753D6333219EC993AA5D39BF74E8E9FA02D8BEFF369EDAEC67A5CBD128FC9BA6F82E31A4C59D783A99912C7C389EC708824AC7FF05D56BA6D228C0A9D96324C6D9725E3BE17C44CAC7C4D49235BD15384F95345DC36519466A13110A58300F7E3362295DD7069DC6A88B542F2BC5C9F33328D9D8D1683902C025427F32FD562BE3F0680FA05851296E15C5FC67E96BAC924407AE6BE37E9B61D9A6383FFBDC6E77CC0887726C474AD735BC50039AEC665D827B0F6BCDF7EC87EA6BF793386F2A65C997545FB93F0D53737C53D00685DDC13960AF2632380F105840A1699ABE53999C568978ADAFBE21913193DD0844D89BD582418BF8B6BC430FF1FF7750AE8507495C14DF21A3437AFCA7DCEE7B1F1247C802081FC5ACE5B125AB2BF11ABAC97E201EEC2A8C90ADED920728EE77E1FE2BF31A222A1CA5263586A16FCF80E582258654D0793B1551EA3C24C4EBD27C52956ABCE6ACD05FC2F088273FEE8ADA0256F30B5ADA8768D8E9B70279DF95AE5CC68FFA99934C7520E12F57D213FF18ECA6046A9A3F32E280044023220140E2485A3B3EF7778006B18D4A9DCD177D190CD903CAC1EE0897F58762299A0E026B8EEC6F4F3D0BE1F070C648A2D73869F22DDA21246CCFDEB7A9784AE967F0DD0A2011C637099AF33E0D608AA0A5B2103060CA1A6718328D451368EA3049FF60FB66FE54E778DABC48413966EA14E22083A884E8C8EC33F885093F01B5E34477745A9F82C645C8C5498306AB00B78684252ECD74C163BB8AF9B49AA03E244F4EFC4A2E7099074F512D465C84773DBD1FA96D26053230C192DB289A1596E60B96178DD8CDD72FF14B340FB5830696B393CA319649BA56DCD517F5A08A528350E2D9531B3AC187414FA6E06C0F05D9987BB2FC98F7C8D4F922B8AA45287FA83B900ECB6C9F02669063296F1EA389858F6D2E10228E136FAE35F21DA151EA7AAEC593E5948536B68BE58ABC57771AEB406A0C3F931E7DCF85A350A3558E5C1B1F70E6299EC9FF8B9CC13E905D9902FED957ABFD7D09FB84FF22BF8410D387BA85D8555A75F432EC5789498EA36CF235276176ED48D1E374DB5C2DD1A64714D64FD20D4FDE2A605034E4DF607EC6E11D0465DB25B9D79C83182384D64477C126E9B8558489F69AF29730B4D5650B9860326249777DFE9EA5669736692D0780E9BA346C1727138F5DDD4914487CF32A4E9CB1DDD5617B6B45CF8C981944684BBB7921C88F5A25120047BAF2D9346E220EA08AD168B30A1B82B3B63C4913C708C02258B6AEF1CAC96E2A90EF7D0E1EFC0BC5BBE05D286E143FC0CA4A23833CA12727F0F83079F7BA80D809D6C739EC4D0DD9CF75C4FE30B12A892096BC4B9167F16819694B2CD5DB4B80DE8DE988AD50677695C4FB3E0940913C250645333B6F55E36F649A43C3A39ECAA3DE3EC1FD4F9F65D9F7AAF75B60DCA3BD1EC06495FF5F1D4FD6D83CC6316E40BC469EE5F44E5AE56ADB229A7CA5CA37A1508531E44B0142B4330048350A40FC82279D25A87E043240B4BFA7321340502F0D37073DF068596C4753F8709BAA2A7264ADBCF5F934E857B3225CA47D8A182B80D3DF24C3612FE4931EED565BE563115414CC2B6BD102DC6BCA9F104CEC8B24BA5465FEBB7E9730C928D6FC1144224232A990F8BED27FE6D28AA35A91F90D6A0AFE9A7E37A5BAE51D8AFDEBB7D5670F2521095A56862354D2AD946663B4BBC7049ED1884347734BF3E78ED227428476F1070F4DB011F8DC86EDC5BAE1BEDC9C5D253E4C5C6816347EC96C5F62AA3298588625304118EC32DB2DE0597BF2056046E17C69EAECFD26475066AC54D40A673741BCE72F138DD98F1939598E5D94D565C1337D1179DA057D4453DEE27B5C04777EA710D77B317A6E8DD3B4F26A6A9B3F4917A0E881E5EE528462508DEC6762DE2BC3F8F8C42E8D721BFEF7583C99DFA4D1CB49DE2A303B67AFD505F8A3865D853BF19C4A0F7CFA92F5CB18CD5D8E378A5B041449EC9ECFB80E0865CEC1734D34BC44E664243AA8F605366CE9F849700593C76BE0CB19CA1255B074A8630FC962B50106CD93DB41C6E4DF53B6B1257872B0D8CE9AD5F245C3027A3F75F19DC568ED1E0F60CC20DE625241D300DCDC8C953676363868B680B471C2EE623DA408C7E030833DBAAEE8E701374156A6B785E0EC7D1A0A55A599605BCA0FB517EF99939889C862CD790240709BEE0226DC7E8177F641C747A151A89340A6CCFF6982EF39683325390DE72E4451BBA74E3CB102870F1E9ACED30BDBBEF160A49746A23C432C3ED7EEF580969110AA438D00AA03F54E039195D61B7840222AC994784EEEA538B7E830A6508AA0B460DA4B4C0DD9CB052CE6254774FB147F7E4F80214AF1FAE59F8ADA6509123438E90AC13FF7CE71AAEAEF7A39C434C3824D49B894C389CF320A430A7F84A5F4972FF98C388D61C936E453BB1A340528A9FA5F0B0DA9543275435E91B0F5560E95F9AE4EFCDECDE1584761F8F60F0280ABF40FC5834BFE456EF66AF66ECA1098DD49BA2CC4B12CA9CFE256FBEEC328D049BD6BD19E2358502672F029888DC3AF3350BC2EDF5C4E07D59DF8DB9C14B86F1FE384227953E98978997902C8F237C8BDF300A72248B3DDEFD52577BCC0F99F75B92BC056719243F7EE67932A2DECFB15B59C95B43E183BA3DAA41B97E177D03CA320A5FD5D7E5A88C4D54A8467B883E0CD5924912642A65F191DD4DC2B08DD28EC0AD2B1CDB86EEA3DBBF6D47754B1BF7036A0BE90CC3775D263A5BC688844BBB9B1D9296804176E17C55D6DB888C2BEDA3D546FC496EAC5243AB5D51686AF9B29BF6D4A138BECD49665458B816BB09848CC4318136E6B170BECA544E8ADC35D40DED979111B8B1D4577DE2FADE6A1D97F9E82E9D3F069F3287E559E99224C6494F36233453036DBA617088D619395518B4E6725125850B3121EA957E721244DF53FB343483D27E6C3A53224B38C11C1D64CBFCD7041A44836AA606D170A80E84BBC0973556B9E4B1BD776C6A0876D727BB0526809700A0EB318BED67843CE4A6BE2BC10FE9D8228A4C94D7A506760E580E8A0E544ECCB07DD0810D79443046951C72E017CEE5B2C959754D477D706C3E043298CAD200189F4390F59BA27B0099DC551673B5138AA654E054676BF30DC61CAFF444CA22EB32E5952A598C07AAAEDDB83B8B3789EEF97663ECBD33FE356DE981A24C29DD5217E14DFCA30C0109419D8765A061F747BFFC1E221D3ACC7FE239375A9548483543599C837F48EA189880278AB2E06EA44417EB945F20ACB464CC458E249A8969273A460F063C5FAA907E42C9EE304B27C85BF41FB170708969A2BFDEF37B97DB4A16BBFE07370039369D04D0A9155623AA390ABB75D47FE2394E4606759648954FECDF4554F660D3176AF33153A9D7B0A935753B11E6C7295B0FF5680A18A42ACE577981C500581F741CA23DFDDBF22EB6511E19C016EDC96DA545AD16D5EFB9A8F10C45D78E01C74E3552FFAF35CFA1BC0C3DF9D14C1BDA9D510FC7C7A755C71B5273CD7CAF3AF44AF066DCF18B1B7D6C0D546C9C0B0B1BBE88F512824CB8B512438ACBB23CAE1178DA05DD67DA6392649213805D680AA61D26092BC1B2CE50CECEB7541D7F10808DB2D4A6B12841C8B4B6C5519C8683C998A74AC3BC3CC44D81B606A9A3174929E4AF06E032A24E67E9C66885004F07D4775A6C66A8F42F94920749FF902A8F1C3BC5A1A35BFA24040EF3B7ECD05654CAB696D3323485EF855361DB57A65C5AA0B238DC551ABD6B4A8DA0EB987A82F56E5EF05CEBCB4155181BBC61C645B2A4FA8B316FC6C5B3BA12829E74899D0A42B42821094B57E6D221FFA108D5D0EDE9012A88A2BC361D90673BB3D19D6355B9239131B42FB3CE832DEEA6E4551BF6C6533CD8DE572ED3E5DC51BC1ADA13C0C7E4F723CB964125DA08E0D08F1CFAE124568DE55E2B39B1475DC8F6558ED763FD7EC2DE373F4C54399A0317087630AED2A64BF13D113E8AC32E6318EB7BC0DE20E846C0CACD876F47CBF79DB6FCDFAB75B371156CF74B443E8DACBEAF94203037BA14E821A66244BBB7E989567D176FED12AD0BACF79834D067662C11422631554D1ACD6BCCBE23BF1D0C042C1CACA4B9BD01D6C5757E52877FB5DFC92161C8BB15A60222D12CEEE973812B4920B38547304E720AE246FB503C9F97BBA79640485624DFA2F4D508300BB80C70CF8E271770876062AA1EE0F548F6F7D95CFAA17FF1FAD847CBF6CF90B01D29C33B43473379F4B5491532432F6CAB98C365B84D357B48B416C2A00B25D07594ED4E4CA0E1BA5C92AA2F1DC7A6109AE8D71B9F06440A770FDC2501900B9EE466DDD853CA5482B4636BFD58AD8B24D91852ABAA0A37536D4118A122951DC78F02DDA8EC8029ED938125D759B24C90B0FEBA1F589AA1C10FC9597CB7E703D93AC4AFA43D3C239337AA454BCC471CC6BECF89266F588C3EA71AE50F146097D9CCF21E75790A5F3A252977E4D848DCF5D96DDD4FC1D0CB583A28AF9D7648BDAF8F1E94A83CF5349B1F4AF63AB1C66757B75C58D10F27F8619A5A6BADA67E841B6429AB40A09451313EED76B93166B3A5D5561CFB6421D83A5E343C8D277389950328A1646C3DAED357BCF2E8615695D7E8922030148844058D177D4E68A8EE31D5D810C73D9B38F6863083A8266652DB82A43615A45E6D14EFDF00A4333404DB65194EB432187C1EA7C48F819C34E48EBCB0836C84534A238C42E0B9BADFBB15B220DD0BF40F8C0511BA69EF82FA57D099BA84EE4AB6FC422442C3BE1E8DD910B4117BF4047D49419FCD2380966F665001FE4793F06F272E14E1893D502BD3343AFF5EE94A58CEE04E745E72E51124AE8013EAF2C2141012FAC54CD25E97B6FD3F0891BA1DE663EBF009A7008222F461B4E7D50628133DCCBA7CD0AE44BFE9F675E094D972D896551A1205FFE0CA8FCB739192488D2BDDD4E10493B43C7EFEF60888CB11ED68F34630623206E81ED04D300C2C43B6F27E41F18241651FC6B84C19EE1EB018BFD7A0D4483B0B6DCF57236AB27BF4CA17E52739E4D1C508C78F6B6E9FD53F423AFFAB01F75A9B1AB725C247492DAE3227ECEE2D60EB186BD8972FE455C393919E6D9760AD1BB706138824FC3C9EA0F673C1323366DEAFD260591DAE60AEA2DC22FFE5EA2421F35920550C0FBD78C4F6469092F89FB6908457BC81A175D75B1F97E2750194E68705B9D1E9F762068EE2FA9286BCCD3ABE98007AD1AB27AD2A094C6E164C5BBF88CD4C5F325E4E91FE2867A94E9FE1A78DAE2ED1C11CB4D365EC2F3888612FF58B493268645BE9ED69C196857F8C995A42D5CF4542E609BB35B0BB1B4BB85295ADE635E8FA237C5DF471B8CAD7E98420077BF1DBF6DCDCC1322C8BE1B8DD5E228B6E6E04ADA1D533B0C6221FA83BE7C19273F9AADADE041CEAE389D0572D2317906005BFAA17940026CCBAFAF8C7A4BBFCE30EDBF4EF82902E181B41A1FC006AC01BE64CF6E4A4A14FED995D6F323405242BCC5797E43276ADFBA44EB8E3EEC029292D2DCDC8E6C93AA6C02766308CD367D3"""), - TestUtils.hexDecode(""" -16c069f82e6f6efe9eb825ae1b6e908e32c28e3b0ffc443e9472356bb19fe58378012592c1afc414e0ff970a13a9b8cb51b968a7ba9a2f7d0c326b5e1d074f5af742c2b548f87b8cf1baf45f86000801486773a4240372f8f1c05e0e9ceb1bf5f18556c62765cd06c472781f73f6c766b44c2f94e436eaedf8612cd1fe381e645689cb6e7befaf031823029f5a6d8913e2245fec9159995956825ee81fd66ecac65d960506f2b3f58aa4e9a6606bae585205b351c5654b9ff455b08aa9ac45ad3b20e7619a3383913defcc42c0d25acb6aa2f3d4e17e4febb6dcb59c31e853fc5db50770059aa70d8d3c58d3b98efea00f9756260d843cfda0c079fbbd4933ff8512ea6e379b7b1b92ed4146cd0135b2c8ac61496cc70b55de5eff005a310eaf50ea88666e342850ec6c22d2d5cfdeaeea40321c8278e341b8422bafdfe71b42cd3483d71df4c1ac8bb0c86a72480055d272dff99203919fc2a7836adc985befb8025e6e491957159183949343d316004c075332466101f14aa78296cba1072799d978c1b36e94f042eec38b989e0c7e40db362fbccdbdb56236397435b65b12cce3f13bf55abc805973dde8f9c65157c3a3751209afd01396ebd7bb20fc16229ab289848c1aa48f5bf86791468df8950ebb317d72c050270f275cc219faad9980c69c377679c4e137810813734726ec78ce545199e43552ed33ab3689b6ac18fc54fe847af97fff3e2d6fd2bd6885fb675278c4d897b507d37b5cd1eb291d6195c03b5beaecfd90244a497c69345f70a118f88ed8568386b1af2bd23c9d0f2763c19b669a7378c42942a242c3721c59a5c0390137077ab10d792e2670da72dcae6042778d691ed96dbe126c2ac03e6f5a71eb1cc363997ce106c6111e3ddf50da12a23447af30d684548536c2402b60b75805cd0a8ff2ce7b4d7863a0baffd5c0b98df8dbe6fecdc37b2c882027f0d5b78ba3bc35a352d419978bee8f39faf096d31196590c415044500140e8ca976340496f084eef29a1a1fdd8df215da732f37e140aa48aaa393e5d3af9b266f98f5ed1410c9b4c88936f1e2b225a6e1c99ee9ddb7aab09b55be15aff94d2f43a8ba09d673b5d1327ea95f42fd26b4e13cd02a6a26c0d20fca8dbea95e71a9d9b6ce80fce8c7c0cf0ccea591916e4b9eceb3b42645615a40fd063d1e0c7753211ffca88a67b3029d6f7e387b11ca34d5357df38f5d92042b2f9a7d8d27ef6c8ebbce9377568cdbdb146d2e15858cd7133b5cf242406a857e4247462d87994959ab3b350cbdbe521f81b9375ee660b53eb534195a7cb0751c54f3af3ba72ef2cb3aa6c748270a64b17685d046641c20156575846e42b93fb1c754140ed6a6a02df039cffd970c21349e2bbcb6323815f1849d38052e6bb143d11890518da4a213434b820c79994586638b70d6c006acd43e43a79821478bba9ec09f9442fb15308d01f533c460b70a28c710da2b3f4ac7449129081081c4c87a241ab2f9483add71974846a3f32c3c96a08ad090098f38021fdfeaf50a36261c728aa6395b2114a88cf9577793cc7bfe45a7e238b997bd35b2ffb0c3992f188de916f7c004c5f83da5aac274a47bb7348df3590668efe9c2503b2c316dc074262fe874ea700b93a9d2545ad3e22b395d294bca1a2b5615d259744c56cd3d736be2c4624a1302cd31ef33f75373d2bf8b22a9e85db1df34ea4d24f0593cf9d494ede243517e2618dd0a6bbd0ff46987995805ccc3439e39babab22a53893223e25eff5276ff7a5eaffb88fdd248f3b2a4936ae56bfac6d778126930b25f05bbf031fb0574aaa129e4614eb1a38171e9d19b7fa0ca5fe7b4860ae3447bf2de8a89b8d0e85c7e130bdeb0f40e6326b1167f744e2b664e370f8a9d31f662364f442f1cda1da1f9437ae6255367e242253a325de08f6a12774612997a2f8b2a6a6e084ba51a07947ee7f4eb68545594756582be6232224172439c1105f46da151fcf9ca328497f952151b38631f4797f6d6ba367ee502dac0b1c5f45137578a5fa947e311cc84b73c56f058a1265ca45c10423aa165f08c53bbbc7ea42309297f7f37a98d146c48a7cbb566e005b76ec243ce6f7b9231428cfc17eb4b1e0b8d3002628e3ed7bda600a5840d4c1b2fd97024bf2f9ed637b521e8e1645400a7037ce6db2bb696b604d6b5f4b40a9e4eb443517c00a5ac6c1859dd18b6fb772155f2d8be3099b638602bdb9e3941d31bbbba3cc52d7060f7b45416c9923ee3697caf14e7f51361051bcd540cda6a14a71cb62e033603bc9d58ecb39ade2144b13d1746f0de2d1742cb6b34d91917adb69634084e08b9b37dd2c62f55eb64ca81a60ab5b71bcafe2c42f9c8d9ce59e6be9c2f0019c3d96c6ab738cc9df2976f0b9c47579fcc2d72161317c541d5f7de0bdc19b6f7d3264db1079cf3deb1619fb6531aa0032b19d2cb2ccef9fd6c1149c12b701cf8387768c6eb004fa6bb876f7ec010abfcf631caa27cf36d30c1738d50e868214ff8989ad497d0b12ed2ae83be1772a531610e4698bd721630dc427f07bf6b4356d720f335ea66969d14b246b757ddd96d1607dcc72d9d36fb10f9a529056255b9f962ba7a02950a0b9c988fd381d801af73d7d9abdd842cac56a77c5e2a9ab91785ad17966a2fc31e42a663ac583488081c236d13b82b09933afc57e25847f8511b0cfcf472ca6b21898ae47ca8fe674a55f8737053ddcf963dce0568839660b47f2dfc9eaced787aab897d16cf1a1e969f4e5fff7a8ec5c3ca33b6047fccd8d32f4c3a61d2c69075e37640d9120330cdb9732ea9325e4fab3e94ed580fc5be75acfb14468fd12f6e4cf87a7ac340f990e33ee4e1d2cc48a793c8c480b59fcc4bec660d101fa1c61a50b423c16c09a29d2dfce1d2011d4e4cae986e4822090379c17ff077cf56d72478a9bd703c2ea037ee7419b8b4464388d3bcd5544d3a2ebf12be85917021388950c180f2b020ed1d6dcb3a7e0770c7c1f5a44030bb4076e568996c307182b103050bd43ae645aa96be787f1d82cdbd629220104bc5167c0a8b8436d828cd70d34c9ab0c039cdb0a1ef137783e92bd7eac1c995268ada3e1e8a494fb00c5d678f5b6010c8687b57bde36d001452b0a73912f6ad0f7076481210a975b44410fceacd0699fcf7c1489e42728ad705600cfe6c2267a9c7979274e73bc2aab80155fa561390cc9460a93f29c4db673b00dd95d5421b8c9ab003fa7b48f82fd6bfaa264f0debe6af3aae7716b66c5533c94bc595e646c38b004bfd638e261b14562ae061164db1716208f79e5ec5e457a9ec47d2b0b7b7b68a62c95de164217b7472fe600a52a3aac43775f267832bf98ee2112ca9db28be3e8a828bb1ac676178ed490e0d27fae273a7d1de1fbca15aabd065890467ad7d4648487c525bf1ded91ae1bd3a99c6c734d580c69895dff04f3409c2f7a3e0416b8a2c53c75dacaa8bc020c803ad12e8a48f850737fe8d88f08643bb6863ae7b23103b0037255cf87f27aecaa703db904d789c61147b8307928bb184bf94ea902f14032d3ab1d6d13066ef6dcfd80cbf155f68024fd9fe95ffa782b2de5c97e1027e7f794c4ad6a2c23e3b5c2de5289a1f96a4f549dd32e9e4cc07771da9d1c170a315ef9d6846bf10dc97c1ec7b748b5cdcecab920d93bcb5a706b23e70bda6ac80b8efc06eb3594e5edfa4326caf3afab8cbd479f5c689e86e20247a42e828e589d831a6f1b2eeaf747f903100540ae7d725b0e48a3d921c303e13cb2a3ab5f8cc20502b90ffbdd69cb42ec092cd2a24ae408436e77565084a7bc20742fe0983744d7c876b646b1385a383bec18fabda857b91088b8c7fdb5ac5591bfd8b4f5c8f880509d0b6a54ce45d15c639f3b818508c08e6ed4a37497b2080364ddf01465df73e2e91a7a9424b10ed9a6bf1f05bf559eced1d0b667c35885c43db657520609a3f55017f8ab363fd83ff7a88974aec48d9b359d25ac9e201302102b8e62ec176918449e7fb745ef5dfc03381237e259f4cf200714830b2ccc4925afed71a4b956d1bc55b9aacfd42aefd9d4815a6e1f6151fdc9379e34faf98911e2d5a64152c426c0e8f386e06a86190fd5aff238128a62f07e02934356511cfa2212cfe3df6d5c87cdef644e7a78b34a95dde40002d4fdb43243a2f33cd3bcbe00d3503451073c3b13bc772f98a579c72116f57f7bbd07f966bafea91fe80541acc19e4010723daf868ea6b5760e66d317090ae218f57ad67c2992b36e84d513052eceee456c29cf57b8336516148ce3835d6ca526913cce6acb9a6fa1e0ecbfd9f34609a6751367c07a6017a78e078f2627e9f7be020482731cb93e778728e0a35a7f5bb2d6c4c9e893f0f7581effe6881f645223b699367feb54b8bae06a68e025a9d8ff507efb1ee6a0b9a74b14d47c8c32a4188f98d9b359ad1dc9967d19aa737355356442e659db0097635fd03e6d2f629380a5a6394e28a13ff69f36ea8f0fc4b70d2d002500f988db49c8d4da0a71e720be07034ebb3389b2c75e3c6254a82e2e841ea0c99755dff1ae01e51367d4e02eecd304932510a947f948007414e2bac773d7359243b8bb9e973cd4a11f7e6406f450e42416ad0927b133e0767adf949efc3dcabd9b523dd92b63add6c12d211edda7dcc73deefa427ac96b72589ae0c9808e7bf62ac31ed8aa5bbbdb33db466bf8a33a7e3b170058b1cfe84c96eacf005ad0796aba2c994c375b79862fcb6cae4d13bad1dab2b838c657a55f85b988892f62c3581cf60f24478735c04288c1fa09896e7fccfe1a102daa51c24924ce9ea1ef8831c91d526a55ba7ef2149e0a5045d8362329b6e3487ce8a7f0c33a428149c55543bbaea26b533ac8103820d405138c17510970cf367b3e3a4c46822d10e05ed47ba4c3bcdd02eb7e4fd990da55a518761335f9d2efa6878f8d0e29b2704d3af11dec3f7a8c2fa9a7104e971ecdb7f18d93ad2a1ecdc8a4d1dcf8ccdd66608859438ed23e5179f6594c631103828dc2d9f8c784d2a4cff15c58084318c18571af7940cee704e9f3cd0bc758ae7cf9d70995f1f1422bdbd2bc441831aa72b66253be6ce186f6e93613f2d3888a555b578481ca324878518dd9537e5e1e7b27094dc5114a4e51a776fa8e5e86c556f45145cc3216569c17fe22bfe281579a6fd70334c574d1d7aa5fe461b3c0262830a2afd4b485d348babfe81a3418bacda574019077cfdcbef5de1e73c8a8bc3eb9113713b563da34073670cde452e84866d688ac9f691916bd443b02c8bf15c672e1e75b50156e1e5254fc23e0b0d6fa530435ae5fe06132d691a3e59489c7102aeec1ae9656aa334321b8f07aac206dc80cabc6b3c8aeae941438ff5cfbfc494fe08661ea496b7a81cfc949d60928251ba6217813140d050fa68c34dc58771b80b84e79f469442584db07c6b5ed39a5f83398965b715966a3ade89570b09a501860accccfe10aada86ae989bae9adc4ca7480916e1bd4733d6484959e4cd199086f413c17b61e16f42ad93a85ab8ee86e09fc1dff1087384ad087a6d95dd845e457f740e538faea88985df42fa2e0ad89c8885de6e0b1514cdfff9e86364dd37ae591a1843f60f71b8e8b6aedc3155ce76d1fd9c4a20d077050d7942e8369cfd9e0cbc19e62e32d15edd34b7f2645dc31c1de6ac3c36c5850d43a6c479e7680f02e23c8870c1730ad163dd31d38e1e7de492ffebab9f3366e85dc9ff42dbdd1eee8bf448abc8017a2bcee2367e958a01986fe9d7083e45e262595937e3287b499090d4ff466f52824b032428757eac7756ffe76ad43e6f70c98b4e0769ab91695a6ead1a1ed45ee36218dfbc4994b7e5227f0fa0536a9b73b01701d10f97d0c4b1bc9adfe7c2bda52e8e042b976a0ba1b9d988acacf9481831cf6881e70b21520cb0abfbca56bc3fde95dfc84de3b3aa9d4f598dc5aea2473ab0b2d9758b4bcf353c3fc2c6a7e487cdf1af90ba9b5a464539e788b86077ad0ef611a2910f784d72c75169ca095e14e4916c346e55cc1bf042b0d578d2923580709536adf49bbcbb7fee7d4c8a61fb39dcac21ee50f80a7bc76e82b285b0bc3f0b0fc9e70563e82ae65345d521a5ecbe211dc07acfc85f707c6d23326124eae586bf2fc77b6021630ccdb6dab8569b00374a1623f1a99138b870bc25d20911836d1aa907e9029436cf0d17dbc9bb350ecaed0bcbf4d48a4a7cb78e602e33d13f243347496765c40c8b786d8bd4ae6d9eb6ab879d4f56a004f9d6a3b6e98e2ab72296b546cc34abb697e7eceea1273f7d8658e60112932673e090be0c212d3d664237b91714d93edc6c86ec4a3c98731f7c102652015d58abca17b412ba07502d79ba43963dabc05bcff231d342951f36dbf8f8097e363595dcf7141215284cb4517474a85e0f0212c2e3c687d868794d51d1fa9b0cf102a62a3de0e2082848b90f31f203291b8bbbcd0eeff6b769095ebf9ff344ca7dee7eb000000000000000000000000000000000000000610151a212b3238""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -a01e3186a88928fad593837cd6f24d201ab8aa8cd445521805be6ad197e670b8ac1410aac5c88a4469cb7ee7b1e2588fe97a400d5cb948553a8bdd0ace8201d7ad26e7db90c6f841f7a30f31f167e5a3873dab36258655ef0cd745ffc8e3ba7be7f241ba2e97f456aa4292288d0825b921d8b266eec4fd51fc0d5efd1d9f67ce4bce0a521d2e693dfd86f3d3d308bb337ea64625b1404f0121f90c6ff06e14059bbe9cadb32051cd3bc9181d78f7268438729e1570e2bd89ce7e28afb134373120afcc99bf30d963f4bd616d8cf0c02c4f436592395ece85d2bf650553fa720b1ce842b0daad2f610a4a458ed4a4ca98f87eb5ed4bc0a57d892eaf62e9b525e6e6e30f0f9f0a5490ade1c10b8aeedffba0bbd7976aed7a24f1cae8670e9901ea3d72d6a895307ec5caa87b18ffa6286a802248f6e1eda5c5191ad3c8f015bc607b79e91522f729f966b1685752a927ff28b59b0e4584f02f456a6c6a81ca4ab7548e4768ea744461882c24cfd4d4212fb4733786e10b23574a3ed5310e65fe9e32ede340e6a2349b551f5a99b238e4bb0496e56b65d88cce8551b23a89937c534c1f38b2f09958d0b017c06ddd26fe08463dc6737a31c1d74add57eb32fb5acccef4258551bf5bd845a2e872cafd171a030db69944b594fe5c7214b21a0f5edc80ae3d3c6c8472fb546ef13c0d0d764087c8c68c39b61f805de2b3d9cd02a86a00c4cd585416a8c25369c959d2a0911da264404a5a95db3688a2b25461a5f26e941ac9da45f18d1ad2fe82614327ded1ebcdd50471e7ed37d32e3b48d12f090cc550b2e64e3527a81b1e66762ad75198787487c4bc3743ae3d4bbcb6cc2b279f088bbb2624980f9ad78efd1c0dadb870e6732b53e63a025e012628b9cacf5cd0ecc66b21754fcafb6e5fbfc99214b080b0373c5dd5bc70b28b727f943223dd69c8908a54e49c86f74da456492d06dd8e454953033de489dbc3fb7c98613a79f303e28b0f01c82270c671490105ff598f7e6f6bf6a6ea0288ec7ffdb90c4c7c8961874c8f020d7228fa79b9b0f86ca39738b755058d341a90bf63fe98104de55fc04a287905933c49e5d5475a49b873272a8498fdfc1e6b043bc0881bedaae1abde9ac55ba925af591037bcbfc768932e3749f2336ed3affb2530b4bd527cfe1589a0a0ae83320dbb8905d31a48d77c1df191d76311ab02de75591da5f2b9e34e470cfbc6e3459cff655518cd2e070c4b506d24f1281349d57732cdc303af02436dcd57ca2d1b716ba8f70cce68035f1bf9b932618d3913b1dc9a9bb6f60d35a68d90584077d02d93af025f84a414fb939b0246888dac3680534b2ba9f2e224b10e44ca412c94dca680b62845e441d3efad02ffb944950cce3c6fcfcfa14e3c9208e9fabc52b1499830cddb6bf6db50f9899833e2fa09e09d06555978a4006c0188bc13150cbf94232938f382633ebc6d41a8c5a917c4abb86b2b5c160dacbdd4a3a33acd5c158e0d95fca565deddbe2042912079e796b5b67905254bada03057326acd332a7c52492fb6a8b8876ab3a9935d11649475de72816dd6b756f204b6d1aef5f5acbf2ac139568851644f622a945526bcb3c86581fbb2e5298ff01b2aa48fb69b5de1a901167996eb41dd8fac44c5a02c3a36ecdba25a7edb2612a5b01b5e242b1a55a9548a962f93ca3797901ed4beb510c11a90821c5c1586cb82f2f095e87c8a42b81670d342bc34fa7bcccac96b9cfc2966f3b2337fd648534449c8d8d7c6f1c12330c2631201acd5a8c8a20d7b2006507b1ce5204cdf8bcaeee8b3036f9f0b7f47d5aa28df4cc55ca9c82bb2d59aff4436ed8a09ae1d44bcfdca5d13c4d4d8b7803bfabe2f8bb88e25eec965b0dc904e48e17acf9a84f50bd98d6739b312419033087ac252287562e9e88bda07b8de3ed0e503610da09e994a81ebd0ba89467c58dda3c2e9c963190f2afc949ef97e595dc445cde87b7303cd3aba04a35b348ee2a9d8421d1fd69ce0d3bcfec9d93d243f45eff6430e75ab1fcfce14659edc3f7d81efed055f948325d28fddd90fd7efc48812f267b828ae94a9964ae4a8e764fa6463840f8a6cf078b39f12ff36db6e03451d4996226b257094ddd73a323036fbee146e1ea3865dbb6d7a3dbdf85490b04c28908d4ab713fd403d97eccd18955707683723ac946b6d90b4ee63a771dac2bc66ed08cabb29fcd96c2b55513b4e3d9815567f5f8788fd22b6364b8cc3d2a86bf9ed5fe775e131206192a85406208c402937dab551fa4e8ee4e4254546a687b212c538a779f50ff39274d8f22cb2ba5ddd74a6440246b005e7fab095eee8c47243a274e11375232478df603bbcc729ea9b6778a37f64c4f314d963301c9a1f92cc8884dd393f3a4b6d42910110183d5fe41a0b950dfe477d505ab76a31fdb5195d1854b7487cb65c378b0494b45370dc64858041654be2ea89a704a6a903d044c962e3b7e068ac0ac837357ee49ae14d612f1e3a319eca339ddb1bab1104b980aae1ae07ddb27bb6a69ed585e3e7cb2c0987d51409d1fb23c4cce7108f6819153e7c670778852a7c7fb929d1357aab51bc9f0e32006bd7167bb39ddf9ecbde2c63e492a8dae0de0574c364e851b9937820e49459b5e9591f12b16f50c47712b2729e031b4e3de4042c51bb51b0dee5b44fb9cb37e915e64cc0761b9e3a8e0793fa49812d2909e8376db7c0dd611499ad7ec5c527c153f916a020d7c23597fdfc954171cc1ac1116a13c0e182d4660ef724c852a347fe9cd07e512f0712b55eb141ea4fb931ab8915f3dc3fea2fd8deba0640a5c60a8670216ca967fb8f89437cc7acda5db202129181ace745e0357a6884eaafd08e8bb992c8d68bae86a940a4d756526f38e115dd75a2ce0486cf170951130a8344bf3ebd241ca694a84d2af21c77f77460eff8151040be2b3b0922684e5570b1097f0a419af32453da40f52676006addb2b9d9124c206ddaed4cec1dd46d08dbfeaba8fe279e0ea1ceb6ee9722f67ef2f70d9f651fe4219f1732e35b3b824d3709621d42b6472a9a9c5a4cf2bc534464169d3dd3763f8ed1d80d43d656e32790334238c1d1c61f3852eeabcd9424d1f9e12d4a08a1da9d937b35c1ada0feee310836417d241c0d7261446f836ab3e9729797ada42635ab2b86248560724242a044323a078f28321c111340423770ccb36d548b82fb2f3db2f1f7eb2e801e510412a91854b574668205aab9d4719d09568b4392131620f3af1308cd02efde135423523e6b1a243f693364df54744a809f483ad375fb792a651cb7a81ff1590bace3d81d02ef26a33305156c620c7ba256c7bdd6b6567aff0ee45d48c8a087da1e91e39c4012221e2baf5c73c8634db7797043bb106a287d2f0af1389f382a452efe0d5ed1f4eec269bb0183eb6d6c73da1647edaecad7c07760543d4869f80674ae0d2a33834b4995ec00955f954fccde46b6b3c1fb37116b74cce6084ffeb1a9c384360a95b4626cec377a964144c0731c4e74e6eab065411f3a46dd97ee0a8a4635ec2409042e8196dd7e4e254eac645e94b99636fcd084140211d9bc34d0b104f202182baa97413e3cdb139c1b4cf1d88ea229f1acc6040c448c7278fc64f835480b1e7dee06cb1ec3c4244739930ae60b208a"""), - TestUtils.hexDecode(""" -14A8B812B4C9129CED02A09C8AB19443D34DBCEE85AA12528B61F84A2AA9D9DA49011C8E2C3C3856FCF761EA9C9882FB18666F3EC2C8543037E54FEC1F0F944FED3D350CACADA9428B7FB7D9DA4937DA4D1859BEF8C6177F0EC93BD67FC3D5B3D13C34D472D01372246704DA4763FA73BBCEB0F4C3658B2111A7DDC01FCEAA9059FE3DD5BDF2A9FE0D1C2384E82926EB895AA529532FB20E12F1C61BCE208E48ECED036E4F84CD60F8042475749E13D8C3ABE0AE17967D5C6D8C598A53A10231929822FB01EA976A08BCC0D18B1F9B6C7C1ABDD15121E00EE80459E6EFD61CB8D5AF950F0A8FF2807C32CFF7A56661C67348617059D7E128A72C8AF36B149DD8B46537EDE60EB5DE8A16A93349883B73F7C4FB8CAFD01E0C9D7B1EBF6D7C9725651980E0DA598A6ED5114178E47EA4C6ECF870033A03F134461146717C8AEFCB8E8DB1ED4E286C68C7358FA105641EE3ED9B4A5D4826B31706CF0946C152A365B246DC036191613655B829ED1AF8044F5707C320EFA1126B90137EB05FC220F122AA990AB476EBB0BB3AFF5B92442A857F6808E144C60F4B5190794C411C705513BC32447D83B760E907E6FEED63FC0A60C0CCD01734AD55EE178E6BD6D4B8A238ECBE8E4F8A464C381F16F11BFE62DFFC5021FABEA941D24B81CFC3D0F07F00F902FC5042F95A81BB8B795907F8D6BEDB5E5C56D4B2A4353D0188A90C01D7B2781EEAF2BC3D3D58A6F6AD63DF7FD4D32ADBC5A7A2F81EE3F5B98E8052017868EE59D8DCCC0199A006FE4FF39699EECC82DBAA846AC60B51FAB6F456DE4357F5EA43FDCE4B57AED55F2F6EAE49199AE90F6CC4AAF662ACEC2724337AD7F9CF74AC990D3083FE384685A1E616B233752E31CC4FAEB8048EF77480CC849D3376464621E2BF48CBB55E1A7CAE855A216DF4A8D1AE4E4016958F5855FC395C53C23327403720271EFFDF1A90C44E93E74D71BA29D860679E877E410ADE48ABD0EFDECA426DA792271D813116ECC894D799369EA8094C328D7694E8CA47459F31F5065858252C1EEB1AC4750AEDDD327048894F7D79A1D64737EF6E8B93ADEB938C1EF31E38DD60E8B4174AE093697DE4207C7733D82B4FE92590358515D30264A408746AC252ECC0BC28A9C98BFCD76C75845E9611909B0089B571259D1D115EE0D5DC6BD6F3697E1289C4742CD99F97B5D3A22631E33A81734A5D2BD1FF4A819CD6A22A938D3F18AA90794C120F4BE7E14324E89EAD34820070F8160B140E8CD5D68378C081DADABB41D365663AF26C606940E08B20581F4E63AC6E68FB5A7EF5DF86047BAC502223AF08F6CD82E6ACDE60116593046B5CDBFE2411A3FE89C438A1E84CE6D1CD72CFD3E5F67C331E72754F6CF2BF921FDE2C6DD5481F20F509A6852AEBF55BFB4B52D1F8B3E397C9B147433198073049638DDEA7E21C2043C786C88E45E566B6A7E8742209F5ADBCD34FF26962E87CD235CA1052AC02E4BF75DAEE60A06B19A4B0A61A15D9651473DF8AAAC6DB951EB6E669FA5F89175DC1FD4D881D688C477D16CEFE809E623B2F2A996909C3E10CFEF756ECE8E93072AF27B87715953E0C48946DA8E893160CD351E48FFCC6847975621E5C75D5DBEBBFB79297AB368D13BA95308E3D576F1C54CCC1C4D5EF2A41BE63AEA2A9F9A27822ABFF58B06AD99515B97F260843DD2304C855184EFE96BF10420184CBA2CD3ABC38D11B7A74E4A9E40FC26CAF3A84BFE8794477335EB1F4C67ACC9513BDA5D8252E608D03C69D493F8876FFF25D39DCD71442707AF2681CC6D5E117BD24315B0FB5C9E8175CD42AEABF699B7B77C9A8918AB94518B48DEE1777EAD8F18709A824F277BC06CB67915A5A2508E18094B0ADD29FC7CD554D8671CFB47EED2F850FC84B1C0F27767B3052869B653BFFBECBF6D8077697D1F440019E3381FCB917F5C06008A04C8A88B4493698C1964E25A551B03805244570D0EB6999AF2BC467EA4732B460A40F7C2EDD2CBB07A2DFA99B4E5F4663A45F2774C1ACB0C8B965E1053E3AA140E973049714DD644CB9317D9B3252150CC9A525E8729ED4A9A7900B417875391F7BDCEE646B1009CA479A1295555759C5A7597A775A1D1CD8D870A71DA7ACE7CCC7D2F38B18BD66441D80068F76AC194FADB3ED5F4201F26F670621D254264A4D2A88426FA6077895B9BD794C8C84DEF942FC43F2FA115509429A939052200196CC921454A65C4BF1A6E871970A3409FB9773F356BC17E03EDDE8CBF2F91E7D2B548380967F756D36520009DA5032F20D8C8CAFCF4B561A4C2894CA13929DF2AFC2C1C9FC41968746433FACD66309D2A7FB5D90EBCE40ED1E80C12D07BCB075FED76DE423D9EE6B1C787E1039749A0E559B86C4079CCA1CA7E4A3EAACB300C453782071725F6E2DC0652DB5EBE7D1C16B6EE0078004ED1F49DF439107AED04A2E69F70A35057C36A307C8F5BC13FCEA76AA997DFD2E2E4B835677EE961234895BE9C9E7D1486C04ECDE36AF4F7075C0CED9A33C372C33F751C953A2096815D9B6186632D3CAC31AE6D0A931258014D6F88157ABEBEBA1C11B9CB2956253D4950F5B2F64476E4125848F27D9ED4F93035FB5F5DEFE2435E67DADA015F048A90EAA9780B983748CED6056D021D21F6FBCB1A2DE0C627F2D9015B3D9D35CA17C54B0FAF85D0C45A53DC2575E2CB54B9A5681FDB66C9D5A09A3F48DFF29B24E45BE82856C6C76F0B9680F7B666B22221E14DD8B22A15FFFDA1D666F4EC6ADB5B929C2804ED36077E1A39F166C777770124253ADDE6B77083ED159CCE35894597E7BF3DEDB346571C2BBF69AAA9ED133E94AC7E31F2C30AD079EB4B4452232D83E49B43DAB60BBD92673D90F187FA6F3859EEE1630D3A232B99F3F960E8BE49CCA0F1A519156D2D861F8B6C15FEA4C4635C23F2ABEFDE8589A45947D391CD1DC3439F965C6DBB5C5C9AD14192B3D784D1C78B3DF6719D5C474E02D471B9B857611E2FED83869BFE8A2A74493C25D39C78DB019BE93E3BE331131CE85C4586C0D40D676640405FE363646C2264DE6F64365F19F87A8C54C884703DD369FF52F65CD9179B8A09EB92C38C284E06B0537EE686D7BF3BD399FBA8E1703BE3236F8BA262E2C84D55EB1E1E55DC14780DBA04BC1106D98B05593F9164F1651809E8AFA0A04BB0B51F9FFD5062B495133B509A569845CBC3003BFE23A7D7ED433B70C2EAFF5FD898009CF1ECD9E9B6F37CD7794234A098CCC39EF078E3C152017CC73A19B811FAB4A2CEF721029F6200A4D1E4F9E95A0A758A7AFCFA047B6707CE048C3BEA6BC561D152AC4F161347C098F4F44AD92006090324757D73DC074F1E1D445A500AF5A92CBE19EF631D99FFF870C60BCA8515125EEC36D004F22FFB420F5CB01330315F00CECFEE3254E54A047A7FA3C7495E6ACD579A9159F667FCAC4C4448579E7A68148D5518EFE269E97D90D67CEEDC378657A45E9DA855EC55E7BFD0AC3E52DADAF76E800ECFA61F2BF532E7365C4FBC8CE882AB327961C6A48C24CF0F0E6F2C54D732BC9B592008F2E6C80F7EFA788AA6BEEF0B6AB7B21DA3F9D92ED8A8F5F3F4B1D1BED6F66B6BF3ED52E49715C07DBAFD67F4F253DE368619A306C513E645CB5F154F7823781EB3E15F38EE482757009E42CEEEC1530A0159D25F052F4D4326412CBE6CD11C0DCC56B6556DDF806868B83602671C96F81D8210842144757A36CD187EA0900F36A0A9DB85B9609C11DE03A38A9984003EBFDD4E7C07CCA7A7DC7FB5F9F16E6C0C32CF86774B46C56BFE2840D8EC51E9FCB719DD1CAC4206372126DC8EDC9A4A2EDC8FDC8370C7589CE9FABE0DF3C8CEA90E82944B8D489C0F52F73EA3E3BF56BC3644A1BB0AF88F4B556A554851593E5FCAB03E235670638E4AD77BF012AE074F331F67222899694CB5EABBF0D6E6E6CEF75151FAFE89DB9D66DA4464353526116B3C2F382825B11CAB3CBD221DDA588F4BA13548CF627B52478F47D9B61479730CD9CB3F6622702C9A115D69EC232CBEB3FA88AEB832EB266B855A98424B2E08A699453A891C89C45FED7BBA98D6E7A2179A24D41D201C4214444BFFE6D01A15CBE640C3C54458E8DEA5DED484FF7AA78541686C60F9FEE76D1A7ED1F5686A2EC1F0AA037E6CE38FF695DE0C17895C9326415840FEDC1675E9CF30B8C45F8EACA1E65DD18290E8ED826738876FE8B69DC3432174151C051FD23CA4675A75E73F1D3DE4CE172FD657B57D5D03FBF8B29E268B3EBB8E9BEA96A4750168E8AE5AEF6B34701276DD18F1FEB01FFFA2A984D3A59D05A56552639D506BAB3021D507D56D0FBD80DC582B3C20940DF2393AF24FA5233DF073C7FF28B54C7A921949960CB2593AA4F93A06D38D896D547B28E9CAFDB479B7D1BA2EA7B4A6BAD33BA8B59DF8792B22F5FFF41EDB1FAA926FA3CF602FA63ACED78E85DD7C3094ED48D1F3381BCD084A9909613873513657879AD8599403A52ED0D16AF0B3B43C672867700167323D37FD6373C4D51B90327F4981A897CD54C8E35A6A5904F5AE0CDE36440393A59119437016E8CC88894B2A6FF661C10AAD7C7B03B7085B70A8145C305D5E66CAA265AB42B34539CFCC9A62B5D9BD09FA4D3B94BACE361B4C6BF6B550B89922EC01041CF05C0E4632274949D244B7776D6504C9803A67CECF65F750F9876109167CA77D412A7EFF06CBCF129D057143BCF03CB1C1AFAF937E55477F5B15020149D64F53887467AA16C6692FDDE61406D552660B88AADF65C03FE1B8D485C57FEBACF8B11C569622FBC56CA1056FD3600E1BF51084FDAE32876BAA1E97637F73677E8FA1462222DA72FB0936ED66C16A5E892C44093CFE7B4E3EE33F21091E04FC4A07C6CA21E93A500E5D7378EC716A9ACB27A5687BCD7F4559C32F6C82E8C06E82135ED16C35762E94BFD6BC33D5116E4FB209C98C871FA8E9230FA807CF1FD509A75DFDDFBA5CD4F131FF8B666878697B372B92CDDA15D0113E8BB91A7750843B3D14AC4E8C956B44C7A3A26720E774EC1A1F68435B122E539C8A7515A1AC94D456BC4DDD54839AAF6EEDDFF8797C9BA3A15AC70C34DAF78AF1F0C21734DA32A79C1BD3CC8B2636E12B9D2E42AD10446EA1A9FFD45430E03A78D8F38B64B64C9D308D18CDDB4D5DA13F1B4D15157063E58C36DD71677334B4D9BF09D8C765FC68B233B31105D0957F1B675798E5B9E982B1BAF1611EFED0E39E1E9E70BC790886A422DEFEF325A07D97FC603866C2C3682FC651CFFCA09B8122B636A65E2D6B8B9FBE6BB9220959038AEE11AA7003A9C4C4EC9E27F4A8350FEBF1084C292B6BA9A6E03C00979854CDFE566831B077823B025FD1B9C7127BDBBEF34186C74759E32FC222023EAC24A6A6653A7073F4033D77CF83831E8B6BC8F26AACBC3EFB2328C6EC35C3A509FA85E2E04532DB6E466BBF8071FA6020CF5585C70C29320786EBA815EECA6FB2BDF9C9F3A3DDD0F1800E93DEC3C5E6DB4EA5A695865303C48986CE26346B6CEA4A734668D5BED675EB0C2A1FFDBB9E5511EC715BB4BA3604629FA28A53CC0DBA1E819A521AF8B7BFF16B4FBC6766543C0111E232157B7BE4D561618D6ED7D13AC8817641E7AF77042E96C7209F1B65C42D115234F6C63B84D381F1820CD656C88BDEC7CD2A814D6346E90841005F66D6E36E63C5906D19904EA0D33502BDED36E7D77FF5E2592290D6F29200668A25A6B6F44FEA1D3EA00BD4BA165D122455E8F97EDB36061DCB335870F44068EE4A64FDE5695896D6A5B30D7613BD8C8B11DB330AEEB0EF239C105CE6C0B2E1BD81E867A2D823FF88E3E82FCA69923E281A2933D5FDFAC6B217D60958D18ACED57D670851D5A6A445A120F5B563070995793E618F885F149A3A3D498C69A0B9D99D92C16327B7568BA8CC35128500FF515273099B645C683EDA30092C225D01E6337AC652586C0872C9C5EBF09DFECA43697BD97B86FD5463F529CF303A105194BCC3014F4458CD3BEE8088B8B05D58A960334C73E1CEA934CA0ABB2597F703428EAC5DF6983A76A5EFBB4A20221E6EA04F67273D52D0311AB99979CB0EBCE738B0BAD72F0DA80097609F4422D962DE43D5B9E27F2FB3FD55DB5B9E98C1E74533DE23930052446A31E656E150261C6658324BB243E0C55C43BB397367D9E6EE51FF7A3F4FBB008F87FDC3448C07B88F4EC3788FB04944AE1D734E00E1CC58052AD2F908B55B39C0B1FBFB889EE2CF91CC1B3FCFEF11C14B083F8A898BB28B838662274B9974AA8E83579181944CEDA7FCD9C36D5FEE67522E828D6FD9CD28537D9FD57C8ACC7B8F888FAE4673FFDD859F6446B41609135BEEB20804F4331E31AE057171D27D1C338DD976634A460436977192E7FED668FF01B7F996F00958FEF2F89C78367507225C458A7EF81513D849081E4D22013A4A8DA7E6E9AF687918486E785E2E5D4EA5CEC4F92910E6A6F89198FF7911A16D7B46BAC5752AD5F7457E9B65AF0DB57148812FFE9F7C70F5531D11CF96ADF7A3AE1D86039FA5CFD5BD5465AA1649C40A513FAD60B54F7AF15A5A6B34F0935BAB28A1AF631816A0F5F1E53E1A7DDB5FCE521252E25910555D70AE1A309BB1BAFB7ED3856618161CB41206810AACFB9F748B06F6BB8ECA8EAE07B77934CAB2FC72FFDB061D5FEAC548CDD1BCE7CE5D04E9D2E4F38834AAD674F0D540DD6EEA85CEEE4F67B1D572597E9F2B66554F7F835894E81F4081EAB2578CEB8FA95964742436FC6741A5A9D1F2257572E7026360708EAA41D31ECCCB55811D5BB7648EF4021268C8AFF001F2D6BB3E1D4D304374E892E4384D66869CFFAC575398808D2042B2A33A874BF364B6E7A859BBCC67ACD4B5DC3494C1A6B55CE004A354C8EA8F14E9D9A4ED282AC4D78909F42BD38D044FBC1C730F921A1C678062A200CAEDB0EBD42D48C0B758F138EBD6BEEE1E45BF92157E3279C6534232AA6C361953A0AE37E81261832F29CDEE864962D44CC6C3C68C05B16915A8FE35B067EA754777725EAB0BB4E20C3BA7D6E75812C498F29A94D18D90D60F49339CF46DCEC6F0A546A90E0BD6E75B95441CEBC0B25945F2A38F3EEB1A9E20805A81E3008750588397A9A168C73C81C97FEC1BC16659DB16AD7BCE275A884EF801D53868B0DB816FDE421A9D7FE37E61B699736986325592EA93DC18B036D5B237115C35AE3862E355A1F3CBECC5BA89947E6E304A86196E0AD6A113BED701D21E07532A6D02D014C9BDEF9F9060799BB79AFFB218F3B98A4BC9488E5D2CA13531842C6651621484207723F41055274364FE30601C33663A6DA49C8187008BFDB1FFF4B7B3DE89F7FB0BF57F2E273EE84ACF8EE91A5335364BD034DB6A1F8025E6522B4F3D6212F3E75AB34179B21AA28FF6911736724FDD4F3229C6C26142BE5D6F2148C9BEDEEBE6C56B6A20746875A6F74CACCDED95179AF50E1C5E09B942B4E3C5E227C1A9DCA36F04CB89EAC24D5E87D07BB407922341590A739B825AFB80F544F2B1B70D877300B46000E660A568999EB8F54A3809D6879935492CDD67DF15A1FA902AE6ED30D5C5EC1178AAEA8E539068EA2A0132EFE51DA8A43E5D48ECD5D8BBD0FEF8F90288E3068D17EEF4204D639665BA3DB7C172E99913E97613DC4304006CCB37F1E9F62327E1C2B5D97E31822A52298BE0D6457708E0E2EF25A0C4C932F16D25A277C5BFE1AB13FD488BDA7BF30F26E89585F56D827DAFC799D7DE3BEF0B41A3EA3491514ABF11E633D7F4B8A88CB6F3ECA3D48495475A33C9107EF39157D53D447308BA03139C7A1A9AB4ECB178D818DB6F83B4489626E2EE9464D7392C80F8B4B6317095926370681D1ABC3A48D82DE7A810124099E375F39E5C6683F4972556FF258996BFB0FB81C44E3C0C1A814AFAE8CBC041D7E7EA4FD830568DE534B65926D6CB83D306A36861FA2874234E33F4EA5BB8AAE05C3DBAB96CAD63295D7BECC26F5A4E862546A166A09E059293AC85937FEB612178B8812541A929B81A090FFFBB17DFC3C774C5BCEA1398DD530C5286658D326D7BA7DA3F2E15FAEB038B8A397B68AEF622EB10B248DCC942E7BF4B4C942D33A4427B685A0DF2BEE8271E89A366708C9E48F6A3992174E8D401D821DCFE12099D3EF0BA0806E7ECD674422731B0DB2B198C495E9DBA6294FC736F41EAD9232A5E404A8E918A18D7A7846E0BB6716C4343C2FB00286049D7BD823410EE8F71347008A89DF42EFE049C61CEE782102730944DD15C0DA322F6DE4EAD8F9EA549767BF02BEDB1F091252F08B34B6728165B11D2C62805ED24ABE65A8E95441D1D5FBD361FA87B39135A75D749325F09416CD3E1ACBC04F6AC8B989716C55B06FC784B0254A884EA4CCE8ECB2EA278CD32FD1FD99C3085585201EE9492B7F7A2259479B1FF820661466022321457088B202B5F1E67709B763A3A945B19CB5A6EF0A322272D98F8921B775A37B6CF92F66CF86FFD26F84547BBA75AE82411E890A7D8F1B74D657380287606ACC8572D8522B87CF26C0247F25A7F8CA12911081224128ED444C5AED9EADBFF6EEA9FB7485884093C340CB326BD467CFC4F6E6C17D4F13C7F9F76192BF4A10F2F28F538C76BDC1F8528ED1360922E5A6DF1A38AF9FB28542357231478192219477D554507A47E9FCA585730292493A2B3EE225E0DF87C747E0CED460BA677EC691637F444D248805FA183666FA65110AD3ECAEFF59B2F8F619A275034CE415DCEC6E68A3530D17EDE27E93D87EE1EA55D22045CF436A34F907D35264116A848DF0B448E4BBE32A18BBF16A8DAC00CA6B07876ED0720591345223877E26D2DF4C0C3FD8484DF1DC40F1B7D4D49E871D8F527837F1B790CDC9FD95D698231CD090C60915C98F1CE43F7825613FCF8EC929BBAB9BF663A555210868653131556553F7A36368B0D83AED6F9A970CB2D63163C607ED896FC7342A71C6A1C90A53DA0F32141600F28F31A9340ABE97D0C6E8AA3270850B6598670DA455F8E2816EF82D3267D39A8163D34B135221D7D5D98069A8233802810C7605AF9764C6DB44FB55E29470503090CE6A720617DC9D17A5091CD3267DC4DBC1A2B7032B50CE46522A2FBFEE7BE29C3DCFA1FCDD43AE2E09DAE7330D2E6F2B15D10F53EC6D607066504AC50AA7F18D3C290296A8D9ACD1F5A3708BC035979CF03966E0081FC53F654AD68A15A3D17A65A768A4CA5F647BB21872B1ACC5BA3DDB5F69DC215735A5CDCCF50D555FE968551D507A7272FB591587383DC5930C5A572BE9FE0C2797B622DA16C6B87A03EA563845B8201168C45E7603B80E5780E493AE87584A40A09AD6718CDA3759CF1940479545789F08DE83333FACC26D28AEB54E2088934332EB7DBD5829F0ECF89D22C62636063532B4361B9C7C2B1D582E9A7DC72FF7F2DF667D9B7BAA543FFA20AF6BCA1A9CC22B7D7D177B73AAB087F868AC68EA0CA808EDE0C2F931B3B0CCB28E472CB316C0DB0367D4D7FFE0C02977CD2E5B20F28867DB1EE0DA77C5935155175B33D3275426C3CC5B73748426CEBB3ABFC50405E30EC21A53073C83A85EDB485B26AE7B633692326003004A822F261D5E20246F99B03D0AAE36"""), - TestUtils.hexDecode(""" -e3204112bf82f4849550037d8b6325da7435333c716595e2f17c8a85d66bc4a612e19abd17411d3f4b7e3a8eadad39a819fe5ba968c8640243fb5d18a7674a3368099088c000a1c9906573a2957b57d5132fa2df9423c64e0f7d89a338d0d41e9300f563a82993c8e43009eef3fd91c10dc21bf4524dde27c4013756a1cf7b5c2829aa1698a5ebc4c46b80cce01384678f5c444648ed513a8e0c6e4d29b3b4721627c1c8832d736d98c17f6c00aee528abf0908b030edb381770e6d23a261731817b4ba5e632b1f77e5beb60f2e34bc2f16e6feb6fcf8605367b5d2dbec8668cf6a7b47fe5802a9eb93451f96e2ad72432726c9579cf08c4337ded15690a1906b82df1e07fa995eef43df8edb543bfc3a7403877b4bcca16aa105b625dd23e1d938d4d89293e841245472a0c38b77a6697923e213eada80659269fb642089b311e2818f8ee998b227a2130ba594a27e985aee0c6a3b34652b54581eea40f2c1e235ec06e055247cdc106164d6856fa8798e0da03c1b4a6b89778fef781dd6c5c77147db302df8ae78b819da5b8ce171f53bae732a100211cf232faff1e0588054a0ee99891a26f88b19fccb49693a844270fcb1a43f26677abdbe3c33261ebaf69f8f417ae6df03b55506c463088d49415c0e5f3d9cceea7518692649fbd2e0153b1612a84e229ca9a69eef15882d402425bad02039426358124d0603decfed2101e93876d057725f6cd131ee346f047d7e2e0398a5bbda6e1fc5029b57f78e49a49cab5febc682931f3a2b167d553e4f1b6511b8b07a8f62e4744c20a7b2731b317ebfa1e89825d4b7fec5c775243c9af25fef92f61261f2b4377593dbb3008385c92bb779ec703a7e76b785b8aa46c8c3a2bc5069d69ed865f1e5e6283f2aea3740a62226d341deb55d420eab001398596c88406387b293ebd1663c2bf94041f3c13b8579111fd7d53b66a3528d9bfbc6b97e72730a53ba95e0549473cb4141abca8c8330b1b4e0e0967b2aef589efee973c3718eef61d27b2a355be3c92f7654a6d33e5441e3a0f389911b40f6640080a752ca53ca9db239216dbc3d95eff963ab43973fd8633299d5adad7020a862a594c656e34af356066885494b1a02fd6fc5cb257cdbd56e85e74de7005f2b160f6ec6f0a61083bb046d9ca90c04478d8489cd75e176d027351a84bcb6fff940eca4fcd464dd577780473eea0a72732d435eb41d219ef7c2619400339ad2c30cb4ecd48deb40d713e148b474c4de28b91efef85e4f16750bec38224c0916892032bff8b89a4e0aff665ebc050e46cf7b7cba9fe8dc8696c5842f82e6e6bb6b58663e1669be1e4469cc8982650e468b6c9e5a1d49a44172f86676d9f4731994d74c4eabb9086eeab469a8a7de0e18845797ed73742864149d659df3118658f8cee2cec3c8a8b388432ad98d4d78f3dead445af3fd698fc01bb81d4658624312fe1da6465b7f53ecfa4e6f958b9f474711c9a2ac9fc8abdb0682b5eb282e5ec116c45c3236baba0cdf49a7478400dd8a67fa4704a8e98b29b7dc9913d15f56e613592dc60db932f374b1a0ddc46435feb7412b290587fd9e925987e80d155ff821e27d77de3141b8cf38694e3cd0e7ee0d822c213656fcb7be166767da6522cf9c1f29cf044efd1fe7f0d9e9df64c417aae894e354bad581a66432f4ba9b94226b1b577f64a931c62bcc6c97e5f20f0c53f35ae39f38d33600208a1c6986aca3bd143e920a430e9b6a311a751509316abadd632dbc82abc94ae234243edb75d362928f0d8a7ff9f7ba927780bd7bf62f3849f3fd937960ed08794f8df99dd27c241539c41d27ece05215f2e63e7305d09cc384223a3bdf8df83d0cb1f76231529faebaa18e76b35ef77d9ce6d2973ecdfde9ebb91d7fe2ff38bf0e4ba8f9c3efa3185f6ffb72a10bdab1fb829931858ca37e1d3356bb199d9e5d9d90b11339643ce9c528ff7fda54f907126fc745cffd1d9c60dcb92efc39469c70899ff3d5fdc6c18ccb0b3bf04bbd9d14b34c857467185e5f427b134c95622d34f3bb5fc4bedb7fa8e7c16abc277447ec511acb82de3d1372f63d9a30c40e6485598e707415a572a29ed1c82bf0e138bf6c6267380760f6f2d42040948e96d4a792abb2912ce8dfd5ad3c20bcd63fc84717a5b0c79bf6acf89199cca48e502661a949cb3123506318dcd0079edd930126c0e879cad817ee9faf22a49b11f44b0719554da894a7fde9e67ed576f562c787832b7cdb0ce85dd90ad391abb590cc33c83a57a1e7c088fef90937f39b423977eb5d48028af46a43d664f3ce89be3f153857210668a7f152d94aa8ce1305e5c467b3fe47306dc75cd2717b67f1bdbd77b7acf6d4bc79cdb65b291e7356201f7fc0176f826290cb70b54ee4f2442a658812274e08c0ff222750703f7127c72184fefe2cc8e6b0769c56eaada9bdc39d44e8464c3c789b8254919fccc48d692ee13e70745b790f5e89ccf04eac5708734ef847a00d4bdb4a7773d8a8e14779741b76b1a3be2b5bff279d8ea3f750c4ea5aa82203f55b332b785536e30d5448acc215c10a2e63a6104afc5d9002eb3cd9b98f76f66679766a0562a1e0ef9a69d46a453d0777046097dfe965e1b380cafbd62ba18753ade14c2a663c7ebe2fa88ec4cbdbc841bf49366dfb13162ef6d6dbaae627975d3f5d6ff47f7685c713c59dab2e0629d6a14fbaf1895526ee00a32405d2f4930ebae1d4c0ba243e0b77b0575650c1964cdaa8a09d70592a6e50f0586fa398009bd40a2666f0e9f4512fd9453e54df633b6ed72916cf87455ad6e67bfeb91e5bf15221e01bd61738f5e92d5fbb15d43df14f3355d54bfc97b061a1db68354e06d1a2fe0da4e1a6c0c0c593fff12496e42761235ec1238879a2c9797d97c833a76a3a65bbedb8012722c4c4347c30bab6d0897f9bbc0cd8b20030d7e84507cee4069192cae1437715c2179c6165d38b534c63123e9b6f07fcb4dc1c73c376d35d94fb4ff945d6b9f2e8f41a01ba5b58d7b5afac6f7f74d5aff530e3183a0b8992d2e885bc6c2d5415a572cd8cb8b5f09094998025b86eec33fee6f19e8fa5fa11cb49932508f066f38192afa3d11b033a6b635e9a32cf0dce3512a9d7af02dcca39c3c7d62861402586f8f08e0ca459e96f2767e991f70590a1303917476df719c38b8c7dbcd8f61e787131c093e2ba97cecca4d52c75e18d855c491d1bbf517542494928061f24f142fb8fff689635d57170be21f8bdb1944729eb2c48a66debf5399ca10d883c37c860921feeaa1ce240c419a987f71484762db1f6ab4cfc83c1bd9e4ca85c7730e9a58630150784fccf9faa926a28bdbce010a355ef4e8fe3bec648ee207e187fc3a8f73f80850d254cd0f9d9e92a0bf91e73d63faad0f6fe7908158ced03f396527e7b96ed2bcd521a5ac0e81fb60afbe91bb0e70fa6d5c39317158f67bffc160f0b80663267752bb5a9aa97d85d9e9f40f557a215aacc03d022341baebb7ab7eeec8425af176f3b97eb80351158095708083dd51d896bfc03d308906c31eddcb816ccb28eaac48bcce688a479dedf9417c950a7a8c95ae7b452cf83dc548b64d58b52928e2f6411d4b02466543e361de3db17d8994ef28dff206b493564876d5e274658e69b5cd70a0090d669a865e56e24150b57ea6d3c261b11c1e45d7bc387aee61add50c7f756e593de9c3057855ff761e95760813e5d30b41ad700bf544c451bc6ff51998bcf48bd6046d9bd461924121a3d8daaf3978f792d9cd23978f1c8ccd999bc79d2a10daebb3c9d065d30e970ace94a0f774d872c700949f2ff6a997c6e3193c5782c82a077c4524981e7aa6abb27b86bdc75928dc9599a1376a2a0ab53b6668292e4d34346dd2658fc9d10232b7e39ff5843c620319e530c71052952f75f2ab69fa193ee321c5702b6e3107dfb93b60cc99cc88f1fb48c0bf48c032e2ab5a3085fc9ae1f542f7e0abccc90b8dbedc9a2468da43edd62864be9f7f50149300ae6e2eba570ded34fdfbacdff6bedc092e49810a3e0e860438e3ef56f15dae6a1f3e01d1fc6624602a486d4f2494a3a81694971fad50647f1f0d2bf9e2b4580877b98917b22c55207689da27039b3e46e7f37bc785c338cd0519fffdf11c1bac606dc58f36f5a6902ae32391c7eeb9fe1251ea7575632aa86ce0bf516bc370b3b02ac8a66c2b82a5d69506211c5d3ae15d3c78d47df76babf0c7fb0a5ca3dea741dba47e67851ff66b84c8b3004f8862d6e8f6317c708ddcd6f232f78d081232ad98aeb17402a9ced35420a5e2802381912f9773d0d431544b7466f778ea3f379cd9b095fd51c2a3bb6fe7bdfef1188506047a31905a3a62ab7ddebd4c5655797b90e7fa78cc80dc7e9acb634da42540cb27720f67699e357ddcf45fb4bb9c8c555793cc885c31ffbf6674648615faf691440dc456126a5194ada986c9387e282a3e8c4efd5601f55273296dd8a351adb1e1f954a7d466e75057d8ef0f3d187cd0f8c2203967c7aa3049968ece39674260ec8ce49a25c87cb4fbdb73f1ad1981c19984c8a7fc6ec2e8dbf74889cf6ee30ad325fbaf3ce1be4d06255353742b14128c74765d32ea790b3235a3ca4a6e3adbeb39c26daf148ce4fbcb993b48f04cbbdfc88f67da205c910cc6d0c85b355689d7a5f6794990cd5a8380322d807f4282f79f2d2686deb4d598f072bfa2df4644c8f098a1c9589ee93fb48926675c7e1481de74304aadd8b104384f4df77cadf60df790a394f021889e098f960650e40b9f71193c642c2b28dc8e73934646862a9ed47763ef721c0c01be4da0de58dac976c7e52ac407eae45bf11243f741d05b90ba2a351d19f0d91d115dfb4626e2baa22a8d1a047b7a527ee81cc059756cfd529db5630068c8d5120ea7a6125d5fdc982f6dd91efa9d4f19891986140cc788285f0cc715e9b21f2175360b67dbedc68ff3b41bfbbd1d3adbade1c46083eb973876fcc9ed1e264e8213111bd18beda97fa555b1cd2f9fc8d216358fbcfe430751152c09c02a78b8437616d4326e6d9b87a71e5dc04e61ffcbad9c2dd9e2f9b28885c3b5383d968611de6be2655f24dd0cdf262e134e8cb9db1abb07d6fce167a9dd323b1b8f7232a8355d3ecb3bd4ba9a3ff17bf0d97fa29064762a6c9b7ba14b1264cbcd276d85e985926862c96e322308242ce44679502fe70654f54d41cc4ecfd6933df5eb3b3f2bc47d76e85cac79393bf6d77bba0164f6f06922474c9c1f9ab86da8051a7ceb0a29aac113b4d1430424e8e498a6dc40d46fd0c341b00a069128f37e56a25734e9e446a500e6790ddaf9acb20f5f67037b2267bae2d4003e1f6104067ce5a360e031cc604dc828c7ee79fb9aa5261e14f473d6b5f0cd365c5dbaeab2997624e705b0a09650bd386b78bb38cf7e5a3cd67aee3a985bf25fd1017d3f1870d726d4f211e0987e9251ed9dddc27f5322c68254850b4a4845f1610fe728092d34f6f9b55af7c167bd8f5939f1f5fecc9d1e375f97961a304c775c36bde5c065076245a9d6bc90c8476d958d00f5421f869c4109f6388a8c905850ef8cd80927b44eeb042adfeb13d808dc337b0d3eb738782fb4322becff76b85105e0e737dddfbfb423c11bbf3bf93aeda6af3634ad5d2d49b5d36aa2d9c72537a69fc0db81d8b033b82c8921b7d50a51546415e51e7e5a47f3c71c5da157e25ecb701cb9128400f0a7fe4ef801a306ee61c2cd975143959f7ee2df91fdd3678719597df544a1686aa9a81b81cebaf521deeab903c45659b270b5906698af28afeb37ced3362e43a0adeab50e2c9a2019f338aea7e29195ad472467cd35fc8d7bc8e5e16f86b273e5af3583718cd0967b32e39ede17770e77abc124b0879e997caf22ca684cb60ca3860f4f2525a989434b132c2ff173383c74582cba5dceea5d947263b6980eda24555a778e8d676d2570e5049d38f386d68b13ef53b035a83364d8247a6b32627756bcedf14c9dafaf82a4af23b232e37eb4b4b36f4bdfbc9ab5d1a963bbabfec682c548789b2ada1d73f283aa8b98ad214c7e509f5943daab0b54a5f9d94958a0e3887feb46afcf00bb0202794af85caff85580f7647fa3e0a9183f202487ea5ddb661416be051ca0da39769fe2f99793509acbfc3efa82318c69803f386cad629b4160a33b743594b0e379b7e9d483c2e5d2dee40489b306981aef5541a8639533f46e058b83ccc878600a43f1c97e36aa1a5b65ad3b2dde0362e35063d6ab2018e2b866ee1d13cc204a2949ec14ff98b36408392751962c889e975de56ac5bf00ae7df15768f02d9243685207c530531af5b4d838d63f418e9261fdb9204e14139e7890e290c047a795dd7aa9ed45a2ae86e0a20bb1489b2366d292b5c8cd2401c5039ff21b734600a046696d728ba8e4e9697f9ea7cddcfa1417272b61689d9fdfe5f95c626c92d6ef364447505e6188abd7e544838aaceffe14768e94a6e0ecfd4e5c6b91cfd80000000000000000000000000000070e191f292f373d""") - ), - new SigVerTestCase( - TestUtils.hexDecode(""" -fe28a25123cd888c478aac1d081ea7efc0ad28c299b7cf879c70474654b0bfc8eedcc03981c72ec5378f14a215f090573a961409c287dd8bb9e17b83d8336b047bded3b424e69fb26e750f5f98a9864c906d82f1ed3f136b22048ccb9f3b35c1c184c7f2646fa81ee83701e854b42e3c6d69cf329f742155b37ee4796e5626681e1a56afa9aabfb79eedc3241423864e67e579ae2dd28927246935ae35aa191781800b4133e0e8491e134410da8b724d7b11719721a454e468eb33baa944c28547cbc9cd85b909dbda3c83671400b0de43dab70b1541c97937fcff85510a80d96cb7ecc9f57942d5416f87d0ec5bd6aa0b83ee64a57e64f88576e5560474db63c12166b62b62566dd79f3e4752af1539b09b4f71da54331b00c854e9a43199110889ad7aac60a224a58df58e997792627d4e22ef649ffd9e4853c39965c6a252330109a9148a2d257e6ae7659441abeb74e3528eede0bba8506b8c8e5be6d2d048c4163d161708b4d28175ffa2bb4d226e4510dc3da42c0d8b6b17592ed49f3948ce18ca9d0d8885c2933a3fa3857179f4ad48f6bc834ce21e4efb3a4c0c255b7f826b9525efa9ad6a1899e01c72c3ba4d78247e41b4387df8e664ca190ad641928e58cfc20b94f20b42cb2929c56f61057e85e638dbb09b8816948a95f515992a38e4d0d4419b0ee9884aebcd29df37bea8c60c59fd091453d7f816ba2b6173aa8a684e36bc79420bc640f3f6ea457dd7aa633389a536e6377ce182ab2fd62e610f51c135b549565d3c5dfd5aa83783399604faecc2c4fdfee1c383c8532a8442e004909c24bbd6dd15f2aeb8e3a2c7de11488b08f23453aa38f8689d0e2d80717f38c68128755114b151f2ac8aa2ff6d8f54770c8dc731074391ec6212140ae79c160aa2216cf183fb86f829c01bee4ca9eeb9b1a534a0e68000ebe4d25c5bda0d3e264f634ed56f1ed762bdca4577646344cd069c8947ac1050b62eb43f0ed7d276f5a1eec4a620f5f160e66b11ef24a7fab0f500c7fd1d5831c6d1994f871216c812bbd4eadaa5050dd2e59edb14b6095c51cd6715db572205a644884bc28fb1ca2e73ed5df2a668abc255032ea645c11b85ae3103119d3089875148b1ebeafba87b0560c22b6bca7f981263541fba14cc4416f20394ecaae798bdae4c15962850d49ea1b3d99ac6ae25bd803437703854f514f36b30e73fb59c97d8f542485a434b2292992e78a73d021f074a11a14c9f95e6eedf86a986afb81be2b47f17178de4f21c287f25600e39147608d8fc3d5d8cb0d6409b3a42feebe1dff95b3c588935713c2f7e8f9d3c0a0546c8da656910fda9eeb4415dfbae2f90c9805917698ebe7866b96984ef22f9db48c81deda5c17928ee0d5dd9e88acd2f5147a9d8281acac581b0a0a5028014decb33281915de058d53fc75932fc1a0d4e349c75a7d1313f9ff44bd3c1e9f057bcbf6c0f889bbb0ec75b967de1bc7246eb91c515f8ff5c2ba15ad9df662e29eedeaa1a137a4c1ae62858c583874ce7b4179372289e9331eb8ef3effdd691b8d4410977cf0962ab9f5fa882faef80a2d2334ddbcf5301770197a713625596866432e342f11f6bdb51c6d629dc0cb159c986c55906497ff751a532d922380c3f0171ce058eb25beea093df5e2a45ac8546d815ff08babdf1a0365fef8e12d59ae04f0cb6c373d4e213ab8386b7ca98891c3f5c6c6bb2f5396d131ec9a173a5c2e760cbd8840ac3be5cc21d837d44efb33412a572853782a7e3c6b8f438e4a842f7db269f7ea339ce80d2da2bcbcc8c8da5e68588e136894e4bee6985934ce772fe9250ceb70d5902a49efa797bb3fb0b7021a80daa677807332bb4cb866918892c7b497865ba4df6cc56121315f9dbbcb7d82c9b1986c5ed428cc257b4087a27f1d340bd6e22506985b8b456bd3d726113d0b190491ab8296ce2725a2c62551924b1a85aedff7c3cd0f1b3f5fd8a8b0c1fd04bb5606c3ee0b3a5c8cca67cb2da6ad7eb74be8db03e91f43c315d4fae4d93f71a8eb1be4a54c6d66d44c203fcec2debd53debd527b4d61b2bea59b74865075de444839ee09fc9f6405a0a91021bc328e7aa8cfbe77ac8b49e049c8831689f52d29a7db38ece3f04b994090c636cac358d215cd36f55f44e1f99675137e192a876571a1271e7aae73443f0b6185d918f9b1bde15d313c1eb3c71bb01b98ecd764a1cc1a7c54378be4e3df310cc0a8297283b94bd45a53f19e55c18396a902c906e2f4249b5213a76e547e10648a48498f6b6423ecb8ecdcd707889092f38c735d5b1255670d121e16091ee2571716497a72c4e851beddc42b88fe4ce51b7084a8e9eeffeebafc1bff1bc787b8b289d793e60502880e7c4625f4dfcf8d9e03cf606b0d08a36522a7707985a1dafc3e16683bf1e6c7338b9f5959d94be1e6b36b5d2fc7c5476270c8b4a38d6b8b8545a88bf34e91c765aad1f753b717ddae316df7913c6cc1d02fedded7ca47464e236fa9c627935b0df1cbb6b3f87ee6779afbda2efbecfa7c5ee324f7037e99d65175a1786547659a3d3e039d9b2dfd48b52a4b676d282701e62c895ec730df929c439cfa55831d13760291fb2e87e92fc3e3228daf16c93b3cea4da2a7b089e79d5c2698e6909fbceeadc461180784c83d5d6857e7cf50917143970e4515ad5d19a9d4836ba201e356566dd1ccf5694feafc9f6b33e734925ed69e82f4821e7359ce6c2b5d9fd2fb470fef5cb90336befedccea1a0ecc4236de6e980e584cdde0796c1118da083cf0b064e91898529c486774440b87af2cf8851b455b072f011b008fc9deafdac5d1401653a989babbb5e0aa14e7ea672951d8c87f7c41cbdbe66eb9856a54652027efc81cd20195a31106fe3dddd23671924c58cca3109611cd74e8b212058a616b4571b5f48c8b13ea3c0d69eccf41734e6cd2e4e1502741577982d6ff5b213275178b215019ed430600a6b940145031d3559a83bb9321fd89d98a3a382ac2e3479fd91ecf7dc31a7732adb04d28de1549b96d153f909eb10e024156c28842a3179aff185f008244143614f96a8297cb553141d967e675fe09873850bf28cec3eb8c519586c220be8f365aed6401beb68235d87424d9ca06806a5b3c00f7fbafb951577ce79de9dcdb7e30913815f695d1267e78f72896073f1878fedc4924f86aa6149bcf2c69e9c0df1c2aa17f95501ceb1d9f074fe9e41d474f7f6bf73d1d993975cf58946d02b9417b398464e9239bd446bc77493c9028916ac652692d80229d20172a4c6b86b4573b407ad836d0e01358216520a442dfc2b302f74c16e06a087f46fb40ef6db475754bcf778ffab7b8ef8dfad3af69fa91537c34da59e0727b13cf3d45d48a5af9586471b7db96cbd0d4fcbc5b699c1b549ad74f43ada72884816102bbb41a5063803c7aab173ef368815bb5fc4621b4ffc290602392624ed534aa52a1b51247c78e79edc30c2ba2ac3b0180693edfa1777316b6b45614aa768edee575a6b2e57b90a0137188e83b18bb53f693124c8c84ae595fb5c24841b8d1696117a5ae94b487cf3e56bac558e2c9569d71c692aaba10ce9afac91593d3a2bc9348bc26b8a8620ca43aa4d17fb28c475d3211422a0450cc0a4f0577ff9ede1368f3e2e8cac80877355"""), - TestUtils.hexDecode(""" -4F4C7E0134BE5200C4512299D134770A64A76B73A82463FD8C86594939DCFD9DC55B895B32A2E96B8AFDB8CA83AB857679C372CD88754CD8A7B0A31D2ADDFD7D1BA64556AAF1CDD674F3E8F5FC0BAD2FA38326365918430AB2344CFF785D5F73F2B5D631DB29FAA0F9CCE5CB7FFE0CF4AF1C7A8950EF32F1D72080A492C7A25ABF67F409FF5D4B1E0D77268C0A1B2A32D9DEC61BB71EDAE6BFD58F274707182058F0E6AA31E6D3763732A82BD6F2C76647C7ACAAE7FB4AA51125F0D2D48351B6A3FC7FD18172FA8689AE1602C4EC0CAFA863AA98BDBB1CD8C2681C2B6C5C254E346C18E2A270CAF2606A6504D30C0E2E505C2FF9D18523BBDF21424C645AF0EFB2EA0FD21B5D0CD85C7C1EE176FCF904B481855C4CD739443F3340AE48276E7F4BDC00CD11C2B0D6B97BD00AC962EE1FCF8A73D3DA3CCBB3B72095CB33C5542D86E843641CC98E27545F99188AF064D5FE74739C54F5678F411D96A0EA043652935BFB2E37EC934327C7C841CB0CD04EC17FD06A18E88882177B51B00DB6EF1DA164245A3F2554CEDE8C84DD777F0B92CDA456D922D8B7B8B63B548CBB72CFACA540C0D69F9EF21759F243CFA03EBD6B080D23DD62945E623BC4F8323DAEC1215B251C35EA13A0F081B86E803BF37DAE6D913B7D942BD1C276ABEA3F8F74D0C8727EC21EED2AFD438BB7"""), - TestUtils.hexDecode(""" -74bd615dc15e9ddf76b9f9bfe3092d48d80a2e8fe813b8b54d48297a3a3cc255927f7d8eb3bfacf8ba83c73455ef02ad7fb58606a401c0b29d8ee5c2146dee8824eed0d40dc886a5a0f4cb73a0a25c563fb78d9b347c1b0677d5b1f4fd9b01cde28958ff5ed00199921e2d72a63a4d5a3c43b9f5a47f5e80dcac8db898353bcdc754e89b0fd3279ef60fdc3114761c611f5d51a7c4ec9d4a3616376956a6b755d2e162db6df7c916d1054cc9e624a7b05fab4ae9080358497d8172b90bd2fdd8219e86663deec82ba86c2ecf63624c5d7aeee9f1ac56738c58dbc87d968fa3ee5098c51188169b188120015a00ef3a5bc03c52616cd04579604cc1affd3aa92270491673887b232eb65f3c0b2135157b6e57184b10f262605c26424cdf5c3a5694beb6a74ff252df89bd7693abc92ca4998d9c644cc737e8baa2ec6380d10154c212422c069c9d6fd38aca468ac10e08fb4e49b4d734f284c3e641182276a45be15cb2a75b78d52dc63799a5a2e4e800b30871655a507c2d0b6baeaaef0923d67057574559b87d8765a4c3f87ed76f1ab5bfd5eac40870dd7510b3bfcd84dd9ea15e5845626319e5faac3255bd9aa7686aef2410dba1221f67b3a649c5528a7f87f0ce8556e3f32d5c48622844c113454d08855d8a930b1c7d68522a9d284f1970f8944ed9882d515a877c21d3a85cc247da447d8005d72b688cd17490d88c9028c140f70052416815331fab6c073ed191288bfeebaa7325991edf0ad3520628f91d6aad43411e7ad0f8aeb6825f9b9d63b2f7d5c0f18c67d58634a9d85ef2a932cb231cac3f057656ad2c0e87a35fca332f132b68d60e39822409657c06dcc1cc92fae42a6c940c379e1fc61b6af60022a76e52c1a73033d6877fabcf9b17583aac80b5922148aa45434fcd0212634d5009aa509fb35e57905e033fe1026cfd4e227861d5be4e69838a92e070b96e61c747596e3bf27084e804dbf380aacb659ae79cc4c17f20ae64117088e297c82b8df7235974c4eade96a4567891eaaefdd7fc8ed1185a8ada618e440c4b85b698028f7ba29d46010d2f965d357a8b469281f5a2d3ad786092d5954ac780793f70ec4ce0ba58b2d755c590284c0062374d9a1453119d78b900b33d0ae9a7c2becfb014516d6b5a71da7c16c9215008cd1fa18b0e2d4b1a189c698e0ef49d230b7b284283b54cf907710730020e4c64a935ae5817803ea1f295f19464122c952de6870cef17bb4830f74e253ed99fc9d39618d1755003ce2c6434d5b4815a791df5478388dc9d6b3a72fcb326b71163922a7660304a9b9a0dc3a4df7f7d1d12fca8f3337adad6144add960229ed4b0de6eaca288ffd38a0a0ed6e0454e95527c18efbe3a3b4a18885e5f568577d903583ead64d60b82175aa2b19e100068bef823e2e8972feb348ec9f315b0a46d672d17effae1b47d60fcefef137956df1b4addad9587f6769269ba0d4e8d90090ddc2fe579dcca0980787ff8e41837e4306dda5f10d3f63762cb2f1b88558e749402b37ffa8cc75dec83fb44a6ab62260a15bc5f6e55eb7c1bec665ff4fd2a3d6e5360b3965187daff84ea0e42ebd3c33e57be120002e17e27d23cc5db3519afc91d9a6cdfb04bd7ee04a69ed087c4eab2ceeacbc0a0f4d6997f8471cebc6552bcb17e33ee72a197b5025b1499b1a19183fbca863b749758023dcca325bbf934fd1eee220e10ad10a49a3c5d861e91fcccde741b28ee26065812b371e25ade89e9a4bdb74956b9763ae2ed876b012d9c9e1278845806d9b22774b107443293848f2c510ea69fb45283ee91d08784c88f31de801244012ebb472b1a5032ec6c7404a03e6ba6c804aaa7aafacb204e3dbf5b9b7c455ad35a976706b0b217ddb0009562daa02a09e6a16484d4d85a4b5e5760b8b7e05c5310cb9eb1302447fd94b64963f64e2f182e5cac29ccb93233d43c398a7adc0d782da927a5978f7678b693d3c91988eee0c11f8614d351f48a3b35c8a5d1cd343ddd8f913e91f82f13922d84fe4a1c1599eb4574d1b1c3b0664695ad132627f8e24e0422caa6dbc0631d44244eb1025020f3018a14629eed3ebd1020b65ca21cc46480d958f67dff1926f99c7eafc6ff893dff9d804ab937dd9a5249d377eb2a9dcb8461c3a45e010690e8179343c8fdd033a2ceef78f2fb158087c93533d3b12b0d02417eb067cb63b3f961f56f7924d549e8a4ef12fbed383997e41ca1dc7ef6bc6629c947ea1a4750e3de3477c9d278d35f109f877d8af9dbf8a5be216b7a3511792efe170d79309910206de37a69877079a6d74b2a46192bee571b47e64a1458f590203789137bf3fa3a11defc15c00b976ee977e97a173502a3c13e01d1ab7c385f216ba812263096d0ef9d7c0c61dd2656771bae1edd5073e6a0e61991e4c163b5f6847231dbc2dbe261cddf6f31b614158cf41c3baa1e9b82bc2c4624f1be8322fb23f94912c2b89d82152e84f19ec84eab678fc79cb31ab6ffc25a56056066784fa5356cc4a39b33ee83f41ace4e6ba647d43e5717137c294093ba7c4d5d2f462d63b9ee0fde8b02d430179c84e79c168dec2e0a24578d067b6445972e0576cf5517284498e061ccc215898e15bfb1be5d8eadfdebe789188852a4e596474c0aaf581ada0f472ccd1a1ba6705bbbc6b938e2bf0b115557d73c3f456badae8422835bd12fd4f5a48ade113261eff298097c33dab6320603d813a198bcf6cc7fd9ccb78cdab417e6a8047e11867c91ab4072763d5e63369a58e8a3cd53258aca1c13f153c226a356b3c111a6fdb0bb51e5e6fbb400584fd4258bec8ad1b72796f0920a316564fccbd05e9bd5dd98552e04abc6a402ca47a9ed76bac30bd66df28aff95d7b86d95377349b7ff0a775b32dc5d6f726d16821c217f9deec62138e6b7b659d985dbbd57c7af7d6d0b8d234b47b122a02ea2813bfaeea52fac4100abe3567b18640f0e39828798b9788cc51f2cf987cd41602291195d4cd1fa1d1f152a2130fa6631dbf21fa1ffd933dd9137f7d1cc0c7fa133d3e4d04976ad8270ee85887b3d630576b45be5f2600a5c8159cee9154d7a0e4acb1bac445c033e57827908ae303d59564268f14abbf4b616e21b944c907ac9a30646f37d53b6d512f9c3212254d35e87aaced28d5d3bfebbb3c9e06c806a5b2ca6702e276c74d9900e08f8345001b1f720240813243c78aeaabce954018ddeda0ee6b1d7638e97b6d5b159984a901f297f10921a681ffc28834cf5b51c9fc761d327ee9585bd88c425459ab657095f793c8f07b255c84c5a0baf15c6cbf14335031347a03d11ba6ba49536d6812ec4e35dff2641bf4782f3c57d2d8e4b0d5d16b339caa4517ce6e8fe2f13f7d9837adf95500adcde6aa4191fd0cfd66f866c520ad3871f4f3bfaa5d0b8b3e1954bab44ac6b26713d2af52133c704d5237a32ed5e8ae69b897c29358c4a89ebc7431aaa97a031bf243e1a41658c8de7ba7e769e73b0b57a5b53cca25993c43f63244789e41b9be75859efb110390b8cda0aa314f96bc73b176d8cfe5f0acbbfa245ac49aeddc82e2fcfe9742c26a0f6128afbfd02ced63b67c26ed4755ccac4bb26963bf98f29c5146dbe5593d7a5b372d726d23e2947f6d98fa34454f6b9271a0fff5bb32a91b9140ef7e1751b3efe5571629784b271bac9d4b48c7fb0ac426dbd46dbf86aeb137a8c9b0d3025be5d71d7123581ddddac339535825eec433455a38ca8c6d6ddc59f12f6b4fe4e5ecb35bb3ad77a2bcdeb5315dffc072ba16565ae879e52e7652c9a45cf8ca840e913cd71dda69a81a09faaeb51a44f342812df6e88ddb34ce2e6a9a39b72d8128dd973ee94d6f86ac4b95af05940914f40ff800c3b25f3ef7f8a0261700415391ff4e9f8bca688b4ada9639da8e0ed0c754eee0e1d75f7c4e148971e7a72ab0233ee2aa77a4cfd345fa3062b921a9e49d444acafeb8c7796725dc84f2e5629b91f876fdfea92484aef3f28f9645973b47e9c607ab78877b035f64b8df0789fcab17f8d7ad2bf3a30bebd4233dd9ec3761bf23ff636ce7262974b332cbc3033c38bce5f9452dcfe3ed46aa3ae7c2c133160996e93a83ac01c4a50b0bdb0d6fe30c0d2b88122514aca33083a88b86768a46d11808beaef3412ba771eb77a17bf6328581d8213c5a7271adb13ee318f6b11624ac249857237d13c4308fa3aad7e148d0fe8b7a2c32ec48db9c2fc12fc536f5e9356dc83a8b57fc082a687a854ddb1aaace41e07845600cea04572c98a2a5482301d6c6e77be14bfb481ed5d36d9ead04ebd29e2c72f6855d4e13c58b338608923ff7ce5d366dfa8692b92c5356b6980d7ba133a979cc5f0e5fa066b575b0f7fac0e4eb0b531e404dfe328ee6ef263fc652a5ed151585d7fa47b11edba2b6ea5aca517b2bf5a38785caee5096354f4b703b8f2b6e2e7cec9b3c4fe09b0785734ef10555eca3e0fac89bc0293db20f64891f4b2773e2a2124e64ca5e5904c5d17e5d8dae7bd268c8a537d6fb7f11287a49e63e028186f9686b3bc6ba6c55a851f28804f53a0bd43098a63f5c005c4d3970cef231379a46561d41a94c18b2141843896a3644f1f19675ca47b4bceb6da613c0800c214df0c543dc6449831a7486dce0a6f9a349a4327209ffd5d240344912fe4315d9f38ed9e9995c814864de81e093517ab59e4ac5ff9d3c625c2e3db325092eeb5dacc6c3e5e3841b6df280543ab79b7edaa510dd39fdc44640b37f1cf44160c067432d32e4d83e60064e803a7c2bb5749e8cfb4c65f4fd515a15db304930279e95cbdaf3df8960f59ab547d527031d3d63d94d937a3115d3405e622a3f0a6c14c8aadb7464d5da999f16b327b61e9ed9296b0a8ffa10bf4ee900c2a3b55ac356f98076b705a8712613844aad76f961cf4829a1ba18238f2265a08c74e0f7ae875c19f70e9f73a328e48a7fd22e5657abb9b393bf766557fd834c6e81b07e1d1d92ff689ad1c794a46e6eb85f4d342caf54a0ed148ede130b7bbe1f1c2e868ffb20ea9c20b45f0311b352b85055d3e162944c91a89d00f2f9cf0e9a93743646379eacaa4ab3e54bcbce08e4ff015d0c424462c2acdf08c747fc3b7c7baee4e909af894c09395b570ae516ae687ac6d75c695b06fd8767b871ee41113b9eb7f5eb7d0d46d88369fed3148798736f31678d06b0d3402bb1577dc0f3f19a0a2f9d101a611d1b33ff99aff52937fc21d44e3f2c293d37b9a901ca71bcbe03965f2a458069c9dad2310b58a0c5662dc113d7ba619ce3e2b66b929e6770ecc3f6026e9ccfead7df2e44cd7e7fae06683a4b5c0a3a77bad76c8754133d7c548bee11be8cc084605f24668b294a6a0a633c7fcbf3822443a90477c8c501fd33c8778848f049a710971853bcbc2ae666493faa6426a96483ad0bcf8ed0c4ef0b58164b202650fce31b3ab76dc96edf271415c5a8b0414d7f60a51f01818b4e8c4df3f35f51f7738ffe534b2f9c2fe2acbf7c5e272a2d1fd4996ed30acb03abb0dee3e099b0430dcd620bbd639f3fb8b32d66c02dbdb262596c6e177d4aa7f74a959e90bd1dbfc061363870c42bd573abce58ac853b85766cd52724f158be47d62a90dfb5f0025e208c9daa5a386433ef5072da5d8938ed6683c7131dc5b0c66a4c4c2e14b04dea6fef564dac183478620e5c0ef74497974222f2788c84523ebc5391516ad6dc540095080042a5a52611cd4bc7785fef1768737ff1d9775a29a3a442f97dedf434d0fcaf2d8ec4931960e5ee03b91c6b16bb050bd9b64c9f8858958e1e6884cb916d6fe9643f05887b97f1696a7c111fc949009cad4f2ffd42f891cdb39292e9183b5eaef8c463a9226e71cf2ea4db2a6c66b7564b38aa04ab38d718aaa8ec5cceb4589e4f72e31e80910d209296e4342c65fae64b55be04a8927f0b9e7bab21f37af331218f43439087bd67d639bdeb92c3f774f7fcfb4fb33171659e00f03537983cd481895349a534395c40addddec7404c6adb90ad2a049ee457528a40821d4e57b94224d686a7ba70b5b2d35102b73de70870bafedf2b30ac3fb7f26679a2471afbe8f9c0f645e7d50d2d9b1e921ec8b84a1493e96e3463d1785b452a58077bd78708c1b54a96d8cb5b186e56cffe16f6ef668ed05cc0967305b409714679cd775168333d5042c9ca581c3ae2ef99e76fc7c42221c2ce3e138bc85e202fd3136c35613396fc259c4e223ea528bf7e0d7a48ee2ca96bb81e687813bf2c04dfde469c649a13816d3ea3e13b2f1fc1f6faf526dea7e3e39715ea1d6542e1a3b007fec2051531404040d929fa91c88a73ee9a717a93df44430598fa2d5922564a73b77651f24a4265c83ff09b25daf7c1b682da1498d5377ec73b00b408a4dcc9bfbfeba175220a6928623238412f1937228e9daf416a6c9aeafc06083d4d525c8eaf1f216299aec3d7e9ebf4193a42649fb4b9bbd7dd27367382849ae718394d86adc23270737c8fa8aebbd4001eaad3e4e700000000000000000000000000060e1822292f383e""") - ) - }; -} diff --git a/test/micro/org/openjdk/bench/java/security/MLKEMBench.java b/test/micro/org/openjdk/bench/java/security/MLKEMBench.java deleted file mode 100644 index db87c24b48f..00000000000 --- a/test/micro/org/openjdk/bench/java/security/MLKEMBench.java +++ /dev/null @@ -1,835 +0,0 @@ -/* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact 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.security; - -import org.openjdk.jmh.annotations.*; -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.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.InterruptedException; -import java.security.NoSuchAlgorithmException; -import java.security.KeyPair; -import java.util.Arrays; -import java.util.HexFormat; -import java.util.concurrent.TimeUnit; - -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.MICROSECONDS) -@State(Scope.Thread) -@Warmup(iterations = 5, time = 1) -@Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgs = {"--add-opens", "java.base/com.sun.crypto.provider=ALL-UNNAMED"}) - -public class MLKEMBench { - @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"} ) - private static String algorithm; - - private static final int TestsPerOp = 100; - - @State(Scope.Thread) - public static class MyState { - Object[] encapKey512 = new Object[encap512TestCases.length]; - Object[] encapKey768 = new Object[encap768TestCases.length]; - Object[] encapKey1024 = new Object[encap1024TestCases.length]; - Object[] decapKey512 = new Object[decap512TestCases.length]; - Object[] decapKey768 = new Object[decap768TestCases.length]; - Object[] decapKey1024 = new Object[decap1024TestCases.length]; - Object[] decapCiphertext512 = new Object[decap512TestCases.length]; - Object[] decapCiphertext768 = new Object[decap768TestCases.length]; - Object[] decapCiphertext1024 = new Object[decap1024TestCases.length]; - - Object ML_KEM_512; - Object ML_KEM_768; - Object ML_KEM_1024; - - MethodHandle generateKemKeyPair, encapsulate, decapsulate; - - @Setup(Level.Trial) - public void setup() throws Throwable, Exception { - - MethodHandles.Lookup lookup = MethodHandles.lookup(); - Class ML_KEM = Class.forName("com.sun.crypto.provider.ML_KEM"); - Class K_PKE_CipherText = null; - Class ML_KEM_EncapsulationKey = null; - Class ML_KEM_DecapsulationKey = null; - Class[] dc = ML_KEM.getDeclaredClasses(); - for (Class aClass : dc) { - if (aClass.getName().contains("K_PKE_CipherText")) { - K_PKE_CipherText = aClass; - } - if (aClass.getName().contains("ML_KEM_EncapsulationKey")) { - ML_KEM_EncapsulationKey = aClass; - } - if (aClass.getName().contains("ML_KEM_DecapsulationKey")) { - ML_KEM_DecapsulationKey = aClass; - } - } - if (K_PKE_CipherText == null) { - throw new Exception("missing K_PKE_CipherText class"); - } - if (ML_KEM_EncapsulationKey == null) { - throw new Exception("missing ML_KEM_EncapsulationKey class"); - } - if (ML_KEM_DecapsulationKey == null) { - throw new Exception("missing ML_KEM_DecapsulationKey class"); - } - - Constructor EKconstructor = - ML_KEM_EncapsulationKey.getDeclaredConstructor( - byte[].class); - EKconstructor.setAccessible(true); - - Constructor DKconstructor = - ML_KEM_DecapsulationKey.getDeclaredConstructor( - byte[].class); - DKconstructor.setAccessible(true); - - Constructor CTconstructor = - K_PKE_CipherText.getDeclaredConstructor( - byte[].class); - CTconstructor.setAccessible(true); - - Constructor ML_KEMconstructor = ML_KEM.getDeclaredConstructor( - String.class); - ML_KEMconstructor.setAccessible(true); - - Method m = ML_KEM.getDeclaredMethod("generateKemKeyPair", - byte[].class, byte[].class); - m.setAccessible(true); - generateKemKeyPair = lookup.unreflect(m); - - m = ML_KEM.getDeclaredMethod("encapsulate", - ML_KEM_EncapsulationKey, byte[].class); - m.setAccessible(true); - encapsulate = lookup.unreflect(m); - - m = ML_KEM.getDeclaredMethod("decapsulate", - ML_KEM_DecapsulationKey, K_PKE_CipherText); - m.setAccessible(true); - decapsulate = lookup.unreflect(m); - - switch (algorithm) { - case "ML-KEM-512" -> { - ML_KEM_512 = ML_KEMconstructor.newInstance(algorithm); - int i = 0; - for (EncapsulateTestCase tc : encap512TestCases) { - encapKey512[i] = EKconstructor.newInstance(tc.ek); - i++; - } - i = 0; - for (DecapsulateTestCase tc : decap512TestCases) { - decapKey512[i] = DKconstructor.newInstance(tc.dk); - decapCiphertext512[i] = CTconstructor.newInstance(tc.c); - i++; - } - } - case "ML-KEM-768" -> { - ML_KEM_768 = ML_KEMconstructor.newInstance(algorithm); - int i = 0; - for (EncapsulateTestCase tc : encap768TestCases) { - encapKey768[i] = EKconstructor.newInstance(tc.ek); - i++; - } - i = 0; - for (DecapsulateTestCase tc : decap768TestCases) { - decapKey768[i] = DKconstructor.newInstance(tc.dk); - decapCiphertext768[i] = CTconstructor.newInstance(tc.c); - i++; - } - } - case "ML-KEM-1024" -> { - ML_KEM_1024 = ML_KEMconstructor.newInstance(algorithm); - int i = 0; - for (EncapsulateTestCase tc : encap1024TestCases) { - encapKey1024[i] = EKconstructor.newInstance(tc.ek); - i++; - } - i = 0; - for (DecapsulateTestCase tc : decap1024TestCases) { - decapKey1024[i] = DKconstructor.newInstance(tc.dk); - decapCiphertext1024[i] = CTconstructor.newInstance(tc.c); - i++; - } - } - } - } - } - - @Benchmark - public void keygen(MyState myState) throws Throwable { - switch (algorithm) { - case "ML-KEM-512" -> { - int count = 0; - while (true) { - for (KeygenTestCase tc : keygen512TestCases) { - myState.generateKemKeyPair.invoke(myState.ML_KEM_512, - tc.d, tc.z); - if (count++ >= TestsPerOp) { - return; - } - } - } - } - case "ML-KEM-768" -> { - int count = 0; - while (true) { - for (KeygenTestCase tc : keygen768TestCases) { - myState.generateKemKeyPair.invoke(myState.ML_KEM_768, - tc.d, tc.z); - if (count++ >= TestsPerOp) { - return; - } - } - } - } - case "ML-KEM-1024" -> { - int count = 0; - while (true) { - for (KeygenTestCase tc : keygen1024TestCases) { - myState.generateKemKeyPair.invoke(myState.ML_KEM_1024, - tc.d, tc.z); - if (count++ >= TestsPerOp) { - return; - } - } - } - } - } - } - - @Benchmark - public void encapsulate(MyState myState) throws Throwable { - int i = 0; - switch (algorithm) { - case "ML-KEM-512" -> { - int count = 0; - while (true) { - i = 0; - for (EncapsulateTestCase tc : encap512TestCases) { - myState.encapsulate.invoke(myState.ML_KEM_512, - myState.encapKey512[i], tc.m); - i++; - if (count++ >= TestsPerOp) { - return; - } - } - } - } - case "ML-KEM-768" -> { - int count = 0; - while (true) { - i = 0; - for (EncapsulateTestCase tc : encap768TestCases) { - myState.encapsulate.invoke(myState.ML_KEM_768, - myState.encapKey768[i], tc.m); - i++; - if (count++ >= TestsPerOp) { - return; - } - } - } - } - case "ML-KEM-1024" -> { - int count = 0; - while (true) { - i = 0; - for (EncapsulateTestCase tc : encap1024TestCases) { - myState.encapsulate.invoke(myState.ML_KEM_1024, - myState.encapKey1024[i], tc.m); - i++; - if (count++ >= TestsPerOp) { - return; - } - } - } - } - } - } - - @Benchmark - public void decapsulate(MyState myState) throws Throwable { - int i = 0; - switch (algorithm) { - case "ML-KEM-512" -> { - int count = 0; - while (true) { - i = 0; - for (DecapsulateTestCase tc : decap512TestCases) { - myState.decapsulate.invoke(myState.ML_KEM_512, - myState.decapKey512[i], - myState.decapCiphertext512[i]); - i++; - if (count++ >= TestsPerOp) { - return; - } - } - } - } - case "ML-KEM-768" -> { - int count = 0; - while (true) { - i = 0; - for (DecapsulateTestCase tc : decap768TestCases) { - myState.decapsulate.invoke(myState.ML_KEM_768, - myState.decapKey768[i], - myState.decapCiphertext768[i]); - i++; - if (count++ >= TestsPerOp) { - return; - } - } - } - } - case "ML-KEM-1024" -> { - int count = 0; - while (true) { - i = 0; - for (DecapsulateTestCase tc : decap1024TestCases) { - myState.decapsulate.invoke(myState.ML_KEM_1024, - myState.decapKey1024[i], - myState.decapCiphertext1024[i]); - i++; - if (count++ >= TestsPerOp) { - return; - } - } - } - } - } - } - - static byte[] xeh(String in) { - return HexFormat.of().parseHex(in); - } - - record KeygenTestCase( - byte[] d, - byte[] z) { - } - - record EncapsulateTestCase( - byte[] ek, - byte[] m) { - } - - record DecapsulateTestCase( - byte[] dk, - byte[] c) { - } - - static KeygenTestCase[] keygen512TestCases = new KeygenTestCase[] { - - new KeygenTestCase( - xeh("796732acba3efdf731bf7c242aeeddf5eba5b131da90e36af23a3bce9c7aa93a"), - xeh("91618fe99a8f9420497b246f735b27a019078a9d3ca6b2a001aec0b9e07e680b") - ), - new KeygenTestCase( - xeh("60d235ddc4f334bfd91d6b7df1a4fed84c88c2933806f13fe06ef15aed96c9e1"), - xeh("2026edec2070fd7a2aa93c55d26aa0cda5c16117ccac98cb86d9c99f5bac2cd2") - ), - new KeygenTestCase( - xeh("c14612e7a22ec88bb5e9dcf865776c37cd5b1c6d1b18798be80b9562ba4752e1"), - xeh("3ead7c9457670c2bbf1a3d0f38d6c0838098def05d5589bebee67ff5c33b4374") - ), - new KeygenTestCase( - xeh("ed5bf4a40e4ce8d367598819be8ec4ed706df4d26819f69729c2acf274515c8e"), - xeh("f910824d75a213bc1642bcfa5a6d304e4723ce0a2ca16000e66fccf48ba0a925") - ), - new KeygenTestCase( - xeh("78981182b43d78c40b828554c36d70b960a02c66490c15a4caa6a7d5f1e9ce34"), - xeh("8908c5912b74c4f5d1b3043a95ea3fc16bcb8d85414a2f4fc134f18bbcde262f") - ), - new KeygenTestCase( - xeh("917a2234587c5969cc1ed10d51b0dcf8b3017143ebf31687930f3e2c610a4850"), - xeh("138e93b1f959dbb22c0fad45bcc828b4d4f07ea2fc109eff6adf423d960558eb") - ), - new KeygenTestCase( - xeh("df022c3c86b725c5f2b54196b7d68684b9fde93be78e38beaeef18195321f4e2"), - xeh("71668363f77b645c3278b07c0e97e7a3336421e624485f2ec35f34a01c9189d2") - ), - new KeygenTestCase( - xeh("d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600"), - xeh("bdc7be9d2b2d3d8e7e616fe2f77f8bf11d4759b8247431b0e9220a7f8e5235bc") - ), - new KeygenTestCase( - xeh("865f638c38f0852d2d712a708ffbd7d96f0df21071d8bfec74c2302ea4c5adba"), - xeh("1878346fc47148ba7523463ff794a14438c5b5e8500bb6b92b364f90ec8c3d36") - ), - new KeygenTestCase( - xeh("741a60c9f1715c42a5a9e67b4e69e5f128372002a6c4f54ae5869500171e2541"), - xeh("6078a65f40993ee3bfce7804086962e5726025b779ca7e62912f244b4162a093") - ) - }; - - - static KeygenTestCase[] keygen768TestCases = new KeygenTestCase[] { - new KeygenTestCase( - xeh("796732acba3efdf731bf7c242aeeddf5eba5b131da90e36af23a3bce9c7aa93a"), - xeh("91618fe99a8f9420497b246f735b27a019078a9d3ca6b2a001aec0b9e07e680b") - ), - new KeygenTestCase( - xeh("60d235ddc4f334bfd91d6b7df1a4fed84c88c2933806f13fe06ef15aed96c9e1"), - xeh("2026edec2070fd7a2aa93c55d26aa0cda5c16117ccac98cb86d9c99f5bac2cd2") - ), - new KeygenTestCase( - xeh("c14612e7a22ec88bb5e9dcf865776c37cd5b1c6d1b18798be80b9562ba4752e1"), - xeh("3ead7c9457670c2bbf1a3d0f38d6c0838098def05d5589bebee67ff5c33b4374") - ), - new KeygenTestCase( - xeh("ed5bf4a40e4ce8d367598819be8ec4ed706df4d26819f69729c2acf274515c8e"), - xeh("f910824d75a213bc1642bcfa5a6d304e4723ce0a2ca16000e66fccf48ba0a925") - ), - new KeygenTestCase( - xeh("78981182b43d78c40b828554c36d70b960a02c66490c15a4caa6a7d5f1e9ce34"), - xeh("8908c5912b74c4f5d1b3043a95ea3fc16bcb8d85414a2f4fc134f18bbcde262f") - ), - new KeygenTestCase( - xeh("917a2234587c5969cc1ed10d51b0dcf8b3017143ebf31687930f3e2c610a4850"), - xeh("138e93b1f959dbb22c0fad45bcc828b4d4f07ea2fc109eff6adf423d960558eb") - ), - new KeygenTestCase( - xeh("df022c3c86b725c5f2b54196b7d68684b9fde93be78e38beaeef18195321f4e2"), - xeh("71668363f77b645c3278b07c0e97e7a3336421e624485f2ec35f34a01c9189d2") - ), - new KeygenTestCase( - xeh("d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600"), - xeh("bdc7be9d2b2d3d8e7e616fe2f77f8bf11d4759b8247431b0e9220a7f8e5235bc") - ), - new KeygenTestCase( - xeh("865f638c38f0852d2d712a708ffbd7d96f0df21071d8bfec74c2302ea4c5adba"), - xeh("1878346fc47148ba7523463ff794a14438c5b5e8500bb6b92b364f90ec8c3d36") - ), - new KeygenTestCase( - xeh("741a60c9f1715c42a5a9e67b4e69e5f128372002a6c4f54ae5869500171e2541"), - xeh("6078a65f40993ee3bfce7804086962e5726025b779ca7e62912f244b4162a093") - ) - }; - - static KeygenTestCase[] keygen1024TestCases = new KeygenTestCase[] { - new KeygenTestCase( - xeh("796732acba3efdf731bf7c242aeeddf5eba5b131da90e36af23a3bce9c7aa93a"), - xeh("91618fe99a8f9420497b246f735b27a019078a9d3ca6b2a001aec0b9e07e680b") - ), - new KeygenTestCase( - xeh("60d235ddc4f334bfd91d6b7df1a4fed84c88c2933806f13fe06ef15aed96c9e1"), - xeh("2026edec2070fd7a2aa93c55d26aa0cda5c16117ccac98cb86d9c99f5bac2cd2") - ), - new KeygenTestCase( - xeh("c14612e7a22ec88bb5e9dcf865776c37cd5b1c6d1b18798be80b9562ba4752e1"), - xeh("3ead7c9457670c2bbf1a3d0f38d6c0838098def05d5589bebee67ff5c33b4374") - ), - new KeygenTestCase( - xeh("ed5bf4a40e4ce8d367598819be8ec4ed706df4d26819f69729c2acf274515c8e"), - xeh("f910824d75a213bc1642bcfa5a6d304e4723ce0a2ca16000e66fccf48ba0a925") - ), - new KeygenTestCase( - xeh("78981182b43d78c40b828554c36d70b960a02c66490c15a4caa6a7d5f1e9ce34"), - xeh("8908c5912b74c4f5d1b3043a95ea3fc16bcb8d85414a2f4fc134f18bbcde262f") - ), - new KeygenTestCase( - xeh("917a2234587c5969cc1ed10d51b0dcf8b3017143ebf31687930f3e2c610a4850"), - xeh("138e93b1f959dbb22c0fad45bcc828b4d4f07ea2fc109eff6adf423d960558eb") - ), - new KeygenTestCase( - xeh("df022c3c86b725c5f2b54196b7d68684b9fde93be78e38beaeef18195321f4e2"), - xeh("71668363f77b645c3278b07c0e97e7a3336421e624485f2ec35f34a01c9189d2") - ), - new KeygenTestCase( - xeh("d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600"), - xeh("bdc7be9d2b2d3d8e7e616fe2f77f8bf11d4759b8247431b0e9220a7f8e5235bc") - ), - new KeygenTestCase( - xeh("865f638c38f0852d2d712a708ffbd7d96f0df21071d8bfec74c2302ea4c5adba"), - xeh("1878346fc47148ba7523463ff794a14438c5b5e8500bb6b92b364f90ec8c3d36") - ), - new KeygenTestCase( - xeh("741a60c9f1715c42a5a9e67b4e69e5f128372002a6c4f54ae5869500171e2541"), - xeh("6078a65f40993ee3bfce7804086962e5726025b779ca7e62912f244b4162a093") - ) - }; - - static EncapsulateTestCase[] encap512TestCases = new EncapsulateTestCase[] { - new EncapsulateTestCase( - xeh(""" -c6e8499d78b750e516b8a67709468d3fa3b4d74c0a5f5a4b5cb94d8ca92188437040f9312aa41edcf274f0aace043862471591e84c0e05d61031d69f4fa11f4e8a0977673ab30b2bec0bccefe434b55632c6057842d977027ba616e6a7fec7340bb20c7331b4e2f1044e9692ab0136a0b285fde033ffb25543c5c9ffd83595e380f8e831701b1e16e040600c1c7924b6bc42331d987b7d63c007d76d198c0c32aa3e3663ca7606454a214821b15b8ebb018026aa1a618539c00d0a84c871c1baf016bc426b3d9be7598fd8148d63865bd6b455fb8a47562e95666e18405367d4cd581162fb878d8c0c3d627597a4811eee0963d4926861ea202d46a6a6e94e89b3cfdbf436fa2254f060ce6b80b4bdbb98da80417fb53eba8286b58644d8d84654fcae20906863fcaaf89abd992b176b05b2924bbe566728878b5e816b64a532ce2cd41f5a937ddadc15baf23023a19932b337f508c8fae504a3aa24261a9bd20701a2d3ceb3c72ebcd5807d358c2ed45d0b84092d6c93b74caa20ea4b5db66369d26fe64652270949a930bbd0103ea7d117e6160d9dfccded58476b94ae90036b68a40b9bfa61b15c889467a0a01342f843be8227ae9cfb1593c240a8735d8105a36c2b68e5ab97671b63a1cb1eb07495fd3bcb380aae66d20f3bb096b5db9944d83196b3bb3e321dc76c3b7d6828f366585f75a3c6d370f5580f22b385319483c9c19e6e81cc22690b18782c2d47be5c81cbb1c055cad84db9b06b15355697ea23a2374f027a63197b46f28a85d089a120848e94e9838cc72d1aeacf7d64ba69a93635c6a10ca5745645416e071a48056c78a50a0d4a60412966ab4961819918211a661cb839b01101798583934c9ce0aa447170b870306cfa02a16b9316f4f22d9b958a38b24960f0203cf2418495446c558a6ed8706d8c949e7b14cc168c965293d128ca16412ff7b221cad771d441ae3fc822d86645f5e266aaeb1df56a6185747e3312587d1b5f51e13e23586f9f3b1cf393bfb24173d7e27584b061f4258ff3c29d27167f58999b6b87a820b56fc7846cd3a0953aab07bcd256cd997b4e0172cfbdc0c2fef1b5fc616b03d1c3efaaeb7d48c64a0c839085160b4a5732"""), - xeh("6FF02E1DC7FD911BEEE0C692C8BD100C3E5C48964D31DF92994218E80664A6CA") - ), - new EncapsulateTestCase( - xeh(""" -1ad51d02065cbbe01bd1025aaaf94bbb2bac27e678fcd7578ef9bf3026700d711aca31cd4a9641a25286b26c034228cd906434c3e2a56f01b54a98878c6842b9bc9c8d95640bd496c0956446a0cd88d344d552a838e29f48850bec6b4667749fc4266ef8d5c47f8b21e7e108f8a58d44394c8711470ce8cfc92b2e49ea5b8b15772e4389564ac8d568b700d11eb5f83d018514d5d3acbd7c63f667ad9340b2dcfb972a333df99ab2dff50f570a4d0001a413a98f4075acc5241b5e6a6132551b9c4c1c22551b5a008df7d5a218783c2810b79a52552afa922de76dc4b89d87761cfabc81d218cc3259457316333c21bc9b650f6383c350e6681c694496565fa7203d05b0caf5a22a4ccb1fe7f00f89297f3dd02915eaa2a881cd41599635abb85890649f1a4710142c4aa4b5e3d71188562ef5205925652ae7606e30dac7099495ec939fc5b0778477be94185c649c858e146cc6750d3a1a98424b2645786681a1b1095979f2313228f96d9daba787a257f4e27a4ed3377dfbc71ccb9ddb227151203798b58f44a280c733a8aa8a631fa303b26c33bae7b088121d917268aba41cc797b7a3336f12101d5ee8900872b3a1710c885811a2d8c4f0a188d4352f259b62da152bf2a022dbb9c913c1c254a44287546c01053bfea0bbe3d05a24f1b70d969feac7c7325ba69ea981c5e179ad564e7ceb4ff38b824f9754af15664ff7a807bc34e62222217b96f364907916be6ef0cc99b014f3527572e0a6be517d2225aa6eb41e4c2a80aef4a212092bdc186598a69b4d0037cfeabfb13b9a9bc0019c5a83ee659100bd76a1da4b30b686ace6291877ab9d834a641abed635b8f3c536bd6394684ba283da1fe7797580924fa6a65e9de87bf833bd2e67c4a9e037aae0b3eb1701bc69add69127a98a5157a6b3f8393cd104c31a24ad3e381997f28c482c5dd6ec24d7747b559a29d56c0f655838fca25c4ad49e6cab35da559b354b55357748edfbca6122601a945d8611863917c48ba20d53b71909746723b4355a620b880cbb63f260ccb10db6d3809a96740ed153dfd07ba60159a3194553fa93ca28513a65b047a7350a0c6f43f7a09f3e2771f461bbba1e3508c8f8931c16ee"""), - xeh("4660985A5838041F2E50381CB4E7AC908BAC83CC1E074220C6705E3F5FBFC2EF") - ), - new EncapsulateTestCase( - xeh(""" -335b7558ac204e11a305d8b1526835e65a110d813499acc36a5409a15a8de46633bf587a706a7d388c5099c73adab17035a347b041cb82938da6838a11513c5756b3992ca2a40c91a450505be4cb4fd9625d209110888484033d09f8b60eeaca65330beee240f9861e768ac7218a6e41a1205f55b411e275253706c57b97ea650c6e69876f79bffed8759ce30df61465b4408a18bb003a7aa446642c90ea072f955f46044f4ed7b9a9b82749e56ad470b0d21b67b89cc7ac784f9dd016a9ca5d2b025668421c25a100dbc0328084c2e3367c022b60fc6206e40aab3a863ba8eb1f8682265af69d15aa9d173204533a1a7ad94f693310663212e4aa0e63f812f1608e1f9903f0685c9b9a797ea5939869b5421b87dfa1ce818265d5051038a9331168ce01971efc06cf02a59c9e1a03373a600f216f779aa73171be66f95d81808daf63a26cc3709ab58f22659ca9587c01029d915c7554946b217044e65a6c98258f6a0a2608a9cdb4c35a0e06c93b19988c221c96b79729cc227ad5c3d4f558062ca3179b8a0b6c0d6de0aaa466c498065ce690278b8980c7c567d308b181b06667f297ee9caa28ac2f5ab454b8045eea583d20993bf69359be500247b3a2ff0b95e243af49b6a08eb19c00f31f3611837cc64b85d8bc35da9466fc12967b158dba95782ab771c134f9945df0b02644fbc949cc633419c48643764e0679a690cdf0239b3aa49a58e171241a106c151b75197f7432cca3d6c133cca0a4902ed6c299a479224ec7baf4243152877adf3255ea114fa01a65a53ca47e3a6dff072d991730414754c831b3763a6673e9b8f4f7ca4d3891a33c542380cfbfe16a650ab749d79e08570629116ef7d50338f26834e298dec8abbcf588f37b428f211434666a1c6041a3a09918293fbff54d35c75c7dba2720a0a91592af264b446105bc5b41344067bb3e5943d62aaca4374f92933e3d4353f1898868d097e504cbb934cf727a9861169582bc4414e46c50c41693909cec50beeda69aadd6073fc1ca3e1a6a822751a404730c3c90a4ba6a9f4343988280eca4c4600b413cfacb8ce2823f2a2b96f56d9d1effc2d3292c0720e7bfe6aabcd8284abd8c3fe8aaee1bfca3"""), - xeh("0D643FF311D83CEDCB3A95BA0F76216A49BCA389A225396F708EC9A51BF18517") - ), - new EncapsulateTestCase( - xeh(""" -ae76c67fc7215e493c8645af1c58bec08b66f66a92346b92f873cbd646aa5dc2b9b6e4c2848a4324a8318e9983932055c4f58f42346df1da07977101434a9378d1a1559819756646eef3094b5ba55e33b596b71c04d249be4b8318a4becb008ed71000ae795ed1ac873e244beb7c4071047e83a8b3c6c2be2ab025726063175c4bab391597923d030b5a9238b131383d15dc2a4bb812a8539f9b0b0876a23ae049777e6229c1068a37ab13a2406c6f7ba4591520d8816ca3894bf3c601fdf493e70c5f4b19bead520d25cb6e8439a548f35cafe81497b297341005fffa18b99754cf199ec90504f9f16f8e415cba718318437aeac50ba8413e540b963cca2202a35e356701e177ab0dbacfe6a0c02b506fdd6436982737f903b8a8204cbb07c380340c5f1a84685392a2b62620004caea2c416e61f7c7b0e6e202d92021628cb4c10d57d5b60ba4d771712d552d1f9c6f352779f8c32fed54a8eec59f4b3177c7c3e81e3ab7dc83a396bbe38ac0fa3ccb174442ce638c6a0fc1fc9c426b5eab83d0397b559a97256b2b0817ee115b1e026c445629bf7a8803ff71aad99385a1abfdb22a3be0029503cb44b7a35847bc675f17437d9246cd104bd8608da3005e14a632d69006ed4434c80594b2909fe284203571eac04a00a120c24d050f40952fd53ac0cb39bca50c28ff450a6e208fb26bcacc1ccfa89bd7e05616a395aafd2bfa59cb541975cbe429919b32cae4b1f4a4b4b97858390c164fde76bcdb32b54b3325392c385d647b265578a1c56dfe5a252144ff1c02dc2054bb53525ce4b3bc2ec190e3ba06fbba12f06707f060bb1659607971f3726b9f59191e6e7b252602f51eb281f454f1d80a60ea29eab42752df9a3ce376467f694fcd288c9fc7851c04821b53e693208867604def746f787ada2097740ec8462ac89baf84c0d50bedb539ccab33894408c5b4b91def7955923a283677867a356b78c5a8eec308bfc982c8bbdc9e40d7695b42612ac27f6c118b5379518b49e338738e830fb6a66488b7115d24895963934688d91fa9608d41582e79e5d417ab07c81d39415fdbb870a3f503f1a197bbda81d7c3204a316392fb75016f88565a73a51537728ac7011"""), - xeh("AA28DCC71FA83D9997DD733D8B0D0394D84D33A3D3E1B74CB74DC6049628F861") - ), - new EncapsulateTestCase( - xeh(""" -59851028c33af8acbc9ff37ab19a9fbe45a0f08b9cdc2268d6e727665429f16448ed840d0a87c34c3422ed857c69f3168820b0ae998702ac6f55150ae3031a54fb80912ba94fb4bb31604492f406f654855b447b39d26bc81b0d1644c1ce2a7f347c239cecb0cf89ab14917192c12e7a694581021e96fb6868282df0a4850bf3acfde5424781c571e8857cec1f3735a464ec74d859b169142e2e7413d2a02c5e93570e3b9bd18983809129724743a1979794a2500e04a409506ecf0a975f58bb0d08b36c1733927c932e7c73afc47f81b5a87f25878d327d0c375c38d2940aaa543f46b1198345fce7b7bdecad6ad22e12155bc470448f98bac8ebb96bb34b552ab3bfe5255c6783a76425b386613a112ec1dbadbf105ae0ec3cad61c7032bbe0bcca9d3eabf03ac6f0d4c5e500348f6581876e80c531197e62071a9454947b450614761ec95bb7072ab53e81d89e47eb875263ae74ca6a28b2a2a1fd44947756c1f3eb38519c9b2d6d63197e6459bd1427f992680b1a6f1480cdb998006a25cf434346d04942732c5617245033b430b4ca726b94faee24ca54919f0842233e1c6268b4bca31be4ca7be9b52851e2ac0dee573f7959eb896b0bb18064cbb9b71585a319c74b7716de398a8111214ae3130bac5b196e6734d3cca4116bbf67ca42492be22f56b538a8532c6acf4404069a329735246e5eccc2730c2f5690c53510bb2685909015874a8125178c7fc00709b2a6720391e38a0193aa96715f13ed628068ff4bba6e74c7be095a897ba3dc50f88b2b08a353cb4c4bf382a5cd72227cb671ed74227ce245268c38874f53299604c41f15978c522e865333dd0c49cea97289813a828ca76b93dfd3987da9726f0d3492cf13ea72ab8d4e82e73a3987b336f0cd2157de0b9b4209869412b9074736867b10fa82b34e5424c5998295b6a54793e9ab119e9c68049ea2dbef55e27327080c6ae71d69374b8314ce6110369b76fa363dfc201729a700528944f2bc23c464eacf51519f0aed8160d5ceb66d10c865604b3b4ab05f1c2990bf2b5ed84898b6a891ba360af171b051b907d1245770038e379cb727784b219a3c5ce49fe6273600219bcc609c8ffcdf4acbadcb9"""), - xeh("A4BAA4C603DA1368C1F2AC552A331F77BF1D598C6BCB540D43CA1E6D4B8BDE77") - ), - new EncapsulateTestCase( - xeh(""" -861927e1d996dacb9c04c630b694150f23aa51f26bed8c744c36a7916864b5160e94cc515ae0a03ffb445245c56a434f9351ab64f6bcbb973718ebb612657d64f844df3b85bd484c473a685a0a4a94e9995d865aa5bcafb7dcbc7e9877d63890a86252c691044df94ef7a19c68056ed6315400f8bd38f48abcd09e82f0376816c0aae53a9cc61b466466b63938dbb0b1dd963adae40802216701d094c716211718943b543cbe0888b1dc463c20804c4c402105130dd7a87a48c3c3328f76a8aef2b0c7d22688e7636b88d62897809eadf1ccf2dcb5a0011998099506925dd3b74869f931394bcae43466a49a40b31075f074bda69c0ee2f7bafbf81712969b43f0beacc246b3e71c9df2c47db405e235ae97e1a99c0365076b29e593b39c485521716967751025bba279f3aab85c6bae3800f255396d136459545f192b650d3b142c383669d2547cc2732015bc4645554638284642b918b5bd65a06fb49c5fd267a90b77ac35d12da3512f44d2556e027e6582529cea194df88584190480d9b0b5335fdfa8685894514cf95386cc1cb63131dcd1022f5b568cc621a729423c0567a51313f647918368012a83816a2caf88e062a9a6064fb52d8b31abc270a01d974459b4134be74c41b6a22e72ba1c993924bc43be6509235298431c72943bbceed41a84f9b84ce21abcea516f32280a0586069acee7627b54055515604a9ba112e620783aa76264ab8136759af9dcc75718a9bac22092a645b1b5cf32a92e377ba03a6117ee842172505793f973f84cbf0fa22d3ce116ef4c1012bc69db94c7b2b461d978c27c93044f22972588af42e28dc3748299e7a098b5566d67110a036ca9c6740dac84205109f05104f80585970a7906d7bf93067472a34442780f0fd25729745c7f85198a753836c3381f0592f818916b48278e14b61f1616c32ccb987940550316462257f1daba0574223ed6767b9c696b1c01ed75484c1738cf60afaaf9b3144899c4dc00fdab36fbd792dbd4885ab3af6ed63f8394b66d0a910041b1d606923858432f81c37f57c146db8dba6775ba1899d5904f3a69abee80050d6232d858d95a7bd86ee6af48bf9c372170c7468fc024cfdd552fb21ae23b08"""), - xeh("C08584D2F5C950E371668A4FC8F527E20AF1532CC28EE6B5620729155B06389F") - ), - new EncapsulateTestCase( - xeh(""" -ae13099bb82ebe29ad44859860634d62f78fd6b26295d040f8a5c7ff7aa393d127e214aac9107ccc06d029da6a6b998736710c5fc3a6c9ecbdf00069a9eb2942b45b1626b7953886248caa59789f9e988fa26073bff9b703232859463a9335374506ac57a8c2936701fcfc0235d071bf9807e907734e6267d130c9d4b2406e999b6cd15adf7783db2309598c058a93ac043319194ba89857a59eb35fe4a3cd6fa1c9d7d46ba2f6c62ba85ca46cc8d450bfb0170f5ad6a2a0388ebe73a8b58627f6cc5e7477635ce32472a87b4b881ca9fc749ecba012187a5bdc6e9e12b668f32786cbb5fa4055f86590e00bc4340c04b8b0053b189a74d6bb22db2f75f6b32918c0c3ac7da62044db4a9c1c2b0b1ee81b5317b1fd734c33fa3733d7b37bfa36c16578cdb63cc6f73d661a35e6460b74396ec6a07111091071a757d962384940a1a2338a42fa68e81587fca304d8a86282230470c8988cd707437163cd46cb489b010d235fcb976e50b51e0a22c5662800e74903b403c025bc6df9d821752107b2e51874147645687fedb108c1894e0ac3801bc1398c4a187bea7d9949bc5cfb8368b296b2fbcf2b59c71321b5aa2055e5823f86113a1519c956d9c1793a5d52a906a5031e905a862fec5abfa0965fc49a2db189eb6bc69cb8882b703e0ab35e088340fc35812bc0a184956fdb448170a6b32b49ac0e2a65a1041d38d4512dea3fa111c7e428cdf52144ae0708c5c44382a0733de356ab556e0aa141d58cb1321058be25a543d7060252c9e87997c35295596c02bc7b926f5ba05675a5dfea5a3eb62b2521854f21498c428a23048fa38484935399bf07c64fb63f7ee793a63aceb6842bf05077d2b3647714332d259576182f0d9c508cf2321f0090a6c1cb0a5c106647101277a7b1248e74189df6b90c26a612b26555d433bac49a3ebd702e6d9649038233d6da01f77534a8d2038f615a502cca8526c314c5856a033ec97155ad79a2e2a32cc1e734cedbc6c0b94219d13bf985588400cc682294bf21183830b2bb51b87fd9073b9cb6237884df0cbb12b929f81448e5578928b07193ea4141d19b4eed07a956c34b6de59127c5e823bb8f6719ddeaf282650cfda0e26e57"""), - xeh("1D51A0CC52E85972001B77047D97DF5F47AE11FFC6C31B4AF42FB0791A3DB40F") - ), - new EncapsulateTestCase( - xeh(""" -d0f903b9113e3b18442e9b125dd762cc4bc2fde8007fca65b4817ef985667bd62bd8806563846ddf61b68a837d35859344e96ac450cc24303d9f116d502135369305a8cc8549641487f88e0f24a31c87cea974547abb569f9c312dac3fab517c85a5521d41b7eac40c62b7cb8a0776d89828e937177785a23ba0599381004c253fc90aa8332172f7366e6c756e6f266f2c5c9bc70a5cf18416c00c83dbe76a8a9c52ec5929217c0d2be88c8e3374c2111c2ac46a2a454ceab38f8d368f2281749d4109e90702bf368d6ba6ce212146d7a21a9ce6767fdba3bf1708fc359fe4e974b676bb9ee04db18b93f60759a071484c134e0ae29b135c5f2546562f6a471a826aaa3568bcfc721d707ccaf9351462098fcb21b441c81f876a7782363ef84eb9c59b2eac7f637ac205f0c1ddab4bc0868f42c4c2ffd0912a0578e9b81dfdb400a6a747c9bc8c97ba3ff8074f454367a5768d48653cad01c30212997553941780b44f3b26b9b79e6bc43cd56683dc9770a1d81ec0601e66326148f8645f820737c2479533a7cc3142341a2fba851cd304423d835bba5c73c3fc617f393e673591040876e670b94585902818883608a773e736f52c496691481b908106609366513ae14b618b8611539b56b3f466f13a5f59e5179fd29ac4ec7a92b5beb004b628e7701b11681cc61fd088a031d80d8e43b36042857155b0c5f207260bbbd30146d83a9c3c17a1bd804b56c96b01e71de75152f4b4990a001a1d8c736e39097771b819e58a2bf4498f1ca346cc851efb29c1551060998a7242c7fb5b04b6c8cf2f703056f18a9df28504752be88860507b1aa517914b278b61704f2e33cb02307a7a898e58a3a87221898cb57243000249709f5e53037728bacc7027dda1b7fbeb7739375811427b3f8c3dbcc0775442323289bd89ea0b668cb458da346dd25a45d4c9d6eb6ad98645a65794a795277480382ad7a99e85ae9e279ff5d38ac9a461d4a8aa2170136e69bb70c2c7734060421388330606763158f0c04788d79ded7b52b79abdbf891c2290b561ab4a6aa02e591637cdac7353798d9e256fd0286389f7d3b079e3e9f89ec0a68010202ca26dd2ea953f551554098ebaea56f782c3"""), - xeh("BC2D661E6283B835BAEE160D1448957AC2366DCD087176E252F81F1D11E28781") - ), - new EncapsulateTestCase( - xeh(""" -ed8034619a429573756962129b459916f158f0ecb0cae396f60c4c84670ce3fbbe119055f1a4382cf2a619c31cee5842ee8c9c6979193ba82ce9f94337306186b20a276c6d06c04f41a414c3100b31e2a2a9984067fac4a7b3c70747c55b87b2512219d62c8b51a6b628766d63d1096f63bec8806311415919336bf9d1b038022d00d1bb84387888dc10f0290b752627c2d78ca5c8475150bd925240ed94af40b43762a99a3f5b0f41d702db7cb485405d5a247ff48635ba7719aeb8a876f0986f233212c40a3645c3e4ea3b5fd02bb520b9d8aa22c4595849b8a2769b92edabb4ba1528dd067aa86b3bdb6a39985983c89c9c916b41b34018bda438e7815bdd4316f6202c0e3c73d53124ee110ee596a9e3198f24b814dfd77f0a2a7aaab3a918b64c47fa44ff018332557cd13325a8081e0002096e68a293258928896532ac5b0ef4bc28bb43f68505f8a61cde0b5ec9ca8d62c261b5290e16b22a4a978d5b141240043c9b457a89a764d9565067cba987a23d5d6b3016291fddac50c9e5581d988088a368d1c9c633bc594d39c56fc5b4a996b7c110208de1394559915138b7cd8941daccc7382b60b47770272a56f846b15c71704b8b7e08595d51658a10b348617c8b552588a20a07c6e0670416636ba0982726671d796803320e0346bea80578f7808419f14b8be67f8bbb627fe4c5c28074e1458ba909581f317e70a66320ebc5ffdab20202143f374742b77d88c80fa8b9593d74a04e2c7113101400c4afb7893f634565aeac9eb8c144a3a172a1263fbee499d7895e298b195d4caf46514927d39f430aaf13c4bc43735670e5b0350a42506621dfd737177ba3736026d314675947a1b7315844da146af84c4cfa8227bc3211895773082fa22a8c9e7c20d1257ee9577c3f36a6d3097212dc1b149421b9bab30124cb3298a6b1505bf586070f52aab80a71e17c223184b32e9a6aa4627b3b99bf089973ab53be7c461ad57317edc3b79872bc50a391a43bb18ee9bf0ca100f16409caf4abbe0239b98b16a598ce86e7c07b27646de1671e915763ec8dc3c09a20181e0525c571a18d74c74c0e798d11d22db509a0f0519c7440e6787efacb39fb35c8cab4a38302c0"""), - xeh("6745F4F0730AE3F14A428A95C9CDFE82717EAA94F65B00A01566A4DCC9ED1E5E") - ), - new EncapsulateTestCase( - xeh(""" -e782aff3f25dfd582912a662095a71ab2b81a7b88a0a0b531d0c735e84279a39713e9b78a39679cf2aa956a0bac8a8b8d6330eafe18a20890492b42ff0eaa210a97f931c8c66a4bde05ba317aa5a7c1bc4e7ea9c8a2aafeaea6216d03dacb9b1e17c30c49a58a5d21a05f37912dc336b8739abf4cb74455078655b7d6644f3d5b91f3a97b9317676156dba77747b0cb2ca21c87e7cb0e3238d67811f4e229ccce2303d358164e85a5ba766f91212a8540e800a6e5b829bd097925a01ad99f8af2b8c7832640c0e64cacf5cb5449829ef992bed3a85b3d86fe8689de552acd1b47f58b883e718c61b810a02563484e63a951927210cb5b1e740c1bc2132d026bbb8a9b2099922ea44c2445bb078cbd0accac1c22c0065b99601c07cca67ced147645508a50ba8e7a0012394cec77880a4916c653803266c0635741fe0c98812f37265842e6826ae18d4b27a334246520607dba4452ab7284300f96a01ce809cb4011df18940c6460c7a33aa34e997b89846a287af180ba68f170653e065c1475f48b9763d6bc2643269631729a11aa33aa32a14525641e4a68a61967326698be67d0fd2612daa94dfa9a5bbd3b87bf57ef75639e3c859ba8c0a90f5ac131c94a0644eae3c32811335401ca4c0994df4711c30ca05ca812667d47a8f96beb0a270f75ace7cea1047d4abc944cf71042aa092a041fb60d60976b0ec120600c79c51ce163a6e11e1b972e703ceb5c792482b01b7c617d31922f760e7465fa427ca118431727bce77c12c59b2a7cda287bfbba68c57aef92a4775c6602c87330d693bd10a5d21724ab58bcf03220a14c4463c5226b86a1fe15477e662ca03374287da5b7aa118de1255f574220d0bcc4f68b7d36286761c9ad5d9aebe422b26e95f1f5b67bc012950572374fb8e19575b2a7b911bdc8130d737d4e34ae721c76d131baa9a2f47e208c668215fc2c56f80b16a75114363c3a04918c0072d61f19d22e55d9d1cbfc9210246e12a530ab7c8a7633ca37b20789125573f866b94d872af914007c3ccbe898ba697f63d15b57b2aaa10145c5bd71966d54bb8728b531c87892711e6c0f2f1b554cadd3cfba90def490f706c74c451248631333f0b3f2813fa"""), - xeh("C3ED79224CB07A8D37DC9C789BC7AC8E278968E429087E5B2C0E878934DAA53F") - ) - }; - - static EncapsulateTestCase[] encap768TestCases = new EncapsulateTestCase[] { - new EncapsulateTestCase( - xeh(""" -3189cdb94a4e3048a4e18621c07578243bc5c017af25da2ffce6abc3194c510076b1d0c5b5529a80b3abaa9658de03ad1e151751f54998fb77ac52a2739b09c4f0ca0b8827c04bc280ca4e7d214231547370e98b92006270194ec3c79e96bb16550692f988627b496ea4f4cf7e9511c014c2ef89ba9620896785784fec1da3458a6f5a11d3840ba4f8714610200d3a276679a7e395488d770cd5122d17b37652a9871357594a87662aeb3befecb0e82513ab90b414d60c66fc61e4db22a2a3668c05338ec86018f154c929af387183079a59e201cb512536ea4908dbd559dbc63aae57cbc40437b0d5b54e784cf7488dffd5ae861b86e7b8a57563abf5f76c81b595a144a11c464d17e6b871011f8f82a8851321f2455644d0156ac96fcc944a0ad89d52f896a2e84f5d4a146e61bd132248572c27d823142629337e116f9635a32f4647bbf2b281d6c1058695b49b51e7f602466a107fab60edecb8cafc47bfa6c65643c662026f702ac7b7118bdc6448eb65bfdf8b9eff908f354410c77bb689d9b557439e9704c4d4107cd6559d1cb5a9a10b83f9f24d3e7418d3781eeb8b07cc8c5e38189afaf64db11b20ea072674fb42c3487d74c392f278c274da80f7518f983152101b1ec941baea92c132181a9442106be237198401ce1b652ed41e8f033c3a364519b2a1edc41ebbb36529440ed398207e600e3bd2622d4534d7f06013047b41a895444947ea252f13d40d0b82b82c0405bca2454a8823a0789468f845441089e18cb89f940519756628a8c61db794c9e86c3c4820b61413b1b88af8b20a687524ccd51fb9eb76eac8b958501342c19eb3b6210133c3848a4cc1b2cfa730cd99dc9e5635b3560b0731e202453b31474bcbabb626204ba05b251bb5c63f85a850efac7d3ffc0c8e161d014a441618be32c94d7ed2818e41acbd060cb9c5b43226c05553b5bd31b310fca52389361b8b2389c952e6a275d17408bedc24a01897ff484012e74545eb099fb0620fe7523d7b49288773224a72a01b198a299036889a5d690b994abda1066072f3566a33c944550880681f716c87a9ac546ff218ffbc8ac48a8efe2b11c8c2ae3bc0a76de2173cfc5af328929d540561a588d4337d1bf8748f71140224c2e4aa458aa2958b236a6c0c77492a307f754869d9c8385213240b7a1cf70b3f7aceccbaa50a134064d64750ab5ab35982ed596913d84c74a8c63647a2f5531247373ebe23695ba767d0eca290b94647a4c94e3949b7337fb7e77ff7668f695b9beb8ab87723a58ca62efa3b75a6584768c229f18a3c26ca1a4da72972c02a9205aa08991873b94fa1f995ea6c67b8a015bc3b7a77943435cbada7323309dc74b7a92c92127b35c32879567d4e389fd5b5a6c23b932108ce22505d815c50e8e80d9dfc6c3640b111cb9c5fdaa28d199a00e405f061b6cd601bc602a6a491cf900937fe566fe3bab921c09091152592f6bb7bd951eb960708167d08fc60c40563173c45a76188871c696ce5585dbc66c65906d1c30f1be660ee2560dd6730fa4ac1b0cacb9fc05a17fbbea5d47e1eba4999f964ad5b88f874655b59cfacd4c36b818d96822f56058abd8ca410456c7af21d99462df2a596e235708b49c595eb94eac7573ff3a49697ce2a18d1c318e2340daaeb34"""), - xeh("2CE74AD291133518FE60C7DF5D251B9D82ADD48462FF505C6E547E949E6B6BF7") - ), - new EncapsulateTestCase( - xeh(""" -600c29817b4e10241e9fe717ba2cbab8ec2b959a255bb414a2571cdaeaba0db244af9405aa870deef7491b1c5fead4652599c1dacaa309535a073144e5273e932a1877bc2bd3b9125ba658feacc6de45092229bc84a94ba3f5c8bdb37849b5372c205f7bd2588cbb47b87779b004309a0b713cf428bd3083b0d6622b1826446925922b293db9747027b587a7677079cc1871a8a5016c6c04bc5576ccab31a2a0b4a7b1b852319c41f4b7855c2451c27454038515b9876d6fa11820c2c024408735837264148ff7d6062570732d3a4da3a27752f60dc2c93ff7d91607c70a13442fe4929184fb9cc4e33c1684660e1a1f6b575ff35b449c14527352c134a11a155cafeb214d12854753f54bb1a342ebb918acaa17d882074467b475976ea080bd23b256c477a0acf56fc3d9ba9b34297e71cdc37733a3d66f11942017bb8c16229a23c196de8b8411336742328ad6dc5d4ba77108342d6847abde81a4e1a4b9cb8023a1d442e245186d155e9fa0653fc4a6668691e146a6c729507c2589ac12702b08142b9745b2774cc0c44fba928f42381ca7a82d98c3b445bca7e343b0b1334a03485494a3b6661613009201961551ef9c38a2f7cfd46ba9f906c19c59386af69ce0003fdf03c880d482ecd206a0e96f54c28160064d6caa31e2902c7eb03d5f0979262591cf498d51175212aa482045121fb30f18c2274525205d7c746225c920e62c88570a3fe23731c49cdee65afc965883fbcdaf2306344c32d46b403ce050582345e5c0cfb2d08d0018cc33d1acfea146de85c1e93a3a015a1cd9c7580bb1583afa73c175645581c59a801952643da86001f065bfe6bc1d94d510bf3a0a0268a77babb675f74ae426934be0c64b115e3dfbbd2e98632fdc840f3336f31698453641a18b667579ad112490b452c8b7b9bc7086bb19e483453c4007dcb556b013801729ae23924298bac6f8c59e3ca971bca2474323cf636aa02b008fa08d56a500af032801e3157f29505fd93cf3791a210498405813d612858f503857a0300d672414bcb7b98868d0d156935b1921620bbe262223f43f3d906e6bec23235441da41415f050523b3617bd57184719ec9c92ee2b6bb4bf6427d7045c01176723c1283dbcd82782476fb9237f96b7d13697ab710291683b2953dcb9b8ff0cc0cd99a33b5fc54f6d07edac2462beac952848aa6ecacf71a656ef9b2506585665a0fa4b8c74701868070beca33556f12c0be64caefe6a1e2e271e8470c5867852abab93ed925f3837e9dcc04440607a34c4299a44e2a537bea16b8da07187278ae672509d53aad998b0de88a7605c99c1fc36edbbba10884ada971813e64815adac6641630635a73336c44a3e673ac24ad41e85697859f257a2781b95ad9e27c5ce39470ba246bfc3e0dda46260939647355d0024aa21b2063b19967eb7d7a65118f6cada035053374812b995977eb6cf1238e5520b6ceb67f261293dc9ab205c5c548213730585ddcb3b6a0d0b164f9546d079d3ae00079f6abb170603528991d71389f9113c08434d481808a823feb372437975b5624590c183c131507b2894b6a15ba6ac18b7d1a5ff0d16ed0ec41e214c1d055226b4b0063059a7486088fcf467cb1580a201b23912e571b6523869522bfa4dff5fb95aeb9fff2ae41b2"""), - xeh("76D04F481E68B2F901ECAB58B6369A2CC31A9DCCED82A1BBD426BE0AEE266AEE") - ), - new EncapsulateTestCase( - xeh(""" -425144a91075cd90b31f9696fa1c326a8886765ccd67e119ddfaa185e292131128dd466206d9b4fc62250c6892be09bd6d379e88a86204226aa9449cb1f39efe58021154130e630ef70735ec57cf4f2acb93ec4434c4cd31f1a4fe798aeb50708cf90e5257991a09bdd3963f2fca8292c17f870a4f5af4cf682583ec953f1321b68f90722387136ad46d81e6a44080784b19cb975630116817e81b48051518ede43acdd9b9eab02dd481b200e3093dbb46228cc30d222c81514d1bf319bb239aa8db631f0849654285fa513b81149c19473b43caafd2115939464207076a11b7c6445a9837fcb6fea0930a321a22320658334d958a98c8921e6bea31b53b3d0912cf737c7b08022b0413bf27504eaaec33c7b8bce11427be219b945668baacb1c6e238a0a57b59d48477218db93b28860132647bcd69e8c62712a4abea8316c42e121201fb4a37e0d942464ac4e0c79805d3c61054a7e897809f37295e04ce42464d3096a388ea0b6ff5c04f3c665291012a5c4dd2cbc08d0996054a52d0a26d153aa54eb5a8ce66675bfcb657f0c952f273c5899fba9a01aef2b8934386d6695471dbac20a2b5936847da5b419ee5c34c4b100c36135ee1ca83b0990b7c405570321209a288d284e4bc7e56809591209d07050a39e629b3280574065d0f102788325b0b5b14d1fbcf2ddc0dcb6c9aa959ae2d2b7c011013814a3971d16b4d2c3480aa4c1eb135736c0d70829dea14ac862b46e9267f392ac8f1a2304b7125d7b08ed0839c61b4c02253045c2435990bc1b6d4c27244035a763d63e8ca6291390c417ee0e9beb805915dd737d68530ff27c943a39da835c49d99c0b6c50a770906aac0a5ba988e650caed744066c7a131eb050678837a3fa9b39379ef9e9283e2b0deacabf1b833b358a1a9f1c78bbf20498b9702b259ea5bb1d58844df66519c1bb0323a4b3f4866ae5ca703e6680de0253fc659b9491ae70d307f5aa4c2c888295b9122be209fda3a5a911959f6a9f0c550a3978991737a76ef408c27ccaac7443da67bfa76a79fbbc65ea72b3abb96b2b048ecd4116291852c568b59bfaaa9531524e36644112a76a809f9d0683a7d04a35cc4729017d70f5b1bb76b74b618cc9e181aadc8eb4ba5973a560c0f55dd1681ce91ca3e8e2275c8c71e5a536c7988200b5646afba80fe0c902e86d990a2ae91750409a5ea09645fa5521360051271ac6bc569b6d155fe8a379a418cfd000431cdba989872f73e2771e0b498e9698f0006050b5a06501a4b705434046aff69cc961077454795a6b3184f3ab402a22a819a24ca856c6a9e01d475c76aa7c71bfb692b182bb184b95b0fa363b76a93c7238a41661226c408218576b175e4084ca1d68b3edf79db991107bc106d103b7fa682189ba9f67c21865f2b88de32c6c757bf343b9b15b10e0a792dd3657e3d85be3dc5c3c52650425c8c62a735da286ecaa9aa15054f5245b3b514ef2c309dac712403a9d2999add6e351caacbd80a68995d67fe094a5c542994a88376397a7a15ccf1a9575e20b6a7b5c40c3c9739b02a53ed5abbc502ab66243c304b74fe27fb7ba7348b3a23cd65ad515755744839616a2e87120cb0a1e4f30ce7a6a2fa2488649dacd86c2e5fcd0162d826fb1e6adb4e0d9cd0d417b6e13a9ab1fd3fa"""), - xeh("FD3C91294D8C974930B4B6135AB647D4A7885C83FCDCB30CBD38332E14094491") - ), - new EncapsulateTestCase( - xeh(""" -12229f38375f8f405bdd3bc19ad9180367aba6988e0276031469512a6514a43902c6d66c06a236f247b077323d5bc1342c93ad1c0638f0b31aecc4a0980a543e488a39e726eceb54d1f807ce3aa556700842f1b2033871d2036ecc567f244c988242641c2aac1e31322cd08d2f95c5d559ba2328808618c5c6d8b49ca64c45082bca908dc5a75cffb1368c82cce0ca1bdd65128e3782d306829d608c2d40cd67e6ad09e79f39dbb6d9e41db559218c8263d1f6a8d4441f465a6e05510208b00522a9a6a77cae073817d99a40f1e84f4224289700a173c415095c7d35a32554678ee8087934c79943c7afdc40141a4810e94602d16c77cb80a2af5363f4444a9c32bfb8bc11e97c0d75435db0e70608dc95d85b70746263cf8c4def024a303807bb6640bee4176142c1be417aead89dcfba17eb319add262441a0c451847dd9e93dcae7c2e9c04f67c098123699df6c39dc90278362558df092c7292364c6c34cd0be104734fb1aca5282bcadc563ac571c8394b6fdeb9372081277b2987f3a26d0a812170303ca09218e842c1d2b886095bb25700e021abf45710550c4851fab4f7968460972144c1b6496f4465a0ab28478b1662b900353ca3fec6ab2c060d64caba43548c28654e1a38da32731d551b9ed03376c01be6466c74d44ce1aba9c2cc694db99cf1b09bc785ac5f0603c0248b352a69599e6b9225c887ec045a1708d73c263fea1bcc3782fd1ba1907064293fc4aced3604fd13c9d831323900f101534454bc7ff071372eba94db771dce7ab21e367925ca77bc3825db071e0f8cf207b2ca519bae8a2625c6b7b593888427a32462c0e98f009eab7b4bc151e7b727b6ba93ed0b686854026418272987069af29712c0c002e1304fa10071147ac1c6b4bbcd3232027ae2a0381a31812fb548360aa45bbbc711a7106c600af77535c51c85aafdbadf8ca6fb2c66bf66cb8856596b292490889a9b079c27d322ecbd34dcd8c2e637a7337eaaccf9c0654f748f73a6bc2921f36e1c6e662456aa66c55642c511c8376868a1a5c829da22e92e9a9af2b6ce7207bc7f94281c46eb76ab742c8ad0374973b36157018b9ba221afa3a3fd80601e85668391b97bfb30912038867b260ffc84c7fa054c0cb1f53d337b2f680d6f627093a21f7c6a065d276279bc83b759ae035288362b63b598e1611a21ae65c62f12948554cfe23bbf282702f87b540248219548fb0c363d19b9aa387353aec231965561397c3b4a41199615f02a27d7a5a6a8a93258b4466f389cd07a5ced1e75306d774c79c0b7b591fa5eb06b544bd4b751a3262481b300d1947a256f5c1a290c4eae87d0cb4b843441ef9f02ebc1100069b696c8ccbfa0958fb4551706306cb5c4d1e417a694718cf0a1e8337067a1a3c7981b81b868c8ebb71d956967e904f82c52f8a0865c05698f0e673ebe48c332293600986967559d9851bf75540cf7704dc35559b024298986d2f612a1ec18ff7f2ce1634482bf626939812c346174134ab65cc0bb7487e87d09ff7965f35a9474416c90a978bf29a5c3150bfa6745289473b485b7650ba78699b843e40c52ab380042cb3533ba8b640295faca956b0556a30be2b624942c97068f9d55db7c2d1acf9cf002c9ea2d973d79a050ba26ae235207358d083e310ab"""), - xeh("7DB18CA35A53AB3A65E4C17FA096DDECB19FC7747E657B49D1C1710DBD1D197B") - ), - new EncapsulateTestCase( - xeh(""" -772071873b6b97125b613002a38c5bae914cc90630d56673b824a14dd20697f800b13b17769c450a8b0dae472a2b70435643c82b329ca6440e3fd16a23dcba5d859ec8837a49d18f5c61950702846a806318752588f88590f0672fb5cf02f48fc3a8073b50c17dc8ab60c2601ef15ea514cf965a42bd771af7b917cc28a368755771ba3069036f57e1206857159394cf1b9702abfc5df3fc1dcfcbad79f2bcb3b7c9150706eb520a57b547bf217cdc902214c1b58a7c8c585b20ff1242de6525ae10cb857881897319f909870b5a5a732093f17c2172688fb585490307902e1872a4c384624b8b27539e7db3c78c272c14a988f3ab48a2e787a794b83186535970c0d19845b884c5cd427dd5ea699349363c3006656594a48bb22337877917258f0a356a58b0d5da3bd99976dde9357658b1394843c800a2cd1c608877703e3c5ca1f282d8b4b773d1623a39833f393009441c8813698957bb86ec8f4de60a92e0c2e6178e269024ff5896e2475d65854cbe4466b0671684b55490240b158657384b67db1b0b8c0c07422b460d05a1323456ca73cf749a727ad0cb81e1109388af47f321cdd836f008208978430ff1b6aad03163a412f6b93e09bcb6acdb3633b69c47aa5acb004fc7bcc8e3e2a24f949e24d1c23b9346e2c3a32c1791b67cb16f16a96ac58034daae1ca11a838ac0ddd43883976c9ddb799d53abec005b00faa3a15702ac2187d9b13b4e0a3ea8b2c9fc77a1cc23b633f9087c188291c74c9db8622dc03b78f48a35716ab5202cdde6cf3b62464cb87064b7b02a8890af2969c9275adfd28ec6c2940c717c8575a84a5cbbbd983c57183fc2eb1ac35744cda32515c2a66e3c988ed0cdb9e6778e98295f7cca7f283960275ca0222dae433c0035522ca7650606436bd767679b42b4b69912d0553e276f6b6428b7d7ca99b7ba855448e495bc51b1871a627edbf535045b037a698c8833a4696073bbe6740ff222c726c9cc636402c912dc1232b10197b7440490b92ca8e683eb4817a2b866c85a07a38885ba0284da691f99f167e1baa2caf41ad75a7931a43e21a9671bd97a65dc415c03b368d075bab0cd216b9939e4325e1c9c96251d48dc7f064339dc062b4a3777cc24bf01c272d1ca86819027cad3a491600efaf961c815940977074514a022dc40cd503ae778015d3305cd8b04d4c001d410cee5538e9331982ee52fee9857ea5c685b41bf16bc6bd7754dcab4ae99024f69336ddbc42a95079668bb8fccbc6ff66a6b05768d6b83c03c759a2bc6ad2c2205b26b41fdf022da075cf1589d88954ba502875c28ad47c31b857998acc5287da6308f800d53f95797e52d0a29ae4aeb018ee418c4f7cf72696aa286addae756e619aa8121b481ab66f25117970b66e5866b90652190d184669a4def63219c025f02149f287656e0a235cf426c7178ad99c61294a2cbc9e34fe5ea735baa8da8384daf0a13dce458433067b004bc78922c3dcc025e5688b67ab4d7fcbce06756d49772d4ebabd8b94bf07268cee346d252a9161262d38a9f04eacd7bc76a82f477334a0b3c272b4ab84aba7205a1b158319139827b3d219784101456b964929fa96d27d48ab35aa1b6f914c1465ca9548559c9a8d1f7e328029954825a12a8b4f2f4cf320831f0edb16a73"""), - xeh("876B17263B409171B746C6936EC65FC94137F958DC974BF98110A1D07F6D95F9") - ), - new EncapsulateTestCase( - xeh(""" -05b46c32848d4c14cb6c567b994c1bfb75bf11fc3db2915f890c626ef2bfb14c1aacf9b77914bda70a37e165c65b03727e1834f2d6471f85bc705b8f63c75672336141c44e6c9b7162f0ad93a840987474b7711be7b8b7a587608604acce1b6ef5618495f365f221b5464c41d6448f87986fe8f71d27658f40a15bdd74c7ece1b8992c137e3b43b8c27e228bb9483255a7050a23755c671b4d9854a185b2707b342d051c262d7cc12439b258b30a4c14096e1c91e962944e7ccc11ca35c5d83c937aa0cedacfb89cc6c552011e31b11fc95626fa0d1c04023d8772501402187ab2af9391abe69f988a5daf8114cae6ab0010041ef4af84763e287c4368eba94e6b0bbde17585bac5a8d89e285c4569d9025b65b301374a32018366bb66f54aa4b8cc385f93a34325282f36c5bbe172ad2cb44e32aa876113d8c1000d94b7f0838acd2000a6e386e287cf77226fbc9588a5019b073a237029820bbb77f934be084318e01562eda6b4e0f01d2dc17caf290fc5b2037738a33ed181c6b4aa4d10982c38aad1143ff9530e062ab3f16a9177f145bf0a4b1a1b037682506628ab3fb127df8ccc36d0095074c0db42bf628c690665cebbd232b302802943bec761acb00065b1e07471a39d36449de0c8591de5cddcdcc3a1c43b5107ae30640fa221bc5262a86c0b0124b434da226d959ac55060cba5f32587b1892471300159c9d8045d59cb00cba04821f1a6e19a713609855e3acc0959cb2c88ac19d335b0856d19e34e306602d9c66ad1085edecac34c55443af41e76fc072741ae61950cfc174ff4f3cee652b280a39124ab7bf6f5283f2151b375a2668b71049042a421086db12e7fc7bff4d95605e8b8d5c59bdb47a71d06089e8a13e064040b1289a70b804481bd22ebca2a4340e5a498e83bb0f96c4955f516a5d125408656b72299ae73ca18a2c58342810f9c10808353acf006f93637e0254b6cc216d4c7336d5b5ce5b55fcddca0cc59a0077a6b939484eb64648281b51c3756c9c8bfae53a904f25925ecb719c25a3d378f0cc5634a4470cd839cca90701582383bf27fd2f2bce345481a2a80cfc3b6588a3c328a9d2c0105129472f5231e5b901be663016d79987812c916caa364450301b7ac0f463e87e3971f4a5f13888f66d5c78aab602e4a01a99992fa25cb303cce0624bc69063063c55c16b48deb9a5945f28c614b7e5c83243fb4500b27bbd232baee32638afa0a72f505c1ca7a286c90acba7d3783a33a2b18ceba62dc7287db9aac24a946f0bbcab94c0a2d08c72b437548b9c0d5c41f3fba3d32026bf8db12ac067cc37bc79d143e3a6c40439bc476d5b10724b643ac4d5f230e2a1c14004835963b58a231bc94b008f3f50e9b493e849cca03170a67e90f00d623c9704ee9f788514239c8105938323a78f34751c8960ed420d5821b0db6722ee07a5915110315cd00bbc4ead43719bb3e4fb63afd743c522c6dd03babfd8c9891549814ab2b7e0c66c8661acfd34db8db48feda502bb271ccc03146e7c5423a8182e84554a9349238705c250c8e579079c6c7aea73f38476f46e22c67a67b4eb20dcee2556adac841b67f65421a814c9770f84a683ac0c2db2f26222107d360c1623c9da4922b3f97e33b0bfb50623a2989ec50c6612768f42d5769fb"""), - xeh("E0AAD46FDDE0B8E64361C3233263D8A751F5583DBE91AAA6E69E6318FC7A8EE0") - ), - new EncapsulateTestCase( - xeh(""" -246a3daffa8fecfac4cde76265e37997e53d8137c99ef4cdc8f0194f1984b7b3886ad87fb0227d569ba5783630f248add3b881d16c904f46249ebc73a6151ee2538fdc5b248971b3bbd5af462c36548b273beb06480b28b04b359c03af7df4344cfa28cd469476e3499652ad759b761697861f1479a4400bc034738ab9b674311374374ee5d73349c0a7b9dc0c158c13739a674532b62408bcb5c70ce4c54ae26c30118c8320eb05cb0c1454b7b06bcc013c7892c9b4693f40c6651925b0a3101da97d98c19ac5a5b3f7930061db8d38e37e37e3469ae6b52fb10300da5ab71a16e9d762a2d86473442c752187d33c2809272a16649f8403609e17bbf8003aff87468e8cb4e0e2b3a2fbc20fb8b172e606830666b6550a5c13ac862113b817c2c2f1415da33b9dc1a47451246b434f586a351c55b4c9b465fa1cc9578792368209655397c3761bd7329917497e3f357f0dc8418d474ec2f01af697b5fe30248de409130c3dcb079b50ccc73a1b709ffa5010f1644de0b3c2598e8580050a0b659c034ba7ab1c627cb43736b6b8a754dac647a1b94878529676426175c700896b5d123c5e125404a59507f5fac8acd5bc5de2035a33ceb680c412374c9753aebe423ab515886cbcab2554c9b28c3497b63bfbf7adb8db29b59abfcbb501f318b5c8d61c2f33336652c787348e00c4c15c911f7e2cb67f02ba5c2b8ec9c87ec1fa6d5dfbc05f7961c6c0829d7687df542b4eb42d8d373ecac1aa55d921f7319eaca181ba1c259e4118bc27615a866944a10e28e260f7ec1083229192212ccc9085c5436210a1392918567619b97be71f65c017555a4ae60a81ef0951165a191672c864f2112839596a343edb58885bc58c6406334a385512db7dadac2b7f510830f3b3b3440f73038d53e5ab143a6b53702f30407c6c824196b4bf069a812777a8b2c26e661cc083c52fd3259ae08b9181f06d8c993f14779300ba56b88647a5314066d4b771dbc76250a60fba5afee147b01396e91a0f0dd30ade7c82b6d85f8613a9354630bf669257b57dd563ab6b07c5a2a809cb16990ad98f23f34bebf6064c049f33913d54666892864627f8c4e64b20e06b43a5c5829bfab4eb774907c36ed5eb17ec3101aa8434a5318354510df87cc01a09d06806bd95939235fb635734068f1594a11a624e7b87ffb239dfdc864ba4322ac4357e499e80656db0bb68931159d759806b3c2518a319bde226a3c250ff0c2326750a0d23beb60b442ca595adac6f775cb06cc988718bcbc29c83e39646b99abbd5f7723757b9aaf63857c30e7f0337b8fc949cc0b4ced2260736298675aa8e6a1022aa1b8cfa3104387e429370689b398a317f0bc50d7841005048aa7e29a71d0b03348328c0c268e8f6a64f518ac06c4398d7b2f82abafaa1c9c37bb1e3a147bf870cd10c21cb702aed892346cc47e6928d3f16575f1254dbfcb910aa967a87323208937d1aaf7fa90f1261131ad4b04ff36e9f6696594a2ccf3a021ce852fb9043c194c4d3d704edfc5e3d2ab671b8103e8bcfc631107815790e5733eeb66fa344b9f276c531e5505303b267b6516b00b056780230847aea99cae15bb4faba0b9d461877419ca2d16ca437f0f2963e80f169e7bd65d440b7d6ed512ee105bb1690052a72bc54207b09"""), - xeh("90347D478D5D964D66A54BE930FD9F7FD3C2AE1492DAC35A6CBDD02616BCE14A") - ), - new EncapsulateTestCase( - xeh(""" -d5e216438b4535c69165f884be521e5ccc33f22695aa122e5d918e8d27a390035a42b9c8e4abc9dfaa92f090360c9892fec554851c7e434caf9d41896741aca2f2ad64e8b1e3916827215beae96d2d190f22917ccbfbb3452914078607a0eca4199714ea8040e9c9945c71501bd1b6baa00628c62c220b5dd79846da4399536547b04811f6915045e63abb9575076150bce269c61390cd3a3fb3db7235390b63dc49d041788d25650858a062e49f4d9855cac7c7d403b172044e2234425f503f3f613a5b1a72fb32590c851d71295f0da4113705b306e6524c398a59a83ee6a9893091beaa78470b274680017387eb13b97baff06a23986251a1f1a4f73a72054640d6574b5d070582925b201b37b5a690cecab7bcf72e16e3454eca10fac9b760cc94928307c2853a15c47c6d29ab90e322b3b566a43166428c09a1b3ab3515704bc76778c38b0ed224ae727024f2008cf2b5128cb912a9bd806bad62e78e1d79cc90f3675f863df590210a18b6b629cf91738f23280e93ba04b3661cb0e040709639a5b495c7a36eca739270031c97db9ed9432a4ad86608528a7ff7034652571fc6904662116980201f8073ca003092c19df909989dfc6744274a2e01377099bd618aa443c883bf8b87a9bcc9d35c56aeb49068592d31e16e12c711cc9a1e9780329a92aafa84827e685a21a84156b29233e50f577c54fca9a3f9dc6f4707704b515d9f2492dfc22977a36dde51704ac653764b124cfa615dd5932a05b895987aa714c1bb38c3166b27cba655786c29fb733448381fa7606df0f586c3ab0f2660901ed1444512ca70108e180776078c417cda8ad2241ea9304f820a9964e455d8da350ec30469fa6ec3470ff4848da109cb1060abea4c3a4b733b97d04beda35e769a7f1f84bf98c8790e91199ef04a6ac80bcdd39ad4979c327b84c0e897a4046bcab450eb3cc4d52b83e2f3845bb6c4729b3508e064576a6a8caa9cc12c917118196000a1e478c278257da8a10d78734b44e426335c81a4e6988015a6eff43470d98becc9722d254a6df327ecc91174a3a76ab430ab40678b37cb098926823955d5d8aa8f4c2598eb8ace098da3cc43e84a4a205c00cce1962c7411646a1a4cbac0fe884db3d55cbc0531d4497e562cc0b6f9139c905a8036153ea18570c1164e8b73c15630b4d020380c63cc1847e38a938085bd74338704266a6462163a176efc248c5ea6568056be253306ad8ba7d7d6144622002daa5034cca3af106a7f2b61a0e7b8804677adec1bfe84b09b910f96eca5f090cbc4e14139f12b29b7926225689acbbcd7e4cf2921219841c68d900397a100937687a9d779efa7301c4b1d1f74acfa820445c851bcb874c3c5b6e33297c2b424737b082e31034723b05c6182ee8154f5f13d69e67b25a58f8a543e19f7c279e99eda3c53854791c20a1ed0e95a8db87bca83aa6925658cf4035ca0879d477ab8b4c104e149b550b3209b5f36e149108a1918fc29de294fdb250fc66b691c30c9d6016b36a83e73f9a31df40744b39410201049642380ca752b64a2d536b6af19365b434b326cce1bda94719bae4d418b81cbb28921c8d02b4452556a156aacac7608eb97a2a56949059a5c232a561f842f40228b99be04e4a6a52718dc4ba9689b0020bf1bcb8bef"""), - xeh("119BC36B5F856C0A2F136B3EE42041B817125A600E829FF6B4B402131A26ABF1") - ), - new EncapsulateTestCase( - xeh(""" -cb8ccd08dca5a5e735178993710821454608015b34746800c7f8679d72b0c628757756a50a61186c553febf79c00430bd0709e3741886ee10667aa7f7e4c91d89820e66ca9bbfb029f5cba016b6240e2bfac3815afd613a13b04810a26559a60f6628308fc45238269c77428aa370418f11928d5b3c211cca7bba2de57898e132035a16a8ee780678b213917c725ba8dd1818428199c672b20ac05061a82246e3b55bfea529ba891da6320412108ef0ca184b44736dcb05990031f3496bfc96c50445040e27df4fa2c28205e1d9090034285912b199b909efd088cf4ea4241f5c3052050aff92be505a355b515e5d4ac55b859d5a3cb1a42564d398ef4cb91db1430a7da96f9e96cfa27cfb12664f9f694a36b211a7a79b46c70e0ea14219c119006bd287467c780b7e6e706dc30b230b20c3f8759f2b2326d8422b16c124ad4a8e031412efb450f881302448e26f383fe01d0b26770384638ee1aa51df773fce34a9dd00ca24c584f5512c108109bb9499922019381022a58c4494241b2b62da8ea0b784967d86c7d8fc5c6a8f6055865173854c38d6b407b3199cb44000aa90253d7790011a9d4551d66278d559808835208caf18cb31642b06164558b06fc615953bb1c5fec2600975dfab48e9123b0f3d8757f53555177766e819f9c5487c9700adfc917e5782c82c681ad8105d6427785c862201140c5919addec3f10574617201e4e35372d472f782388c707406d73b462f25e3ac846bf7274a721b1a05c36981093c3a853996552c85b4a90e0c796c790dd881fb255557e0731eaf8aa9747b0fbc64f2db3a7667a11b6c7718200367dd86f0690be472b5a2fa4b914f91622b78be310719ecb81d1eb8b6c76bc4df0116f84179654794b39832701911480601c77229bdb571c1110387a78d4510dc0705d66e189e1f80bf7e5c4952c083693c6908623be31b1d2c63eaec178c3523110ba13bdba64e6903df028a23167594a12b64de601c90b41231a29eb5c2ba2475b09091f8389363030ae56fc686d024a1f838a0fca5914941f72470ac5052b8863aee631a3206c9f79dc479c925d906c86d3e5797eb2ba45499690b3799ce39cc65a9887eb5785c1a6ed660502d85f5b169ace240aa6c492f9bba48c61c81f0722f8377263a33087814dd51070012a103a93160359c3c2a945933c081409cca0963e99883dd27cc2572683881c189861ab10e17e400b5da3d40983821b4c45aad97aadd35b6d7296cf2ba029981182f5a1b189668711d528de7c7b07a71a47056074066193936437016b5afa3fcb245c05764af1d77681325c0fc2bfd2a74f1490c704e216d18345a1e074dd440b730a0464db2bc5852caeec23c0bb0d754cadf8f050ada71d85061d18a6138d8b70f77aaf45aa25ba65c643f6103390168629bcaa10577070bad8119619320762486e9e340d43a04bbb408ab86801ef55647e43cf88a6c0772b8d5f274f1c12593b07bbad80ce3bf1903f24c6dc976cb8c08d2411bffb92221deacc5f2783b6d38078f51d42eb5ff1a6b78a5899f044ad4d57c582a72844a98e9d1bacd4c081abb44117d20a3fd3b18352a1f2943c29d0a4832a8eb4b22cf69030def765bc527aae51010c74cca53b8df382df9ec3e8d9d492fb165aa4df3ee6a45fc8a9953ae5"""), - xeh("697CC7445AE2C9ECCA2569B7871F0BBB364E63E4B782F734FAFED4FE33E4AF14") - ), - new EncapsulateTestCase( - xeh(""" -2689044d7cb15005ad5928aed39889c195c94ab0366f91910658388798b53c6028343664f5ec4601d4acef04d0b6f2460e75bbf32405a512ab2474b8da27acf70bbfadfcc21db84ea0b73b548066d4e4618a355f9c051b8b54977c3544bc7151e4ba1710e9a00e86a46d1149620c291d3673adc5101499301296cefdc04bfd5ba5d136ccc845b4e69c629d1086e94b622054c5fd662952345b48d988e4b7198f298ef6a925fa1a3f912ccad5b46eddc861e69130424a8d952110f5820c776a0af58c7aaf14922466ceca0aac3bf1261bc73df001bb7a081a9440c80453b8ea8b06e22689127cc9b2ea3d8e5c2bf8b25eef8841a527729dbca2ab815baff343aa74b4b07c06d5158e820c1fc440a86d44826c754a7e3b05d40c1cbf32206971c133c80f8f678d3c30ab99db0656f4ae9ca12ca4fa132265232bca7569c8624730b234065196d773a290a3633605166161d86bb169981c956394aa602d5ad37cc8d800a8770bafa1667b04ab37a668acc268394705e679594445bf0a7987b86cc8c8f48e180279a193a187025648b22f53d9ac5d8b8a760978181a9755e3195754530b907ce992b939fb3740e626ad5534256bb7dd538c6bd2296d5675567c2277552c52930401fa09b581b87c18c70ac8a4076c9ed8dc001478757f01ae8ad3adf49a6ab590a61fb2c5c8645076e78c58740aad2990cf3858e27ab151f797165550b1f4a0fa9b7d47a8c4dc47bb53b359742aa486ab776b3a7582459f229b969038379099c428c53c1486cb23911f50108032796e46ea04842b28a84373332287db410390563c2271be2ff14065f22b7ea32a284cc3d0654ec6ebcbd6412d2f5c29b3720182350b82b8b65fc57de3d90c0cb55455527a469097d913331a7a0cca8692200bb9711008fe5549c945b306fc48f58b8abd835dd339797b9c508bcc8e8d76a32d560cdbf7506b1c2d32fc35170347b71a3f456163bf3116794324a46651f359bfdb4a65cfb754ea47064a2336f85bb82f2947b9fa164e11a55ca10086ec5af899bf9f7a3c5130a9c4880412946ea6ac478258a67c58131df3b7338933b77c064bc9231a49330a1a7c85e864b17c56501697b3e22b1fc468261b8eb8f4b0c6703d6a1ab764496a6eb27f804631071962c4a8062203148cba5acf2226b74b66fb305ea88040f22779a5f3486574a7a2833cecc69af95c64348288bb1925abd5be25878d9585c540134eb2046d7bfc5fe16581677421c1b59f1c69a7717744ab87902480ad1f697cb7f66286c43b73702f42720840d598c3917f25da324e5aca224a9ccd9757e91b2dda2186d56ab2191b46c950c54e7c570a3a0d7805096a4718b57bcaaca5cd6fb1a6e1272ca1ac7fd9ea9cc72440400bb0a35abed71c3ff0b9855058891555c713783386bc591a9663e61bb9bf8055283c2488e198a6e991fcbaadc7885f25295b3d531920d880213b410c1763aee1beebe665abc1ab64c6ab3cdb95555004c40148a8530c22b06341c301f301970f51479199c785a4c616813e6e41bd8fe078a019a33af92df22b207b09972a60443a39bd11c5c38de24770f3a29588abca32283650a0587434b74bcbe6a7bd6d70bfc581848c9b2ecd6184a0623c75c1768e0f3948eae08ad7e7fdfa17684a3c63b6a10dbcfd6213"""), - xeh("52CEBDECF06579F4A9351F77CA95B5CEDD034D812F3FB7FB50320CA80E4118D5") - ) - }; - - static EncapsulateTestCase[] encap1024TestCases = new EncapsulateTestCase[] { - new EncapsulateTestCase( - xeh(""" -4f31c22cb34ef4a51478c635302525fc0abfd221ca8b3a6e224338bb0b9116ba54cd581cb7a3813c878d65317d8736881c8a6b6a7030441b44dc6663a6919c7a3574463b706105c332693d1918682d2a0f2e12b1a545a8aca6a38f0b63a216463099558d282dee3c33af3bc160d48b889a9d80e9cb6d83786dd826cf2c58c23c87f0279359026458040ae638c3eb5c5e0f7b6ff2e76ea598bac5143941d50d031a4906bcbc826a364d92641f68cd1b43973fe9b802f778963515cdd47eba329fe6b50c8bc5bf6d3aa02e69965693997afbae7e2c8f06b85435403c827a39d63c8cbc675d4fc31a5a699a0f2381918448a4471eb5aabb24c0685e6a1ce042553c360190ec470b44a7cebc153186be0d8c8996a9b3bf46383aac698758ca7c9b4a993b77e8397cd3a3bfd11b31b961c90875c900157f97e211ee6c853fea2dd83212c3f8861c0a98963820d6d73c7b3693b738519deca589639462db956bca22513b9cab7459a51296443076ff732e3eba57ca767d4374a8b2544c46c54c2f46cd7bc6461b8105f0d41ca4a532c6e4052629929c03bbd0b3c6b52c51cf3195eeea6aa9a55de0d9063bc57722a72409a59747965b4e6a5e14ec112a103bba204977d43822d20c92a2aa0f4882798216cd26a857c6a12bc78ffddab1d73a9b2f91ba4de83bfc54092d4359f03a4416230cd6616dcbd916b989856f3b0672b172e20732be0730d1a3a6a837c59a05b846ec1d600841594b306acc67cce4ab7b9715afe074a75738aed749c1494dd683ab6791522023acd8e5c403f77b23f128f16261a100497e0b1f906b7956c53c1f1a0d65d9422d7a3e234c252675446f085450446393c0c151e751ce25cc05b12a58c334ee1334d16b813c7689c6851b7662084ef05ae30bbebb5c2911859db6dc449165bf8b41626839cb37814768167ebd24300306af259941c7628997bc80156c6b87c758d6c40b55076b74b2b9942093dfc979ae59ca16a6ae33b523a7c687f3f22638f37c69c4946a26bdede88477c7b67538115cc890873ba223a953e1b79f7a902d0b20cda992a25b235f30164312111a01cc5d82d4a6e1c4961ad96bf48b797680bd0d04c83463bf92d86279c994c88b57f5a14c45645f28fc19ee835f0ba480bb04a17f5853c1e00c37f0857e88504166a230344bbd3180e6421432874fb6767d0a0c52c661bff33988d3e3132cb744df5b6c28ec4e7ba2b25c22a179914f043bb93536602d754c92cb6ebe42832f605d6dc99a8065cda1ecbdc589a93ed321c529c5f910ad86b9183b827e1e8005e0ac102a35b5abe533e31acf35e649f967c064963675421990082f4897971ee4204e3611bb3bca7af3a5507b239e9ccd49c5c4e09c14f3a3106bd961d9d649617212832c54f430140c8590dfb1bdd40785390384bc9640e2c8564c4a4f700ac1c6d1895fa40ca309aa5054b04934bfc190a45f78ac1a8811046710ded3246ef4032f3b73231913db1a58f45563e3a62413f6a0598264321b33460578f682ba40d29ce15697d6373bc6220c0931bcfe87326f019c7c746e0136a98a6bbe8c7caaea8a222e80915926c4fca60dad75a3f03a60375c09b5c5b120180b51f185157a345dbb91bb5aa6b704183ea0ac0f374a90c02206668224f975ed605ea1b01c55b9a2c159c2a096b3c4a98c2cb8b81682864188cceb3bafe825016381b8b2bb7df2ab4cf2a71f77347eb84314dda92f6d5a5c34d9cf3a123a16b892099c23dfdcb5b8e67be1087ec5b38b081289fa8c3d8d560a2d882f8b8501b4096d82602e7960a2c433abfe928e769b3e22965cf7f7350a1cb4543c52c8f3983dc84709c1909cb76084771c3a59867208c1bdf869b85548740c8b4390a2a7824d2b8a283606aa04a78b79acbeac33a2e4490a44b2995c70165aec4e37a79ee3224a8c3693056b67b1021c5c473e7fd31551a24a3383741d082366398b835389d4e4a34f7905a4c5808b27b44e86aaf02032ed07ab30452bead1907ac28a1a98a97683895ee583ec59316673213f9b1e5c2339678c0b6770459509ba5478830bba25239c311231b796c8225c9206facc138cbc2f58495f106b019041387982cbc656604e05c06e630b3d84aff82240b7a7cf6c078b9fa99fa426c197a5aaff94a93ebcb61de47f9c1c368b4f0104a0e8d4f20f98b38f6962ea4d6e053a96a8059c6e564a9ebc6c"""), - xeh("59C5154C04AE43AAFF32700F081700389D54BEC4C37C088B1C53F66212B12C72") - ), - new EncapsulateTestCase( - xeh(""" -a696835000919f0159cdc7aedd3148ccca020f181b2e3888cb6c3c8e271449bac0da2a2042e230895818cc5bc87e38471d3abc51f6c05fd80bcb43bf65d55a0c4c867ee28163618376fa5dada52c5f4306cdd99f0d4583c1399dcff8175f465a02d61dbb98680de662b49b762a8353ae15bc76bc097b789ab1057d2595363cc043e56c5b44562971c0097188a30e488433a07e7d934b89f4bd74b98822518d2e06932403bf81e97347c203e5413bdbaba6d4107e9ab4aeb1091d77a326d7ecbc09706a98499a70f28300a0c80c3aab68980c4d1cc662091bd370575e7986c38cccae743efaaa63eeb9965ae8605a799b447b76f91a15c8f16b6a52864431a19839543d86ab02c469ed7404d0eb365b7bb643153ee2737b9107a8362c4e3b05c0136c6d1510229497bef7819fc0a30030f899c0bcc6366090d4eab165258fd1447a3b12156bb6a4b3320914d797a2eba18bdc5615c208d1328808b667ec39a283dcc331e83b9d9302e3145fc003230c8a2365a5b3bb52104e698d41662318535dd9557df8907b6161a404e946a4b00a52829c8bf911d79385f254465bdcc77a31974fa6426554a12e399b8ac57e8c94163f3727472baebd458cece806446842c48659ac6c7262304fb693befd3b67b3237fc239a782c83afc72366cf9cea621989d801fa2477d564178d5c13197482f373a9e4ed9b2c276ba88e0348c1708c93a7c54d21bbc64496ac21969b975e5f56d033c287af7ac993cb87965818d26458844103957834760aec8c1572bcb0aaa740cd23b71a1a80396e45bd5a2bd704474f3d232041ab51404a768d404fb295a18275720b205b470778226abb26b775c972505eaa461fc52be230359e736cae2299cf47b1f1c0cbddc7472439ad8033608a8994825326b9297225c8fb4c0ab6a51c74ff2059d60aecac1cb8e9b5b0de1bbe00038bc883c25d23be3198c21648271cba8559c3a451624a403a6c390cac13412b2c788d7ab93de4790e8230bf7491e39019b1feba2a551629a5a012942912d2631b5f64e2965c73205bf25fc451d8836aa944063925a221784a9b5c99f13c381b5ad71c6581f28510ce93366534e8cd137faba6c53d92e25205c9cb43d7be5ca2940997ba3c903c04ea5ea4605503354d4bd63e3070a12840e2551f15c20f6769834761bbaf8a8b11ab94b69807a1ab2dcc396fccc22e3168e35c444efe876dc4b7d22683b6ae49467d88e08b795cd556b975155f4324dde94ac7a89ce5d802a91b4745c2b6a86cab67836030005c70944864c0835f8039c23d7a999d43bdbf7428bbc83e8e65c7b81639ad41bb1f357ce9080c3cb57319c1f37db4a3efc386a40cd60bb7a06ea70c38458bee0baa58a9209682e73fc2cb7a6aa55f863b49acd9cb18186b2b64434a5b7a38a2cab3b8baa47e6da377ffa1d6a432c847c4c0e757d0847933f5962722a92b06abd6ad28adb1736c0a96ac8130caa309f2e5893b0190bd67016f04b17f38218853300a05a00fc30330cd907fa08bed95646db857f4edbaae9847af03729205691eb715c2aacaaeed21419b187c7b99b1fd83ace009abd93586a413de2d9313a854142f076ff76a9661a96bd11c2e8986dd9a7b3d9e1076cc21c0787226a66087f13591c896da8e521f6117a9d7c5028692433e86959450868272445450aa42429478a4df821653067cf61638a1c676b776b9de76c50e99084e1d71202c8a563c9c4afb6bbf49c851bb939311b79a358a5118c945f0b9f54c7a5d0c504192a94e610153041a291f450bb44995050a964264a79818e6717c89b4046f16908d7254fa4f571548b01e9eb37759c7e4544c5e5f98ea014200fe291cf40bbd4c3a61213c2ce862ef907457db3b39f82c87690451c4a872846c86ca53681030ff839b24ea655b8a868fca9188cd2afc719b99fb3020e547ba9e1c35bbb7d153508889c7d33526dc071c4e89632fb5538adc58a6a304b17610558b302efe55a0c631e4760c1be689b843633aa31bba7d9c4144a14d7ea15e8895061c025bce225eae5570dc375b6c449672ba29c9c848ed16aff85785953cdf0891aa5756166db1effc3ac58c0969edb54428588055c9fce4b05c023bd386a9c19c33d33d59044f9893bb98f3a77b35ca101ff518e6eb4b056b816afb48b7b1f4f707d29344dc3cd4fc20ddee4ea9cb19d236d7d13a7846aa22c2872f73b"""), - xeh("2E2C821791D3EA49D0AF380B97AA24532F6109D85360A751BB8B4C048C48D26F") - ), - new EncapsulateTestCase( - xeh(""" -0799b60055b072088af992055fd18766111d70a92dcaa1881c1b5d03807e4a948d0937b9ed4385a6479a23930878102c0c9a04cd1b51bac6a7a81cbae47b15f33a331a5303695a4ab229585d27b3a7105419952bde5c659e089d38789d3a82212e03cd0ed7a6efaa913362b55f386d2e4b8d2565a5781642d8e970f6c9ca25d2acdb8a3da7f493e37331d26432c530bb401a4ce65c463d24194b2b1d708ab2a34009cdb02b1a96a921f42c90488940e7033090bffb30b17b06bf5f3b7115a24baa94a1620434247ac6c9579f42294e1f50cbba44829640bb7713c8ee957174a85b295bb1e44943db036773d91b211537fd9584954726cb83c4498658d1d2a10d2b6b1593348423aad4f6bcf1807d6599a24c4544dff617a2710e119bc17785b0a8c57428ec993e5991f76a9503fc580e4c62a0b296dc52a1a2c83846b7673ca308fc0877d5f473012c5c50a67813424792171e87a7ca555c0bb380ac351baa05074abbecb602610f1c095a4d3aca0bfa11092bb8dac09918449149960dd7d0928dfb2fc23b7b50d85012416e2d237afd47348378c024ac5b14c9ab4c5507a1355685550de7dace35cbbf20a679c9b76fef5b795e0a14c803c36984669cc88acd814d9380646edb1cfee159040c8366e7396af8977673400f5ab2c21980e2a184a472563b1c32886c58a0d68a2d39275529c3fe1a744c877a0605c5da7556dedb89ae8731e729b6911a6194d71102fb42961bbbf770873784af83c596a66c2a94a7c851d9677c779a0ec527bd761dec9bc9d1b22645eab949e31f1968c649c811884a765ae00e98f3228fb03643f47890f78fa6f0369dc37c98b593934a3937084f0664b10c091e7a1315adf4b3f34b5b20123905009c6f24c7f0c601b8f53664b6bd6d48cb487b0d22d45e00f19409a894f3ea32b2b3ad0536ac05e420a74a710dc8375aa9610d2640fc7818ed599598f60e21113670b99cc0d96447f6069e0b193ae79277cb29883506180743678b3c9b53718974210f043140d74392d9be2c08bcf796b462211d60d618faa152e461cebc3aa675ea1260f4585e810cd4ea8415687d3b2405ca72a46129c95f9bafde87061158920c4b13a3c5300918c8de4b0f840410ee91077d611971a4094f3a236230337127c5a789209f36c39b05b6618512ea7c9549aa4552d30ebb5226bf06708b4621a5cc8f58b8153ddca32748682e36363df63bc1249ce1205484048fc8798ba7929fa627404f072a2e0c02abeb48ac9475dc1c087e427309c2b701668a291a54056047def6b10618a34c550235aa6d39f05af809174041b2140640c252b604e81e56f34f2f711ce6d64e56ca0fce0133244481058aa477628022f2c2eb6c544d1045dc61aabeb0aa42127bda479160f582cb075619f810ca2ab886319bf87b12ab710db03b4a1a170be0699f7f333a46b18d71e6832c356fcef57db82430b1bb745f2215fab44571d4b0d9d568fa5cccc2919b2ff6b8d9281e07759069b9a602ba7642f570b20b15a156a1c322447323a4e9fa1219b812b03a5b2e1abe8c5b7ac26a8589733a3fd33480e18ac200362e5a0dfadb1252c0b2d8c139e4532507329ebc3910f05b480ed196bf86166bbb2f4a96a91053b511c81ffb748f420a33a6cb771dd0129cdca037e4533624aa16fc8f18a9bccbb475ef0a8b978ac9090a4539ca1fe06c5501f2b34480b025732a90a01e60ba9dfeabb4e8c61ed5c4396423af0aa79b86157e687c313e5623e6137f67a25680eb6bb841b80530362bd1425ee986b18830509bae9bd9926f020cd02713c7a83e8ca4318a044691637d03386dd28c3ba081481ca7649939bab47668fcd4291a4885317025e5250894e968168447f9f5c73702a5837802cc4593ab99242a59a39fa14935eba3e781a7f2740fbfca7141c821c8921e7c52b4ebe24732118cf57590dc919d09ea18d2ca63a605495bc2a88f9922eb356fe0343e4ac2666c49adaeea898b1c023058bb5bc4437bb6b798f59ecc8b565f811c8ffaa13cf8a4af8374c3221c3e1ab89cd94393053acceb40fd6a2c1d2c4c6316993835b9ade3a4bb396a5040574005ae9f1619c2fa66ecb363be8a7fb424927f8033ef8b2397a691d2670195590e9299375ca9b5dcfacee6eabe078b28e7aa1fa314cf3c866667cfcbbb5b57f2db74fb19e5e0ab5683efda06a93631032380727b6a80"""), - xeh("5729B2AF60A4A5EE3BA6D7F255D7D2437812579942FF2C6F48611669135DD695") - ), - new EncapsulateTestCase( - xeh(""" -5f0436c441361e37075a75830c1b0310e763205645d482c4870336de131a6cfcb2435119341cadb7e70eb3a7b7207237c654814c9a6e04c5955e5135c9d311786802df76bf33c37a04f84ec0f9311ac371664ca11dd56218f65240b97819165d90b113e955a19834a144e1ba40f97cf815b90b4cb7b06612168c6c46e11d4d79857f04cf00bc8e11b930588216e7ea3a5c99caae7b076a4680bd76aa3e1b806f428c8301641640b938743770b5c1ded957b8b1aae1fa28e6f19a3ac59f50a59a9a346766c9ae68a5c920b0377891511cc3b3fea22a0b7216ab1c1d8d97139d985f13345a073434150083cdea7977d9a5eae98314d6898fa14e89e4cc7d417d4b060baf854840e12505fca30bdc0d60a12fd30bacbd62287533aad397c208b0bbcd50b8f19431fe727460d754668309090cc81d8b7946333cb6fb890e152069624a923476369879f04771a0db28002ab860578fe351a2a1a2a11c198dab6b656a4580caa45e45d3987c4445f312c4d14c7f70505272364aa8341b1753af08040af6501f69e96d108a48ad245ba2663aa154339cb48d4bf55acfb9534ec42c06a11e4d4b3659f65ccda82661b1700090187cc57b17b50d66ebb7a44672191193dee20e9ce21bcb36be9d312941d622062c7906f5ccbeabc861d85ecff006300ca549043dfccc4400118a18b49eadb276ac45469ad69ce16c60bb717368d6c7b2f068bed1b2fa930552731444f08a239bb65f173b7e61730c68bf39656ce5f7425601519a2773aeaa3795d98db1146912683396b6c9232b498b9bcd3adc70f0935d71e56737a422b5792f75b12457f8817d926c44f8a8e2a34573ba7228204cd5ba24c7f245dfa0c1fc50be04e36f407043a4aa7a6f62b271ebc30bd76a80d242b934cb8448535ae51dd43b7614a736d72c14a577915f9c6b62cc10d0315442614a36f32d94077e65978430597a6694410888299939784237c991262d38a540a5e84f326906a7883a6ac3b05bd6051c5a11ae47809b30ac9a31226281a39f63be3876bbb6a896857a5177a94b8193acdb441125236c9cc291f2d7bea99025b282328c571e93f2bcc943b3d1f6ca4e3784f4314e570b48d483b6b20b9dc41280610aaa3a345e2645a3afe5b4f3b507b9c1a3502c84f581617f2449035ba524ca6a454c87c57652db9535b926557a19b157fb3f3896116ac1488a000f20c5251017c34416bf6d13c178204484c83da35817d0975183170a100c0b24404645d7b551ea24569c5d92235e6df27b105c065f66b23f4b119e5aaf6eb9ad73f3ac55826faa55021ee116d9ea096c350ed1c659751bac4a57c8c70126e736ba26f276b5391096541236b3360d9b76bea1b519d141f8fc9f4e8411d02702ff366aa7e1a5629295de395eb251c63e5170c1db22af621dadab30ffac21a9b400c8a7c30beb194f027858569029b19e43929901e18fc45c1d7dd6b464b64b14984f21286ca02124beec214d354ab820b4e4aa8a26a35fded6cf0d95a26f20123a909a7fa708c74580b7984ee082a05f8b481086b109d61b26fbc171844bc29c0ed42bbad4cc167935a9d1524a4e162a4d598a6e23ce1d404cc4a5b9b80481fa3b1e416027a590880b38517ee34e768c61c93cc170c4c8a8d3abf3e79ad2b53e710cc521027d2b8366ba7583e9744d68ebc33b4b45b8f04e44b98f890bbe3bbc0209d93a9d6140e6260cf28740fa35cd68513d4b024d5d5463d664b3d11a261d5bc5c1b8ac71f247eec4c66b72812c308b3b93a633b80e2ecc502813cfb4339c24ab91129c93b56b4d87a132d835986e994bf61432dfa98477dc70f7a66b53f88843e86ab729b5f79cca14e2263dfc868e2b81432bc47fd1aeac51c3a1d49549423d40a86210317e39d9ad15019e90050bcb882ef7dc09377a961465098d357061f8549ccbc7f951639e3a73b3e7a6db109ae463ca41038fa32418ae4777372121a5470622964f514c76c108535d7913fa16954d6668e2e01b16b492dce96a932532baf3a413a3c58967a46b80c5acf276e2a86cbf499009a5685f392dbaeb4621b66d9f1a631a60b59d03a8cef18f87c9c2cfe6290130198e67b8d095019b0484e0d274e488640db473d1402929cb501e9291cc428d37c0264d1c3edaf23921b66855f3b90ee38931192e0b30d24650e4c7c62b62b0bb885e610e1a9e542c7ef8f4f03f8ec11130"""), - xeh("FE8AD6E3F3EF1FD1890FB7FF75A8CD9B2A04CAFA7ACEAA99D06D116B81039DEE") - ), - new EncapsulateTestCase( - xeh(""" -09d4099084b07199a5cfc53573e6291a7978b848844c008f3fd45aae742d49f4af1229c49189bdfe177ee5c2c5315940f0024009eb4bafa5965a472d87767d4dbcbed6f6af41307cb48ba8f9828f229160df4581b59617d34203450b0426593947fc84d739784528081105c2c0fb9a7af8be6045c8606cb22d1324d5abbdb773c69f4bc88fa15e136509dbeb698ea0bdfed69f8ed67477e10244304f866a912d2c01bb4c428081aa46b862a6d420cbe7386596c34ec87f11084ed0493952a656939c5614e6afe7a022756621b77bc27648be0e86a763e36f8015b9e5e68684f73680773b5d5a9f37e90186fa13c11604e9f231ebe02a9c531370778579649f33c70e4be811ed668e62d28f67f7133f86695b790bfd2a39a0f22a49195ae4a40196a974a1b3424f4c574778b0036b21b356835eb2a142084aa2b736e4a810f08a2199c86c3e8a5ccf8386498592ab3570c6677ef089c0d05b06ccf4049314a8b29c9d9c18ce40933cb857941cb59abcb499ef53869f155bf2f4ae7e1c3e41889bb0682de1b4ba1ada65289669a55807d10672fce9142d1a8a7ca20c332b4064ca8a1fa5a8c4a898c76cb837b44013376fe1577b0104c95b3757c40a8c70d926216c4e9cf072ce4798b8d38776b3786f6136dec4b9c3a35ae088905df969ece6bd26572c91d78242060c54c9573a789d5110b25db9a5ad1474f2694b31553d3dc63d69913650287f6296854c46a10a54acf869757de3bb21342d26825a34704966e5239ad16b57458ad75881157988d5b0577d432b89ec573da15152e89afc7cb0c587a3db87bfe0db286c528c4b211382172064c94210f3b4c698124d860a13e12b87756bdd0002423649d7e7a1f57676c6e53c1ef6bb6152a932a110810ab80c2001aa53cab449a6d8b9a734e48de8f4777fb7c6f7408c2c8928f72482950b6497c2500af7568d514c4c34151f6749a0a6b79ddbc12e03c5563702ea733ea142035ab4149bb58ee56970378727e6215607a64fbbe7888323bb1e265dccea33d1f96b8e797532249092a202f3f9c9e7026483e78251cc57c1977c1e5a4ce4f9bb6eb4983823998101a58b0b785823b3352c6a5e2a8660fc143a5c2653e6a3920a8d75c29247a846f578abf56c2dae289e62d1a581dc561c946f00edc202222e0489b697c786ddd18f38a937c7f9b9cd0a3d85a9960ab2b470e5c57fa15991e74517fa9757a4a62a245392f3361f7601cf0040e391808235a593a88662895140e468e88ac4553908630564e61a89cfa2c2271a27c848a08b97adc0444a7b72bc0051695e197c91eb4af7ab869a4b9325ba36d3636645b23660b0a101eb0af171470dac7e4d72c53bf4070706c840f11d8514913873667f7ac5ffb6c011aa6dbc34c8bd22c597e0814feab71a99b2969b8679c4368282bd5a109781b02561b59164832b6096a13b204de5d8592b9045efa538072331f984b42f43a44d4ca6e2792bf26a4beb24089d046b13c25ec3612a73c19a8332a9fff70d5ff71851da2927a13942e8aac355582fa347920443f9a76c1d942d624c8b696bc3825675a6150cc56b0a3e5a19bd6782ce9781f4f2a4fe6b632de07047828713b23d98c91c99091571d90c3438c8b64592ffd747f29351d8ba91a2d6349da30247db82e2051cde3b0094c4aedf7556596968ae6acba7a790cba9c1de26689cbcaa4d61bec738a17f33b666764a2ffbafb488530f0c1b93617be1677a53cca42908c8c7a051ecb6a894273becd75313420b3d763a57ccb7cc73c8e94aca79ec03873c2ceea96b16d67c34c99f1f3642eb6948f4282e8d50ac30a10a47ab8859d54f86011a652913194c8b5e3139fb65039b4493a07a95b89177a4d1798d35cc1b10c9f0ea8b1afcb5ecb2841b143930c58ce8ac90b3b11f43837645a6b9f6c08b538a2b7b9272464b9707ab4faf9253012cbc985ac5594a7609a1b82c13bb886c564b577247f886382872d32102d0a31ed410942c5b1be910bc63b0212eb918eb0485e6734fc5f736aaf84467692534e0161c4258eeda24763894d0598795d48d99c56771139fcc016e516a29203774d038610bb5a57314a9ce0c677d192143d34c8b2148fc190f9514820bf8c8686a4413387cff6863fce50cc85cad03b350de7548972a4168f154337006e6873a14aabbe7a7f23ddbecee63d35e15fe156d0a508c235b058056ca"""), - xeh("0AA3B1F8FFA63F89F949DA18B6D8570BC5811F85A4BFB293E9D411ACD43C3227") - ), - new EncapsulateTestCase( - xeh(""" -d3aa9a1476a6b477cf20196569ca9cc4202176926f2e6b76cbf4b4abb4b183847e068c585d7c65ada8c29dec27a32642647901a23c635f6751ae131c34815b362ca00618554c4a9d028a6aeb81c0014815ebfc7f7f7001edeb5890995a25b89332c466c39888b9b542d741954a27b5dfc72a65a0cd453b8ca9529701d49d3cf21922a7a365fa3f73778161534274b3244a31a192c6075f2562f04c6c819111fb1a099c114e07e813a472a802a0af3167c7d1a68583c57305099cf4e9a0a5c724eb2a318ce0582078090f35b856f773194245e6678b9e77160201cdf2fa8d4456671fc9bcca217a2625784e4052e2f339c544a5e589b24faca6e3c332891b2bbb5849c6ab2805a4b8d01199feb49250bb8d30380ac3651c7a07525556c9d925001568a73b804f0d1b0e9b9ca8453c9303669618f398b95ac2e304432256811b910ae2570009c5199a110ad8424f135b93d99c375243c37fd36100ab89b88b1997d3ab9eba0bb6b33a8774b07c33a589c236be155b2df1420e75a0962315eca254a1fb01ed63102fd62f249c79dd051addd531597cac00757014e01366b771d9e06e825082a4a310f8f72b7cf644e56c59f751affa55985e42447adc6775187170aa0093ba12e65b1b3a2aa5b3739cf2b09c3677184d6302141b8eb4985fde8a993782c256f0ce35dc5f973cc7b4987b29a333e38ac3131b63638003c600b5077b6b5b7b9a246a02f466621ed67d4d419c65ac1144054120439424f58d9f776a9a3a2596d10de267b20848c6245350e68b593ec7b49c877e5614be71a624fde99c0423216302b3106a29c85698f1b3a96895aa97c021c9b539fa66230ba8c35b068c5b2565f974b112140db6588be7016bc1b2082be9a0f5394544141643b75270752bfc6920c288468330ca4b3171a715756dcb467ba635f7d17753e0c1d3778114227d8678cf63f580adf5407e9353cbc546068207f83b4f16ac1df250a1f8d499fcc9471de920faf2a23e27055fec098f791ca19b094fd7aef23201041378cb51501ad0691a39870dbc8d6c9ca2d6003de995b2cef5957745c6d04194d067a2c1140d7c6aa3e271b4b95ca49ecb9bb94254e562905a0623cd670befa9c5fb971e2a69151d209fe4494ea753a926b4524b05793fe5c1b55036a44061d8d1668bf0094cb14004d3759f510703bcb22d730091370e09c1022141c3b35035c2a08921e7a23c5899ece95136936b68e839b021a97499bd30dcbb1341141698594225cf52740ba1b68ea20768d7a8cf3af91f7c1b1a49817c04f475014b0b6ae38a81f03260ac672c6c5a7bd2b8f07b3e5243028a0c15aee58ade16c2ac72985de1525bb34f99090d67097c11f3303b219fa68453fcc03ec6c84aab448d7c308d76253fd5078764769fde087b6c955c1399b54ae068de44c0a282a7772154b50177b56c6a6c10a317d292bdfb4d447045072857a0a67dc5b87599424705ca9d6dc18c88134ea1c746ead5018d00bad1eca2b84217b53743fb377765b674d30aca06c79ae5c2bd0cc06e4f8249d8e5acd3177747d65a8692a3db8b1ea49504de28b67fa1ca3c3bb1b1365fbbdb3d40d666ad72b286b221ddcc505388819c993652c72397fb158a175906546e1c212609dc7b00150987b408b479bba5d290e0130d4c98c33f543da186bc514ab453f13404619e841c634b4c5486c2ab80258ade6007c8895554e819b5e894b1b6933692b3eef79571b8b38493c3cebb915c6aa35c5cc543547400b81b6058a6450ac5a7a81e8adb26f9a8367da7bf8cd2496031016ac92fa7853708463911780fc536cd54f498f807a5d029a24bac5c1b300351367e09d1ce68e6af97406c74f5c7ff796f4ecc10227bcb4bbc27044c9c1e7404bc15985cfc2dc166088119989ee32789bcb95fd0103ad969fa164bb5cca5cd5c3e6fb65f989a118d6a2bed2b59121b5000f64fa9fbc723a1969b93ccb83b661ab1b25913bf2f6cb604e0218cec9c8eb2aff60c948864288ab6bf1aa1bc65b7894e1357173ab691630821d63b75380958ca91cc6a9785556e4b63b5920c0e3876646e6833e542a250399b16814236524f31a470ef05cfd2dc0e01ab2b4d5a9b70c4cc5832b72a632e2733829c9753ae5a928106267097bef54b47918aabfcf91c1a6b9ef3f1154f8a7f309babe4a75743409f7b155e6557807d6b428f720e0bf260c6bf"""), - xeh("2429F93D29E48EB6A25ABBA3EE2F3423CDDDD0ECF4B2090C6CA5BF4883F4F3BA") - ), - new EncapsulateTestCase( - xeh(""" -5b42bbf7fa109a95c24b6a71902c2e2d806d1d2baeb0c2068ef710a989211b64636cf58bcf43a3eac1119f809a26f02a216341f4b60b3c7516a1cc40572c6855bc29d006737ce64739268d0bc59718b9aa34a82fc9834fb05b27593a708ac4756c28342a148b2173b4cd023fad458b0ec6807f421401991dae15cbd8b01181294f95e0a64446710c41671ae3b298202fc44045541ba5be8516c8e52e743c503c9cbf69d6007fe79c61255872d312e1b9843300a6b436a96403bc33f6577bd4ade56bba41ebc964028ae6684c65e0c348c7ac445bc6b3021529676d5c40a3255930f2118d2343a866a6c5f11c3a1c85a790f25c5096c816166d2d08cacb3bc503d83ca9d1ced3aa0372a3235e06ce21f3a8ce609621c954bc383c97b49f23e2329ce9b092037e661b361f9bb13a285cd77c02cbb6cba1e37cae8a6264448e07401ada6896baa3189a527071e52dca12211135b6c360158fc60ec2b692c119042565172ae9c7c5e15e1b1a0952e772d61b57e66680b8359cd4726421930562562913c0c30ee486b023c8e36926bbb00f1fcb4e89600bf7d79905794487ca1dc5d69264fc56872588faa81a755b3227d2532ef54f8b0a91b8a6ae66cb55d34197b7c71e69c7bd39f8276e35117e96775b6c6501034f81267222f54a3f7b94e4a7a3e3ca04948b4f17300b92330d43a41b3de69702c2bfb9272eff89868551beebe890cd002a86d8566ae5cf47a4ceea731ec574684533796162ae9f206dad42272e8a7f7e7c97f93334cc833396324a8654480e5193a8e0918b48015de487df1590b0f7627cea9fab8c3bc1cc31c52a7ae3e7173a7a8c420c7090cb0cfbb0b419d53af678b5db9244dc8b8645f6c093f1b14ba5b65e4c0b8a875d4d86266aba296e648670867b7af5ab2392c4193b9f83052425362c5ce4a45dfc3e5d9960ad3b392ef6348fc7a164b494f75476b78c3f2557cb898a70af6280b7053823727e18a7130fc777b7e81cb8952f23b9b27dc02447bab51dbb9c0dea135db473906987c5ba76b0424848bca4e09864db2cad5e97adbd00629219abf8978dacfb8370f2ac6057477cc7829b6c452d242299c0b314855c5a5c61ee4557555795286c904d08aebfd17edd57195f831321ea02d68493cc994dc8370e219152f5245560875a88c3b919f9ca9a745ee8b942e1316a177a9471cc84984c31b59b8190a9207e4ac1ba253093e7585621878a3004d21851f349805bd70573580f9a98c97d6a2e790c0305316040f64533a6bfdce19d9ab8658ed26dc39837fddc2be9c66012eb76bac7b8f2c05361ca1ea7e0a77ec18187565f3c4b43a6397da9a16a1987ac8c700996124a10789ac7e0932fb820f4f18a9a7675257c7cd08249f4185a1c7ab357470e8a35c688a236b4191ade41bb9271a3798380d4a2a643e302a53396fa8976d5b2096724ce85ca4cb36ba8f7bb470f534fb496a7104675a0367b05f090f4748145ca680a489fdf719612d52e610352462605c1a43d39945adbc42338424146c0707cb28b986888468b85f5347c8ccb6456dc442903baaee62f4bc1b56fb27dbb50c96d9b359894a823b812afeba2ba39b8af7227b8b58580a2603111a6fa511ba7e1c7ac4a037eb53a8caaa31eb551339212048865f4a5c8aa207ad8688c1e0626fee782fb6c0b97f5463d8830747b3eff7136a1a7a83d3c5cf5b32bc42b6bf06b4616055ba6b53fdf365b2c6209fc5239ad269263bc9458bcc2bf45cca868b4eda432d35a0caf361d9145a4200bc9a770b5571095eb18cdcdc407390099d43194fe096df8133a22753b7749c7b51c11b4b7a59427590f71091c969ea619601d494c91cacc34133e0cf75d1d34235a45b6977aa39847a01e1a5fe4e2c2a509a986249c482443cfa8cf3ff9358541757a776efbd7148383ac98289b4d68a579ac3fff02adbe7236e6d06c8416be80445de82619b065436468b0535906ecac1f563b5daa78b89c6ba5d4283b06795b4f88022be4b1b11ac075e8b571fc7af7d91f13334dc18a317ab4794ed69946c45a615c19209302cadc2f50c767840b397a9934bbc74d3d990a13e656d8a1347d4a46c6676402d563a0e860df9a5f0a911a7193be4b162428e0cb68b66b35146de6b2a57871bad3b166bf4a605bf3633912c31d0cb2e100c00ec9501d0be84468dabaf76fa2356a58155898e69a3c0e7d683c"""), - xeh("B65043CD3672CF9AE2CACC94F923CEF63B5127ABC63C2A5AE6C064B8C6FE7C57") - ), - new EncapsulateTestCase( - xeh(""" -d4f6ab585b2b11fc091bb28a92ab2a5d061a3e4890ba687cf532201369883ff26ffaa019319b6914b8a2d76091aecb59e37a0916e5380f2143cb34176b6310771703be07305869bab8d98fd0532847446fa156446f2ab465499f7aa81f450b09df23ce66d0c0e6b82579425748da4a4cb1a13f711791300d21c0bf8a5191f3a0817ed4519931150e3161bc1b076383056db994a3775a27b61c0cec0e5c3584295b01e9855a188a184f78baff6a4ecbc5cc1b0227a5f12498d0b90ecc450d5a278d74807af78b3ae94bae64a3baec0c6b109a57800297918bf949b69c5c905f944ec8cb7e84865d67382c6e3546bb4c891da34eed09028bb3677ba624a9d5c967e94b65e24b380719517712c12aad85672f20c77b19e477490a411389b5ef63429b15a1a8d680b0082d586955cd67163ea7a7c8c26e661c52eaba8503b14b168c8c79fb7e73109b135c7ef5790afe65853509196b099aabe81a525a0d6b6b3cb2d5400a916416688d8f960d1607c777db22b3b2954cdb9e3932432e24805f02aebf672e8e6640d949221d3570d901acd9863566f439f5a4525367337b718536623b23c16950dc59c4eb9c00b76e0d11a942fa4e531a6152ababe6e54c101433b5b41c038907a548c69b1111aec34d64e084863c950c4903493b768b831a4acc04059083d6e7a25bd71b68dc1d10309f4edb246b7576acc70838034bc0e050ab40808a298ac7571d6a392bfbe57ce2570f18f35a109ac32fb9cb7e5a1da9748cfacc022b15abcdc469e79319bce47262012334478f301c1c42583ce84116a251a0e4d8aa38366561a22552eab180b1634442138a1c370d23a6acd393cdac517f59acedea7e620b4458b03585410d3edc5264f9375ceb6df9f870c8d7393dd0c2394882179c991933b8e474a85ccc6338124604727bab826553927d86541a4da61fea2581c5d15cb70b740e7b38b1787d0ea7acb6843fda6c5dff60ced980b80775501120c46f78cbc49a4ec63a98d324a9a177bbdd74ba0ee0108187ac0e245cfc7420a9294019573453763cd4b9c1bea9366d8cc7c996853c5c172f9b0d667caee2395b7a7c7fa036be9ce7b59b96663d260b69940a2a83624a62623e8906352939338c724a038337a59f59392f759c516cc417478cb7fd8c92ce868127e156ad4abcc714328ce67e2082cf2805c3df4b5be17b29a2446fbe26a50a54afbfc47bfa27855563b64e3846e934311f515f20c68860012c43195e6a45684eda2de3f9af70549d3f41c0b17519b02a7d29b076e49a3f80554c8bd7cfdf12a42d9b511c4ba187845b5b725b1a384febb470e3063312e9a05e846fe28b155dd00253a3afb9c2143ebb0683b03457c937efb1158fa93130058213176cd7888598e457d33cc6a600c2fd465b3629cfe84bc51cb3aa8bc4111626bb57858c00ab7b8b13c729a052bc222b06745b5181bf1c58341d239db92378a83b20a7e1299d407295fb94beb2c111f07c57401e522149f9c2b0a6d369b6f829b09970b660aa3dd6b0792b21797716de834286d662a3b03c38cc9ff1aa982dacc0d6892cf01492dfc506e7c37ecb8b82603c7d65843cd011172033203e294e6920b2007631f377cd003d8b9a4421614cc20e126d07f05205d0c1883910d9172aac4864ff7b7a8b1a1f5a8c773427aaea747db3191d312b4f4a82b7d9b4ba69313e6b7cb310507d03f47f8186a15d49030df21c144b639a7721357aa2fce77149507a7c5430d9611d0e7a5c93e54593314f3749ab0025603417173b13bfd7f32c6f854238e2675a948130ea2213a749da0c18001791f31755ccd829d76c5c62eb58554277f262427506cb17143557c919443922a09c1b735943c1a411e9db8a6b5c0dfc73a06d49c86e5b5fb03677f234bc97a2931af2ac804c0a9d721ac2468058a037e53346175981c879be43400a1c0760ec3096a56c0b2f11c9b97a87bf388058424faba04abf8b4d7f5069a4f26b14e39917b7858465761fd802c7c8cc2ce11cbdd04a519bbed86261f3b3b3b07174c26008b4d71311a951e0584100ea7d97881da990ca3cbc1d9f596a798cb0b1f79353413871e5a4f093b4825a47833a99994848af3378849b089b3843c7b153e4dc10896b4a6aa9848c17cfd3e0a0c491b90587cd2611908fa04bda829f0b494b045f938e08a7bcf1212fd194fac918ead125d88e6c4463a04689"""), - xeh("6C8C075658F4257D42010EDFB1D7EA290D3344EE6E4C43DA799366985AD52243") - ), - new EncapsulateTestCase( - xeh(""" -bbf41352fb8040963385438d80125b7b78a7bb42515971c90c01323d9b3e75697ee3729f7521301d11518b92154436843987531887631819167405c36c35bc3be88d957053237bcbe1fc59fde76f1fb1c0bb4ab166ba098e6c4b58d26ba606589c568601c507a6fb149e30a9ddf126a4491812813ed0ac12854b3bde1b683cd23c588082066303931941aa5856bb94a0c932c85f9b9a4796b9152172647221d3e611b94b667e0985bac481f69ca20fa04dd57c42adb71ddb51933ff36dff38bb580b9bb0a666e80372c8e2b8c29a711f484d11c1ce58025c17d053196b50ed28342fba9b24b8093b7c286a4c1712346cf886454868ba79d53fa445733af9582113c85408c2e8473a3bc358af200cdeea56e44086e1179ed300204dd6b39815616dda5923dbbacff091970a57166b0ab5f1b25e1c1d2cc495151b97dd1aa87903204cd3b3b19830ff010d4df31ac3c7623ab64d951c9fd502ba14f4c884661d65d249c33b2f8d225c81f99f3bd88fc5a71f40722849b6b838c754a11a3b8bc8673cf900dc92b6f4f66b139c76a420abb5a2be9592ae1f3045a8da088871b45ab66610b64b163b38f641beee8a9a8f13a30996c262b2b9231241b34b5abef4830dfa922ed98a75f61cdd59666e3c728cbc8a6132a343a458beeb0702fc962439b2afe7b971ec62aa593cbe874b8a8c923f963060d1ad64bb6ad1dac893cc3ab5188e7943cf184b7b18ab26133ba4109a57207147f5e25e15302da5e82069aa721f77557c39c760d28cf37715f7a943de605193e29a6a94ae821675eb2b3f08ec4d7f0a99c5e71cb01292b327c107b61e6bf99066d74a9c8b47e99a05d8f2b9a1a5b12723c101220c57b509a42c5b28e853dd75251185661b61499ef978bd1ab9b92864ce013ce2123515ca5aad6b108660b4ff1492bb124f5bfaac592107c2678c5f04c2b658bd31cccb7a09028f48a245e638e8bcad19bbb2dfb6ba3bc10c487359b3b0421eaacdbe033b6d7a8d5d2311bcec5148226d4dec2061265c25b0746af8c63cf99f687a04c237739d648de7919cdb59973ba35d85187d20212ea537cecdd9c68de59345fa0dedd31ac6b21a7053adee561851b7be01770e07daaf903c2738dc835cccb05f5a931e2c4d2541a8328983d26b20de5bca159973bc01301d0541a8e311ef7046ee9b51a0f67d5202d0ea8c8217226a622b32b684066f2a000ae22cb1e29b47176e7973b3e9d4c18f22919a89a6573147129a43998886e8d95c804c15a01084f3d81d7f0288cfb34276536389344ed7c09eb47b9d20300abfea2a0b2878090819477a640e39cb7aa1643d4a59bc6488494a0ec3073dad9706b752c30b123fff3a1e66a8b575587e3b119d83e1b833893056b696ed49a399d11278f23f456b5192fa324fc4222dd247acb005dd50c918893819545f59b8b5550bd0a3d97ec24a5c22d4b8fb12290ce4cc96528893f772dce5c52dc0114f19c6ed026928f1092349475a020739aba5f5a45b8843157a76945dc84e7284572395345e695090b37edd895b22870b39ec07b36867b5dacff5392bede2680d74cc2272713be24ed37a22e33c36a84ca9643a46c68112a9d12aeaf67bc3160080113bea680d9b1bcfdf75be1c18c9f2e44781b18b59a090be8aa957c366a4b24a33b9b6d055674593470f37caf456b367fba266f34160d4cea1605d6140be110a93b2a57e06dc811b67572510549889002ae53dbdcc758fa1aa2e4bce4d6ba0dbd09ff3f736ce630c7b454096d6415ea32b797404f598c4b02a3dd6c98332b7440735a71124178a0622194993b442c5596bca2caaac46d77f6713a547980399c18e5685cd9dc879194cab66b99de4e2888952808b15c1bab5b712ab3e0c781b209162818cb3985b77f4e915e86779ecc5b2096104f512cbf1162b9aeba6a3546397e608d23861fa3aa5847a4cbea7229f5338ac4161b9765d74b175a4e95a68a6cebfd6ce796214163ac5b314c0deb2a3463b1f7e56b6ada724a2827f60647a92ea4f33d36d7683402fb12543f73a2804abd00371073306f06aab9705819091c9afab226514bed5c46f8c3c8046787602501d9d4561582164baf07497d09beaf06cb2a49627663e04cabf05e5bd55f9c0f75ca0a93678ffe69d7f8034b4f0898ce5ca9a26f52b3bae41398ef444b73decfdace24a6d62657cfe717bfbb904ea4bde70"""), - xeh("BD990171C3252230BE21FA7F186A121686187B77C234C37CA5122A7AC77E318B") - ), - new EncapsulateTestCase( - xeh(""" -b36a6f80ebac6014cff91b17321b0fa32c4d1eccc3dec3707cd34c7bc63e62d2b57ec0314b659dff4263c0f2c5fae2a37a84b0dd415275b3452894904ef146f5728a76a56c9447988767390a693ff7e91fa6e36f3e5a5b42b97f1205704218379231169340c416f4737e06364b935186e79a6bc0912938ac1ef818d57878ee872af70c7f31e8a5da0746ff4137e8f9b6bd7b4b32b47e12660b239c77115c72741c74b8dab0fcd07180c35e0adcbd2d58b726e3775d288a6312aa158620022b623bb29e141c33e0532e5dfa67da9476f49a6f4e6b001597a54371be84d70d04340c2f403db373a1afb102780b5050c841d98b10af489a39f8c2e473c23f202f05a20dfc4844cf1126c562cc9610a98b0a2d5407169db917969b1aa5c314ccc96290d2c27743b1efdc410802c78543ae40686cff6b3dca439e243c867d70bb957086abb6a91b49c7a39bc2dd107f65c7bba534c1216857d2b1a7ee99ca0556b3405b25da0a0941f403d0e34677e49d1ca84f267bc86ff0154614ce5b3526aec88f95285c316175e15b4fb92bb3d2a99d70a0259ed295eb87b90b5b2f5e2a757692262866c70a9cb8d843490e563594344e05a4051b3155fb8817ed53431d5c0318146cc31b0c524b6410d53aa0612a51f1c763941c4cd42628f212c04cae54b6ca05a5afdab8ba54f5666a13396006afe7005f612180002d1005795c468cca3d778938e187b00bc29220266047b22df76b18040160a48e6378c99fc5afa4020fb2b135ca913c78c73363d93d10677bd6764a27221ef2a2600f5b867b52c375cca78846880ac448f1086ff678220b7a238675b740c21bfec76559d573a6a84190c750cb502d9c7663d50987876b607f548ef76b764d03b704781d3b324ed2d7c1ad285a3e1ab1e5d6c7ff49495825b1b41a5ac2f524bf27c2e875aab1023c5f058f1a7881c3e60ab9fb56d15562b6fcb8c8c04a272c8ee6c807baf6227330071e6c49c8c805b89b6acb2025b13c08fd9916cf40191b9520409a6cfbac821fe8951c027f84a11dce4c54db98be7427b724331c64169aec4304cd71128448473f599eeb8239b1463cbd43c0836755170c19b3108dbe42bcc290cf23619a303230f9b0982c3b7307734e940807245bc097649d2eb9ae2b0695fb56b16cf90eecec1a50c5157d48098a063b53158855c9a1f1db9ea92b7bdc2488bdd28c095ac4e3374311c2754cc56dc8e511a5bb4cd486cce605527d594ec1dc1356b9bc938c0488b6b6d53243f2443223ba200b0c32c6f49322545ffa8a2b1bab914a72918a658b6a053d91249fe0c20360116eb3090015c161d4480d492bc7644762a48b3f6b558eb1f9b34cc39398cb266be91c414a3ba790c9c92129e5d40ddbd3150a5c002f763484546519c3a2ed327192bcc80f4710e8690a8d30a36059b12df6c107d1a73d9bc57796ba08fa01fc0c2a4f8b7a63074786729e0596615ff4b7c957959ffb1c5537508b191507e16d33d1bee9eb2148618bc8b279f0e92072b8c037565251992e87db4c0de8775d151ad13b2c375a46688518e5a2c409e32b9f314e3b177d72a908f3fa0010c87724aa2a94ba6a2728824719c6a1b0a2e07c7a364a0a62cc2730966ccdc96eed27341f77389a854fd12b9aefc0aa4c59a8aba457c57222e7065be09b593dea82279c8f67971a46878bf557b8dc095a9a0241d3b64ebe02137ab14eecd7410bc70efd3c08c1d6220f597eeabcaeb4a7b129ca73fd96872077577e44c804bb55d02607234961816b85944913dd83c5c835b1c0cc94f871a29073b8912973dd430246f84780d51ab9e163cfec5bc3472e02377bc9a2760ef5529568a4497c556e9a5f71526396aacc3e86158ea4189906b8ac277a90e383e298c8a1b98623cc909f18c894daa83338bc3f3b57152cc472889ba297a533d0554a3186229a8514c9c4826725249c61e4411963329eb99a37a4337e24c2257e5354ec5c2e4cd85bdea15c4e16cffcc628dad7c3ed9066287b587cbab64f0ab3aceb69494a333d240074c989cde4932d291f8edb065577985f68421d312e429a15cb21b31576c8d0b470c2177cf7369d45ac839c5c191acb40e62a115364c8875883ac507e5dc90a6cdbc6a540b396b422e488bc7d25c8287b79efc32085758d593b33882f218e758a3186d9cf309538fc57b81edc3ad0d228aeef39b32aef07a4054c"""), - xeh("135056EAAD8A28DEB1BE77EEA30CDEBC7B3DD89D1444DBAE145F39898256ADB3") - ) - }; - - static DecapsulateTestCase[] decap512TestCases = new DecapsulateTestCase[] { - new DecapsulateTestCase( - xeh(""" -66c1c53cf37af5756e10648db20895447c40e147649357bc19a947f98a20908360dae890abf92f5db10deee57844b51bf15ca71743cbbbf647f07ba8f627a8e7bc12fa29c941b2809d48448147c94ae3081e772b4321a6be0ca55632af43bc7991483c1b4235be2c4e2582bec03c4531e8beadb504ce55a3d837c8357584d23bb430058833ab8d0c5912255a363d5b623bc88e70a293404c253127abdd3495b2d6cecca2582c7544280cd0c3f779e3facbda109a7b423b29a1c752a632c5e4094063c9a79abdd4947b530c3230ac7e567ca412b6217da030ff8a120e75746f26b8dc2429d76a0a5a06b029f5174c1079487a1432758f699032f2d32f218b625ca593d3d26f5d75b0c5651358ec8a1a6673aa7010af290c1bd1c6ae795d1b7318d4db125d970cff78c2810937a2680beb10b1200782d5682ed8ca1fb288212428918cd3517a7a999cb8ce4d442a9d82c8b13c5337355cc63b549c93c9c6016bfdcc498885baf837b360412e9f517e6f49baf1032620585b3d3270644c9530327382a5bd2ee0a538a03a0226cd1e6103f32b5e2b946e03839e4dd247f6957d357cbd1f1bcc889511306917a2377274c8bf31f41cd66a4bc93a8fb5718e88d88e1664b35cd91a7e324d4cd86a95f93a49d0aae96800a2a23b806542f9f02cc86c0497dc6f9933c772a7b497da3e64385f14c2c9b1624f37092d5c1a473e963b3aa6b67641112f501e7c5981745469163b8830113bc7f77a254750541c9e08b728b834b0cd39528f4a41e862ba4a0cc6d4415dc99a62a86562af7640d4487481c57009e1641376918db323c54b98ffc1a877e4b712d99d6708172fc6400da1761ff6ca603649ccc93824e7c601b75272580202c0434a199ffcec00b2c75da4ba041e766a8e9141785457a148517d58981fe031d332453553abab73ad287cbc610cabeb7822952b7e79db10a1dc4729f8cc39e3003756522de9cee0385383d54fd363613e8727c06a02dde3ab92c8926be48e6a386224daa106884eb18c7cfa1566ebc5ba6f9583c9a745bbc2c642522b0141743e6837e4d9a603fb403aca55bfe509c6e8499d78b750e516b8a67709468d3fa3b4d74c0a5f5a4b5cb94d8ca92188437040f9312aa41edcf274f0aace043862471591e84c0e05d61031d69f4fa11f4e8a0977673ab30b2bec0bccefe434b55632c6057842d977027ba616e6a7fec7340bb20c7331b4e2f1044e9692ab0136a0b285fde033ffb25543c5c9ffd83595e380f8e831701b1e16e040600c1c7924b6bc42331d987b7d63c007d76d198c0c32aa3e3663ca7606454a214821b15b8ebb018026aa1a618539c00d0a84c871c1baf016bc426b3d9be7598fd8148d63865bd6b455fb8a47562e95666e18405367d4cd581162fb878d8c0c3d627597a4811eee0963d4926861ea202d46a6a6e94e89b3cfdbf436fa2254f060ce6b80b4bdbb98da80417fb53eba8286b58644d8d84654fcae20906863fcaaf89abd992b176b05b2924bbe566728878b5e816b64a532ce2cd41f5a937ddadc15baf23023a19932b337f508c8fae504a3aa24261a9bd20701a2d3ceb3c72ebcd5807d358c2ed45d0b84092d6c93b74caa20ea4b5db66369d26fe64652270949a930bbd0103ea7d117e6160d9dfccded58476b94ae90036b68a40b9bfa61b15c889467a0a01342f843be8227ae9cfb1593c240a8735d8105a36c2b68e5ab97671b63a1cb1eb07495fd3bcb380aae66d20f3bb096b5db9944d83196b3bb3e321dc76c3b7d6828f366585f75a3c6d370f5580f22b385319483c9c19e6e81cc22690b18782c2d47be5c81cbb1c055cad84db9b06b15355697ea23a2374f027a63197b46f28a85d089a120848e94e9838cc72d1aeacf7d64ba69a93635c6a10ca5745645416e071a48056c78a50a0d4a60412966ab4961819918211a661cb839b01101798583934c9ce0aa447170b870306cfa02a16b9316f4f22d9b958a38b24960f0203cf2418495446c558a6ed8706d8c949e7b14cc168c965293d128ca16412ff7b221cad771d441ae3fc822d86645f5e266aaeb1df56a6185747e3312587d1b5f51e13e23586f9f3b1cf393bfb24173d7e27584b061f4258ff3c29d27167f58999b6b87a820b56fc7846cd3a0953aab07bcd256cd997b4e0172cfbdc0c2fef1b5fc616b03d1c3efaaeb7d48c64a0c839085160b4a5732eea1a09177c4895f1b454990da691770698b54c8cc8154c652046cff0fb30d40796732acba3efdf731bf7c242aeeddf5eba5b131da90e36af23a3bce9c7aa93a"""), - xeh(""" -ea231b200f36afe0ba1bbd719812ce994d5f6f2e60403c1e4fc1a295423e38a77d66bb06645c4ebd004542d2e39655a1bcc461af8b5d1882b8405902c8c3f63082d29f263cfa9527f04d8ac9eb99b9ed322079c5bd62c8b29c8a22992eee4cd6d7152da756a405bb0565808f3ee3d592c659b6da737b7ebe5f7196b859b04dafaaa10056488d4d455a939cd640a0031dcb9b4e5dd89bd634ad9c8003b924f76702987b6914630c5da035e34ddf40af1bd6fee7eafb0c602d91ad848f45ed222ce1334bfeb6f69a01bc4e5a11d044a421adb30dcb08d86460592f2b61f67ff0f02165b1340e9f6e93f88fa8d9bf1b82da7f21fcdddae82117881416f9b48833cabf7656d138e9dbcb29e0f4d15f11f303227a8ee6d04de284d9c76e0f35103ab4303e67ed76ca2f11c2d440e6df881c39fa1f2fb435b6f8c517c6a341b1cdf45064e7b67c1cad43b2c171e5557bb78c5ddeb9af3ad756451c70f10a60157750d2f40a5ab9fae21621484b110e7232b9ea9c52ed2c1331045d555dfe87ebe3ea13c52966080fc140728a26f4438fd25b4e5559a9ecd0c3a73e23c976abf2cd38a1e2f61e6c17672b569c08f3c2ae49add14370a5c9bdd3e5e6a4c0f7b3369f95dc33c30cda832b349af1f4b8699ceb1e17d3fcf515c2358db02b9cf0ec8b0706675e5003db6cf2182e34dd9d030e90620567fb83d83df293092efe9f0e935d79bda625826d45cd4fba547005b9e416c07112286eff057429dbee4822b935b3e16f9655a5fe6f362c58c7f52c5cbc75b733911378f174f706e4bc0b37848d274a29d9de894f5dcca67f6b80185b371f3b37e43d56e374070d6831f0ae48ae96c15ca80bea4eb6f37fb528064f09eab83f95d40c4a80feba2b1860b6c4bbf44bf3e4d4a72a28755f00126f0e4cf78a81cb1d8ed56f615e043e7b4a4f219c4f0735f68589152b5e0a81241ed434313635924eaddb815d0495d5fe065bcf5c6870b76781e486643a858d972e35d9c61be9f517f28963cf836eecb05f24777f600962ece48ab25cd32b80b9e96924f7ecbc1e3f29e011b086d9627770670fb7ebdab4c5""") - ), - new DecapsulateTestCase( - xeh(""" -9e28069ea8b958931b9241af966388e1f4c336e0a960b266896b32cf80889750ba87e53272f792a1d0bd68ca5d25035f42d092c37882ef7c627837cdf6c56aa0185facb85d03bb8c353c1d3155a94286245ea0b2476b885d7c298ee079ccc30a717b7826076a95d49f060136529855beb163265851fa256393bc590e2a7f4fa83fb3a0327fa56c3f55bbc833c3341caf82690e1596c52f00a63e49998206431b564542cc0614d7af2437ce879223f529c0db41ac2f8b8ab1449eb8078f391227dc6c62f123950720ac5c841ee96a4f80a383907c81dd6b3e2d4a040b15301fc76aa6b00029217b1d3718644672e19998a74691dc996829d7a918662cc42c43b96a1347a716f41b11c9635f4a425260a1498adc86a6a111b2997522026c6a1a0f4555bbfae0aa262282c04c1058dc9dee882b81f3c8dfea72517717f1f8b778752cef58ca93a31747f833800c632ce9072738040c0a528b7704e0266aeec4c2dd27085a702249934bfa7b47d25b8f03955c2bb42cdd107fa4359131943aa4a78f716c26d2f448eb97249688998cb80439f4124db1cfe2d41221640e82021cff731397f50ce6c9c50b181a4fc8af39680547757f481598c5ac74867b4b25fa30df83192eb57019d36b00164184792b2b1832d107d0a2d404ead54f380aba0deb8fd10a6a018c9ef1b7b7c85ca8b3811ee72730438867b6bb32a8c517175c045ce7b562f9ae7d20ce0eea053b408b5ac745851c0e735c293a7bb89d4007c0761513962816a57f44643e170008bce2a64c6295c37392f1207a9d0bcf9fb0af7c4b7956bc2e1a7cbed9e5363a4a40de2c3e2d4121ad0acf932cb5b3613e052b109038160f9c4f4d5b6daf20a6a6334a7b787a2a1754969930d2a9a8c68b67ef4a4a0aa86e22e28479db632f0c1eb0e96c00dcc309007e4edcc97da65a46227156fcbf7b43898d44c419a099cebc9248050f60fb5e4156679622bdcddb62b70a8edd86a31b766f5818afc89932578a2d0bf845da2508c6e86c08414467694ab04321cbc77fd1762e60553d098b80bdc0cc7ac2bfe3eb02f888a2141377694506ea69341ad51d02065cbbe01bd1025aaaf94bbb2bac27e678fcd7578ef9bf3026700d711aca31cd4a9641a25286b26c034228cd906434c3e2a56f01b54a98878c6842b9bc9c8d95640bd496c0956446a0cd88d344d552a838e29f48850bec6b4667749fc4266ef8d5c47f8b21e7e108f8a58d44394c8711470ce8cfc92b2e49ea5b8b15772e4389564ac8d568b700d11eb5f83d018514d5d3acbd7c63f667ad9340b2dcfb972a333df99ab2dff50f570a4d0001a413a98f4075acc5241b5e6a6132551b9c4c1c22551b5a008df7d5a218783c2810b79a52552afa922de76dc4b89d87761cfabc81d218cc3259457316333c21bc9b650f6383c350e6681c694496565fa7203d05b0caf5a22a4ccb1fe7f00f89297f3dd02915eaa2a881cd41599635abb85890649f1a4710142c4aa4b5e3d71188562ef5205925652ae7606e30dac7099495ec939fc5b0778477be94185c649c858e146cc6750d3a1a98424b2645786681a1b1095979f2313228f96d9daba787a257f4e27a4ed3377dfbc71ccb9ddb227151203798b58f44a280c733a8aa8a631fa303b26c33bae7b088121d917268aba41cc797b7a3336f12101d5ee8900872b3a1710c885811a2d8c4f0a188d4352f259b62da152bf2a022dbb9c913c1c254a44287546c01053bfea0bbe3d05a24f1b70d969feac7c7325ba69ea981c5e179ad564e7ceb4ff38b824f9754af15664ff7a807bc34e62222217b96f364907916be6ef0cc99b014f3527572e0a6be517d2225aa6eb41e4c2a80aef4a212092bdc186598a69b4d0037cfeabfb13b9a9bc0019c5a83ee659100bd76a1da4b30b686ace6291877ab9d834a641abed635b8f3c536bd6394684ba283da1fe7797580924fa6a65e9de87bf833bd2e67c4a9e037aae0b3eb1701bc69add69127a98a5157a6b3f8393cd104c31a24ad3e381997f28c482c5dd6ec24d7747b559a29d56c0f655838fca25c4ad49e6cab35da559b354b55357748edfbca6122601a945d8611863917c48ba20d53b71909746723b4355a620b880cbb63f260ccb10db6d3809a96740ed153dfd07ba60159a3194553fa93ca28513a65b047a7350a0c6f43f7a09f3e2771f461bbba1e3508c8f8931c16ee6c08e1761b10f2eee40190ab3fada5811a768b72674b1725bcf05d76c132f99a60d235ddc4f334bfd91d6b7df1a4fed84c88c2933806f13fe06ef15aed96c9e1"""), - xeh(""" -cb7eb96dc952919624e5825a24ca80f9e2a313bbfa357af50438fa22870029c8f876cbc9cef450d124df902e93618d8dbc8d1344cc51fdfcb19788872aba1f13f673c387dd64009e1ef98ed34dd5c29d8849f503dd064424b39a8b55bcb714e6d09877fd5d7d1d721b2b32b871cb453b1b00587038f5c313b807b356bbf7fb9a50a3573a2af83f0e893c32a20cd95b9046cac886f74967e6c73e718b0cf8470312cf1a9241bf25238a3bb54e01b471bfc398b5e23ea7cce32ade3169dc472b25fc7cb68997f2bee116c86415245beb30a01841acac6bd06c82a6644aefa24601a2738fb1bfc2b08199d1574dd87d9b220d12866199c01b6c3372c204855ce8884ac7393da5479818f26dacecb32e43fc0d9affa881b4952aa4b95b8cc563e1cb4b06ac2edd783bf8cc4be2dcd0d3105f73c593f40771bba6432c654f34849f704ed007652628db269bdcc6ac14f1a15fabfbeb7529a5f3d70244fa2e7bfb4efa23199b88defc15821581f6b3ccbcf3fd75e3b41dc8a50bf21309e395d8e616d7655bb3e99e3c4cf09e192725ee5eef558f84fbaecf144c69742fdb40aee854b95c80878904773311d832cc5673ff0078c4f877d4f208a538ad243ffe87b4698af6ab0d207b338715518fd794930a8650fd5cea71f035623fd19dafcfadea4f53db42e76f5e61c46f1da934a497c3142ceaaa1d2b514b9149f34d1bff9c5f71206959b6e24a034e5be92da9713d79bd885c6500ff3dab4082d488e4932420cbd395a5d612245e81e8824d317aacefa6a4c93b82f2d99865dfd5d8a03623b463f0deadc1345d123b8ff876198cfbf945c0366a20a0bf6d5ca3814504591dfd731d033a30e2728b74f859f0b91c9a16bc310450ebd69d4da09931fdaca4b5721ef2627053a47b8a290018ad50a4c2a0e543b130402a323bd94bbae64a175790da350128e99ac8d9636ba12f5de00582a61bbca9acee2eea84be49dbbbdd730e0c078f94af4bf44ff8a8de89003867f94bbfa55bbd905d7a260c23ee448c198fc7a89787ce879c04a7a77f379bd55dd8c33c484b9dd070b116645a4a44506b8488db""") - ), - new DecapsulateTestCase( - xeh(""" -1ff7b9950a3965da1037cc7e93959b73fb975a63af4069c76ff9b2a97c2727f4bf72aca77874771e938dbbaa1237781a7560c328b6ab6b372a93969a82d9a562043bb60aba1c6a2d35249e0d248e7105421a248ed75cccea32634c4b13d05b64be97689f46c4ed78b224a99b674a2f70a79e82a025a27165a52a3a656067de520a60858f5af6cfa39952360bbf94549e4046c2b65a6683994a5cf45eb465639f13bf7adc494b02384c28c5d321c7090777bce454aab17961cb786ed9845ea29bb8f2a322a34b921420cc800c865706be4b0de4c7c9e6f8bde4f4acb58433dd71031c23553136a25bc7c1af30030f543d3a86785a4791455cae59f8be1abb8e35a4b9ee2900e6c601f76044a3235003d963eb7383bb5a88deab5bf05a621e83c3c091c410c03f07fc8d59ca7def463f69a162c027ac38ecced39754c7a9558f3299ef41c98f779db82aaa7ce75cfecc453b801b0ca77ba505c087cc8a890a6a35d1688f46042ca7755a4804b896053da6114f6acf517136c485000237bbdf4829d966b3b6c97aa0b93046e6903c82ab552bbfdc1aa1bc7635c14c058c16581c771e9ca55115cc1627fca7ff650084c09a8ab4b8cf45a8bbe7162ad99274bc9024a96465b399c94b44af882862eaa8b98b32c7b280ac909aa8c0974116596f348aae2b4f0e533d291c6eb827b8894821595892258809dba111adeb3f184c490e49330441a57ce0b5f2045f4ab182f8764930833ad2c189ed6602e61c3815d57541a5b91beb442275939238c336a220d6f60977b0a0ccc894748abd21aa064644ae7a037c02c1246ea6443b23522886a290103f16c16b5c621aa67872fbe83603c47e6724374eb57c91c14af8265858f19161e756d927417d356a50733326e97ecf7a567736c67efb4fc18558a769cb30c756ab186d0110c10bcb7432e672394146d0e03d67794744f116aacac81ccc1bb04962ca331ce742167a654fbba262ceabcb9db5baffca3e3774898ffb6611c8698ef4af489a94d1e16ca1ec18f9d49083d712fb325f7dc016d5487eabeb33e5d996bdf5b8b45a890f099b0feb3521f82d335b7558ac204e11a305d8b1526835e65a110d813499acc36a5409a15a8de46633bf587a706a7d388c5099c73adab17035a347b041cb82938da6838a11513c5756b3992ca2a40c91a450505be4cb4fd9625d209110888484033d09f8b60eeaca65330beee240f9861e768ac7218a6e41a1205f55b411e275253706c57b97ea650c6e69876f79bffed8759ce30df61465b4408a18bb003a7aa446642c90ea072f955f46044f4ed7b9a9b82749e56ad470b0d21b67b89cc7ac784f9dd016a9ca5d2b025668421c25a100dbc0328084c2e3367c022b60fc6206e40aab3a863ba8eb1f8682265af69d15aa9d173204533a1a7ad94f693310663212e4aa0e63f812f1608e1f9903f0685c9b9a797ea5939869b5421b87dfa1ce818265d5051038a9331168ce01971efc06cf02a59c9e1a03373a600f216f779aa73171be66f95d81808daf63a26cc3709ab58f22659ca9587c01029d915c7554946b217044e65a6c98258f6a0a2608a9cdb4c35a0e06c93b19988c221c96b79729cc227ad5c3d4f558062ca3179b8a0b6c0d6de0aaa466c498065ce690278b8980c7c567d308b181b06667f297ee9caa28ac2f5ab454b8045eea583d20993bf69359be500247b3a2ff0b95e243af49b6a08eb19c00f31f3611837cc64b85d8bc35da9466fc12967b158dba95782ab771c134f9945df0b02644fbc949cc633419c48643764e0679a690cdf0239b3aa49a58e171241a106c151b75197f7432cca3d6c133cca0a4902ed6c299a479224ec7baf4243152877adf3255ea114fa01a65a53ca47e3a6dff072d991730414754c831b3763a6673e9b8f4f7ca4d3891a33c542380cfbfe16a650ab749d79e08570629116ef7d50338f26834e298dec8abbcf588f37b428f211434666a1c6041a3a09918293fbff54d35c75c7dba2720a0a91592af264b446105bc5b41344067bb3e5943d62aaca4374f92933e3d4353f1898868d097e504cbb934cf727a9861169582bc4414e46c50c41693909cec50beeda69aadd6073fc1ca3e1a6a822751a404730c3c90a4ba6a9f4343988280eca4c4600b413cfacb8ce2823f2a2b96f56d9d1effc2d3292c0720e7bfe6aabcd8284abd8c3fe8aaee1bfca30de00ed421da54add2aabcbc9c167ae2c0e8331df9e9acebb960e9169d90c036c14612e7a22ec88bb5e9dcf865776c37cd5b1c6d1b18798be80b9562ba4752e1"""), - xeh(""" -7ac45cc6b87f431f05a28b0b6f8ec44fa020f8a0f798e4463e084e58c950d643a72fbdcb2a8e442aa2a9efa2345111838129097d942773073581f8828baaafee93d3bee80ed21e13fab0585b329de6348acebdf25e09f13c1edf96789a3e6c7b7e1143e0a5f408e33699c68ba140410e738e9501e4a087390970a86e212e3ccc18c62b4233ab94f3cb7faa3a5a8839d68514d851555704ae8a601d7e1df4f3e31390905945fdd88f0eb8a39afade14b0ebbaa16077acb4e3ffa41931bb057e386297d90045add3ff509df9650d86d2709d89a5fef748b15e5fdb8aa5c2dedd84533b5ba49bbe88ad78224379fefa0b68bedd76379b5b7a06235673f83871201316d9f8f050645f6d8031fd951ffb2fbbe4a66f0010abc8752ec509ea62cbf2a59c3a927918b06ae3524b6d94765f5ad6856f5ddb2cfc036f2520368a4e15cac62089adecca6b83e8b9896b48bb4aa4f33656c7a2ac3c02539c0525ae71481aa87be9b956ef8b6558f0bd2aa62d3be2489a4c477c605220ae63ce5b67b3d517eb53085a747c0566449c06c9a54993a2ab089ceb3183d5e69173b635d52b87d6c1e0dfd4c3f8a15e0cf2d2cccfb2d12429c6c174aed9d59ded4bed6ffb964e8d97d4d10ce0f2cb9124a4f88fb864bcfb6ac358824bf0e7408e19829fe038b481a4b161ef06b584eb720884865abea18a05a00d45b27ac0175ee1667f6feae675d8a4b85c2a181a52cbafd73d5e70becd0ad0b27b08b14ec2185e902bbadbd3c7a6c1d49a3a8e65568e590b44d12d6dff7abebd9158ce588d73a387f8dca572b51c24649e2ff02bdfaa779759b93a70f8d0e302a25b528e26a038298437619e4978f1af582d19a11ea772fd0e705dbcc92129e4e9f88857b0cde3da2055427dd8565b20e1531f701361b731bb2dc093f259a01941e255a1191718098e5477e27f7a3188339a1237e742d71882376b72f55bcc4ecbf03f1b29e79a1f0b969619755fa449f1727635d9eb71b977f4acbd58e5c72e89433689d5a2c759f7feb2051eecb6e4e2d3f37e36d863b4aa86d78df37b4dfcb453cae1c7869a0e67f6af60d90f""") - ), - new DecapsulateTestCase( - xeh(""" -06f89c5592b91a8c7141b644db94cca7c52b0f36a1bbf6b0025b0b0e994b277b77ceec519e24387b7ac33004b38afaa2d34c6f87f9287ce8bd373a322d55c5f9e79c8f72bc17971c5dc77c2d26aa1cac4de8f7c2a613454105067359cc414a689184af5d5409d1e6bc4bea7dc2a20b11f272887c8491a0c0025163bb1a048d402d2542cb10b261e2f9c446304a98336a422ccad181cb53847275899d3a0c74a167c39245623620242d87a529119727933ec9d1b717c14980fc56dcdb963a48ad13239d7048773cf5269d3a5797016bcefc0466b6b7575024aae92e0c751ba0315505944dad99b54ac516966808197a714c7379e60c7dbedc9b7fb89fcdd96808d2c63ac13130824f5034c8843420abe07c837b4f853615ddb4900cb6abf3368765d0544c67b36570598746cdc8017b2d0a778213b7a15b492f4c9f462aa9ea3a99c9bbcc9f2052c4754cd347adc22b446690908d791b9912123b67cda366bb9ab058aa5285e17018ae498f1c7a1db6846ff7b30d3ef43aaf0c6bf2ccc574e44f29f8855b787ac63ca4e1a05a6b4a972608687b18696ea18ef69a660ff335ab54646f70350e5c236bc29835046f23ca2b46206f227b4d2f1c56e9394ffd70622e22c1180bc2093092307a34b9b4c71f514b8c890205fc001ab4bfdc131f58b751ee4011a55859b000088c6740e9f2cf1639840d0b4b3ef9cb7a133d5358923124cfb7c2131352b7e1fc590e711c575484304b0975415298c7ce558662ec621f9d1548b18188737b96e308c267acca09317453b863393aba3d96c9a99485ece5ce4dbb86675c21bd5a1356ca11e5b7050bd9bdf22418e24c966c04936a39a949f00f322b051dd40fad238a773b23f2f84a63675584a04b88676e0f864fa674658a1c2d5d7990411b7b8fc21c2e08c2d3da45bf55060a3b546ceb8e58f1326c50b861b7aad69607f4580236fc4a51e03b3479c8a25cc294aaacc5b376a3916ec41739ed11bedcbc445419331be39731d6c136d40a65000cbb046e48409f194706c09c6244401877501378751352abb7d8d52fb5fb47a76788cd99a0cf217f029c77ae76c67fc7215e493c8645af1c58bec08b66f66a92346b92f873cbd646aa5dc2b9b6e4c2848a4324a8318e9983932055c4f58f42346df1da07977101434a9378d1a1559819756646eef3094b5ba55e33b596b71c04d249be4b8318a4becb008ed71000ae795ed1ac873e244beb7c4071047e83a8b3c6c2be2ab025726063175c4bab391597923d030b5a9238b131383d15dc2a4bb812a8539f9b0b0876a23ae049777e6229c1068a37ab13a2406c6f7ba4591520d8816ca3894bf3c601fdf493e70c5f4b19bead520d25cb6e8439a548f35cafe81497b297341005fffa18b99754cf199ec90504f9f16f8e415cba718318437aeac50ba8413e540b963cca2202a35e356701e177ab0dbacfe6a0c02b506fdd6436982737f903b8a8204cbb07c380340c5f1a84685392a2b62620004caea2c416e61f7c7b0e6e202d92021628cb4c10d57d5b60ba4d771712d552d1f9c6f352779f8c32fed54a8eec59f4b3177c7c3e81e3ab7dc83a396bbe38ac0fa3ccb174442ce638c6a0fc1fc9c426b5eab83d0397b559a97256b2b0817ee115b1e026c445629bf7a8803ff71aad99385a1abfdb22a3be0029503cb44b7a35847bc675f17437d9246cd104bd8608da3005e14a632d69006ed4434c80594b2909fe284203571eac04a00a120c24d050f40952fd53ac0cb39bca50c28ff450a6e208fb26bcacc1ccfa89bd7e05616a395aafd2bfa59cb541975cbe429919b32cae4b1f4a4b4b97858390c164fde76bcdb32b54b3325392c385d647b265578a1c56dfe5a252144ff1c02dc2054bb53525ce4b3bc2ec190e3ba06fbba12f06707f060bb1659607971f3726b9f59191e6e7b252602f51eb281f454f1d80a60ea29eab42752df9a3ce376467f694fcd288c9fc7851c04821b53e693208867604def746f787ada2097740ec8462ac89baf84c0d50bedb539ccab33894408c5b4b91def7955923a283677867a356b78c5a8eec308bfc982c8bbdc9e40d7695b42612ac27f6c118b5379518b49e338738e830fb6a66488b7115d24895963934688d91fa9608d41582e79e5d417ab07c81d39415fdbb870a3f503f1a197bbda81d7c3204a316392fb75016f88565a73a51537728ac70111a4771134601afa8449cb475bbf9789541ad3f7b5f85a4f54aa3dfe0bfe01174ed5bf4a40e4ce8d367598819be8ec4ed706df4d26819f69729c2acf274515c8e"""), - xeh(""" -574c9a1db78f7ae6ccfcc6ef48b8246db140f1a0d94a5bfccbe8b807e08889de2b45666e78b96eb159a73916947c2ae930c389b6c858d52144ca1f5c6d66a43f6ddff5c233493592e89f196220ad4360503ace196ef8057800c2d05b5b12e98203986a45c0dccb4ce1bf84b76e3f6a84f6e8356956f0b05c02ef2552e135d90c61264c63033848651c71464108be23aa0004fa1ffac1f4e1022dc915abb7a9f66b8770386e4330d7a94722fe54411fe0388599e6ca1463c9ff6401d9b37d42a3039232b62a7f8dd7ea125a4e54feedea008d51eeda575b4ee42031c908ec52a4bdf61f1ebb051c65cb9f9c4780958f2fbc0fefd38574e7b09f48412a7990246cb64dd8da41d68f0c16468dae921d548240d14b3023c830cbdd130aa7aaa87861f58f2530f9052e84ade036b717b365c8cd897b20166859c95bd90a28ec0316a0784a9d30da3fc1a80e012ecef3d1b12f91766fde1bb4a99f4cb00a94fed0f345870881e777a6852700068f5d321be5311ac813cfb3f5acecc6ed2e0225e016856ca379bb61806e3dd5c264c31190a7f903f0691b92a55ecc40a0a683c09636842df5337b6bb1b2616ddafdf9e526b757bc33831172722d95cffb2162941ddc584e70055b1fe21eadd8ddcd04c2d574ded14fe924c0990ba81c2eb6e146e483d87655f139fc651a1070420de9d3d82e9af7591a981d1bbf650682332f3bec1ee2c291696af40d54289598327ce64c32c2c77a81a6b4818839e8a6145a9eda06570ce5a348a72e8c332015387298eed54daaef0d4950f1c94646e1bc80547209d23d51d50fc86f4fb4e32351ea2b7a6451a8caf36e211df0a7427a46d9ce462335545f133fc6864286ae2349ab61d1a993da4f81ef523b3f1ffc6141742aebf63ad97cd6b78df8d8f73b69a4d6efcfbba2c44da1f1bda3cb41e725221edcb4a7754b9d79fd8ea8bd2a11c73d39c9d10a3abd5af6c145964601a0478d9c18573907fa2d88ec51b56ffca7b51a7a604706fc035dfc12366430234a46863c2fc03f3fb599b7c99b58231c28bc571bc629192fd3f15092bbf5718e2644a76bef5af0a3""") - ), - new DecapsulateTestCase( - xeh(""" -1e4375ab948b3505593ceb86f6d4938284c069ca2673f272b7b78479dbb923128983d882cac84076ccb047820dd6da22419aae702c6be0274273e1a5ae7badc7456dc8f0a34d8cce6608a4e5605c9bf2b5bc232afa9b32c9225ddfb87c24343104d3b14d3b86f8b72fa336344cf32315f296cb88c3e8a5352882acec72bb68470ad9170689c938f7a9110ec0bb5cc1550e1b5e26f44a99c73d3a5c3fd48b308ef854e70956b2402f1b5990070bb2f365cd057bac1f4599e85c82363ab851fa6f89e0ab188b28be11ce7e52060ad21961c26f037662319950e0f2c56793984a45560c427160315769e71f9e6b3535806bccb497aff0944d004a3f41c16285b803ecaba95789129242e5961ec48cad3a61753b631642065a378155b279874ff038db51a37f1445cd496f7bd220e5796c4bec29dbb9b982d04dc08ccb55283e041350688c9d2ac639498bc5eef46e7ee721f46932ed4c790ac18c0d11cfad286a2b647c37901b841984f7a11c0412ab8fd79ae47375476079d27728b5a01d537a1a37640a95166feba3b16ca16883a4096d511eaf1590e70c6ded992907e6bae99acaf8a55154646056815c8cebaf0fc3c789ab485ac0b8737258692b2fa8db2f69aa1577045769c92d8332906bba0e44cc79de2c69549a4605548e07104ad458c90c29a826e04e2f1442cb170cbbf4ae1bfc50a7a673d633420c56596b7b9cd966480143287b985abac15de74a5db1502da05088613712829500adc46425b54c080bb2a0bb1c9fa53f145a6ae655776df15ee60b38e014abd73579f51718b548cd418a7e7f29ce1c57912d77433aa34b00db00f3f20a00714e0da2a489b091b2e52daeb58dbeb759428c3a85219fe13995d9c0baaa468c5df3bb51c282d3e13166917487a81dcd837bbb7acc75d2c35690ad3aa412c8610a36da87c9d8669f56c68475096f853569914961e795a3795328e33f3e15c1ec940b4c5b4b5756c772d1228fe54f6e05485548675a6461f8a26ba7599f708526d57a0a67c0a20e25ab02dc03100687b8e375358b9d5c149a132a98fd29c2add61da49601d8b70749d18159851028c33af8acbc9ff37ab19a9fbe45a0f08b9cdc2268d6e727665429f16448ed840d0a87c34c3422ed857c69f3168820b0ae998702ac6f55150ae3031a54fb80912ba94fb4bb31604492f406f654855b447b39d26bc81b0d1644c1ce2a7f347c239cecb0cf89ab14917192c12e7a694581021e96fb6868282df0a4850bf3acfde5424781c571e8857cec1f3735a464ec74d859b169142e2e7413d2a02c5e93570e3b9bd18983809129724743a1979794a2500e04a409506ecf0a975f58bb0d08b36c1733927c932e7c73afc47f81b5a87f25878d327d0c375c38d2940aaa543f46b1198345fce7b7bdecad6ad22e12155bc470448f98bac8ebb96bb34b552ab3bfe5255c6783a76425b386613a112ec1dbadbf105ae0ec3cad61c7032bbe0bcca9d3eabf03ac6f0d4c5e500348f6581876e80c531197e62071a9454947b450614761ec95bb7072ab53e81d89e47eb875263ae74ca6a28b2a2a1fd44947756c1f3eb38519c9b2d6d63197e6459bd1427f992680b1a6f1480cdb998006a25cf434346d04942732c5617245033b430b4ca726b94faee24ca54919f0842233e1c6268b4bca31be4ca7be9b52851e2ac0dee573f7959eb896b0bb18064cbb9b71585a319c74b7716de398a8111214ae3130bac5b196e6734d3cca4116bbf67ca42492be22f56b538a8532c6acf4404069a329735246e5eccc2730c2f5690c53510bb2685909015874a8125178c7fc00709b2a6720391e38a0193aa96715f13ed628068ff4bba6e74c7be095a897ba3dc50f88b2b08a353cb4c4bf382a5cd72227cb671ed74227ce245268c38874f53299604c41f15978c522e865333dd0c49cea97289813a828ca76b93dfd3987da9726f0d3492cf13ea72ab8d4e82e73a3987b336f0cd2157de0b9b4209869412b9074736867b10fa82b34e5424c5998295b6a54793e9ab119e9c68049ea2dbef55e27327080c6ae71d69374b8314ce6110369b76fa363dfc201729a700528944f2bc23c464eacf51519f0aed8160d5ceb66d10c865604b3b4ab05f1c2990bf2b5ed84898b6a891ba360af171b051b907d1245770038e379cb727784b219a3c5ce49fe6273600219bcc609c8ffcdf4acbadcb9e5b333bc301e771315f8f9b17882a6ee955159ba457f9f019c41bdfd90776edd78981182b43d78c40b828554c36d70b960a02c66490c15a4caa6a7d5f1e9ce34"""), - xeh(""" -2c3f3d5b5ab52392b227104e8b9c85303e6d579df35c1e7849ebb92e80ecf200ca9d9b9c408d9f68b4f4e5b0875047edb2facbd6a100c1e5a1465df22a88dc1055a663cb2084409d33ffab500c4e20ba796115a2a3f23228542ae90ede48e05dde69197b9d8138b6359d1aaf85443cea446a4a6b0fe769d2ac9de4a6eb1a4f0d307c6277a3fb1e4022667233b90885ad45eea2f6dbaa54d737886bb504c61b53fb24772c6c7efa12a7b13ade4d6c29e410a604fc5ad87f378e703ce9f709f9a7485aa18bf7e0b4d7d1b88968e06f085ae69d49fdd22c40533b07dbd7642444dcaf8e31c5c7c15f6261799663c5b00099261b747635a091c6759e2c1562a10adfaf75d120c33ade725b7cd6fc0edb63862831dbe6e73e356b729cd001289028596900b714f72d47da69306e3e5e823198ca4b45f56e1f60aeefb0827c44e4c16acdc892319b6ff3dfe138305df6bf7c518aa48241a1927171fcd1576f3279cc727fd8c6296b919296dd165ccba9544a8aa01a54df914c7e910d2930e27f7af36ab21929799b4ed216b971a801c11bc1381c205c55a76b9efbca88ee3ed2eca5f3771cce86617b5fbc411afd6d5d2c6e2a73675dbfb26cc7dd2cdf8a1f50ff8644dd1b173e090c8a70184bd14836254b29a489375d1b1a896c3a991a0cbaf86c93c581d0bb922acdac1bda28d3520bda5e4ae8815a72f1afcfd1168c4a4f8c526b12f9cf201e3b146779b2a2ecd35c56bceff5c0986402ac5783e1bee5b044cf6fbd94cdd7dce828b2421addb9bc80cc4aa298b2a95498c165ce241dd64aac62b1f17798d439c46ba24ec1290434e45b2560e8ddb938244c6557b52ce5f2d73d2d6ba3ae46bbd4afdcdf948c27d05b4476cd4fdb879d495c8405abd5ad4691f3853fd95253a22c4e012fea078e3e967ce666a5ebd6492a9fa2019be09923437d59b4ec38dfa71664020ec591a53ab5a2d6d77b3d44da2ba20a098a445182f62171b482cd5583ee290226bb7aa3eba414fc14dd7f0bb56e7b647269d92258a4e272b68cd42eac155f000f936ee48cb625b122c7237bbadfa4359abd3e82ae9899c5""") - ), - new DecapsulateTestCase( - xeh(""" -96527bfd017c70facf0511955eb04e1c8b6ba35116b6c7242af57a8efb7045577eb101087062518f9421cf2b3f09b681ec2b8793b973c338ac4d39505e296d027cb413981ead738e27202782095589945028b5540dfb3cf120a22cf347c3e225391750c9f93b9799a0367418017164472a762c63a8c209b44260cf9997cd5b33be79fa2dddf177de723644f094f10a95920c2b27ec31e78b0521faad545c2964513fe8839014e9862dcc18c1cb088096b82980a1dc586c44b7610a6a90b10861a081acab7381955410f74970cac1afb52403a0ba7f81177ec65b3e045816361050b4226950a7b1bc474093d9c1df124773c82300778f52e8746a54808826399bb1cb7d7026340283f34baa768b785f62b449b9681193419af289c1eb845f16af7bf709ab3c7d00507f62457d74fa048942556d3877e54332be622274ca89c298b64a46c4594030a031c795523928f11f708ccfcc2b75db1814e087842596a575b35079184b8dd61543a94e93762b5116855a423201b66fedf028e25cc9a3d2733eda6b364c30d3c358fbfc4e563a52be95592c7a1169267fde07436c31250aa22285d229b04a1cef106c15b79681a955dda7028b3c205c188a32081b780500d1cb41df8601b7fc976dd67f9810c9d7b809ec3a725739609cd573c3038095235560e9989a06aa910486da5a24ff041071675f0ac327c6b4154f892f13230b05d37ff7f1867c7908f20a461839864a677d818a81d0b7c871b64de4082ab3d472503bb21535a34145bd2fc664208328745b9a06959340f939b39b2c02239db20204964b9329c3330104bf81aa127f75cbbd1822d96c99aa75a8562aab2a2ca9b5fac442988465232ce1cab05fb9c6abdb4337201a16374b75069bc893913ee28dab8b2e56d309ac2c0d244122ff755ed68474e3c254ffb03dac4c9e73392444daa7f8e7658780a49b44b134750eec8b4780c308587287c8c8c726041e2e70cf6488735a6ca6d300956fa1c027c3679e0ca96a457a1beb8e60f139eb0869f61872fa2c130117c321aa073935131a8c9be7c800e6270e71822492c992bcd26df43478861927e1d996dacb9c04c630b694150f23aa51f26bed8c744c36a7916864b5160e94cc515ae0a03ffb445245c56a434f9351ab64f6bcbb973718ebb612657d64f844df3b85bd484c473a685a0a4a94e9995d865aa5bcafb7dcbc7e9877d63890a86252c691044df94ef7a19c68056ed6315400f8bd38f48abcd09e82f0376816c0aae53a9cc61b466466b63938dbb0b1dd963adae40802216701d094c716211718943b543cbe0888b1dc463c20804c4c402105130dd7a87a48c3c3328f76a8aef2b0c7d22688e7636b88d62897809eadf1ccf2dcb5a0011998099506925dd3b74869f931394bcae43466a49a40b31075f074bda69c0ee2f7bafbf81712969b43f0beacc246b3e71c9df2c47db405e235ae97e1a99c0365076b29e593b39c485521716967751025bba279f3aab85c6bae3800f255396d136459545f192b650d3b142c383669d2547cc2732015bc4645554638284642b918b5bd65a06fb49c5fd267a90b77ac35d12da3512f44d2556e027e6582529cea194df88584190480d9b0b5335fdfa8685894514cf95386cc1cb63131dcd1022f5b568cc621a729423c0567a51313f647918368012a83816a2caf88e062a9a6064fb52d8b31abc270a01d974459b4134be74c41b6a22e72ba1c993924bc43be6509235298431c72943bbceed41a84f9b84ce21abcea516f32280a0586069acee7627b54055515604a9ba112e620783aa76264ab8136759af9dcc75718a9bac22092a645b1b5cf32a92e377ba03a6117ee842172505793f973f84cbf0fa22d3ce116ef4c1012bc69db94c7b2b461d978c27c93044f22972588af42e28dc3748299e7a098b5566d67110a036ca9c6740dac84205109f05104f80585970a7906d7bf93067472a34442780f0fd25729745c7f85198a753836c3381f0592f818916b48278e14b61f1616c32ccb987940550316462257f1daba0574223ed6767b9c696b1c01ed75484c1738cf60afaaf9b3144899c4dc00fdab36fbd792dbd4885ab3af6ed63f8394b66d0a910041b1d606923858432f81c37f57c146db8dba6775ba1899d5904f3a69abee80050d6232d858d95a7bd86ee6af48bf9c372170c7468fc024cfdd552fb21ae23b08c1e38d8ce7232e254e153d4b2c4fa1fbf93c919bdfa47bface7a3a8708917b45917a2234587c5969cc1ed10d51b0dcf8b3017143ebf31687930f3e2c610a4850"""), - xeh(""" -ab66f3111bf51917775e0b0ddb50f0b1440256896320369968c564019c6f5236f4b951cd4370965a16f62bb2046f67584e4b3c2a6e048071d4c69835076b2bdb5f1c5323ddb937a371a418b0dd84c21ba037c2d94470a279b92e0ac53dac8de04f84ef1632fde456999bd2b596242dfca9484fde789794808c8cc5e6cb80ba87a850ecbee0262440402cd7f4ff1c6ba24879305b4f3542a7bb45c767c78af8d167a5233e42f0ac11d1c3a09aefca29eb25b3870fda30d97c53f988ed4820a7b979d3bb5aa4a3e09a962f98c58e3a2b231e6932fbf68398ee649642268950e7c3538268f02553caa443e6e3e29a32b2123603ea7e194122f0ecdf02f206c95a90c3605978b871ae70710887f46ecdcbe326368d909a062875f3beb750b366884802a0f6dae1ada16e55507ac15431c36ab1e01d54c453936d6857b78ce0384d970439aaa4e422441b1f8706eef30b6e8de22fbeaecd3204f8e9f40f1a6ea0825da1e0c967e3dcedb62ddd1befb3eb1c98d7decbafdf326268b79714b57dd7cd0f753c7619bc0f6ebbc8c4be474a6fbaf3d739c952b7f2ef8522583cea9f0a2690349422aa8b09f55cff3579546b2f3371c8592b459e3c0eabf4f871ada231c2933a6b19dd6c1267498d185f2d6971c1a73b4d61ba9eeb4797fbdaa11b87798e3caa78ad03e5edec0ce389c551855ae967849ada410e996b8cbdfba75cf9eb311220ee294585700d1cd15305a5c9a5925fcc6e46d8b94225fa01b69d70f0666466f69d58b0d3f1466d0972ef697ca0b8a40e19bb14aa83a7348338962882e05a79ae341b622ade01b19239e85ad3ea04d6d5d7d9e0d2db8ddd892b7ee6cb832b8b0911d85ea297e169f8d9623e12b9ec50d6e20a5f5f2a5607159f0ee44563851bd229d05276d87ec69aae43b8246e26d1c634fa5595e68a2c0d8c6f480f8642bb62ff80cdb0337f8f4aed0d12f773dfda04871ca37988b86f2b35c0babf83e45797e5b9edd97112bf079c470dfcd10ad989fb871cc66c696bbab7cd1c76dedb2c136192b6730d07a036fd1e3d176d69313bd3ae595f8b1ad63fb9439f0a53ab41""") - ), - new DecapsulateTestCase( - xeh(""" -1ba960ba9a80a502090c1ab5d4f72369bb48ede1259a76c54cbb87579b0b623075ae8a1860bab4e39c460927af3e44007671c017778d160aa5f88cc292141eac1c6d417ba6defc66fe160fd64b5734c86fb5e54ae04363bd34982450279e24b4dcb2b6fd8260d385b810493f2506312c52c9486648079609ff972725392c7a0205a850a201e220f40219b3557993c2acc969708960a45e8c7f915562e6c7a42a2495dc499f1acc3c46d20b0b152de840b523c42b1251770956349fe35c8b78768798929df771469a476e997eb44380f19413d3a0a5d0c8c25ca540d6e092ff575e26543863728179b95533b36145a5324313433f7c66f78c66e664176b564babc846f454be93d9341a004bc05c2d067463a529a486fb447309298e26ca2c9105eb306c001cc3a28074af47675c40aa4cc371ba330fdc97bb03c95aab5247eee30cc8cb634d1274a4a2b4ebd6065ad3047701c930f3145b65a392d0956010c23d0c19c4968e22125b71d06087dac0af92af7fec35d008a073e99ffc9cbfcfaa7e25ebbaf0335072c083ebd81664085038121d7fb022aa1c9478254af14170b0d2009aeaa7f081b01e610d970b70e40851ce8743d020c731717bb8984884db8cfd52a79f0bbcc336bb43f27f8e5108d1f4887453126c628300f4ba10fb45b7d511909a035d65a2f6961e065a8492895699c539d7a78d4ba1912fa9c30bc43534b3c7be252f4aa27e78021e97a423e9ac6d9b57ae5262af73022eeddc4918b18a25c77032762c184c861d924c519a01bfa3618ea01d9b370c13934f2f6199487c58b5459cfe80c60daac2a364cd51d766cc90afb5796524a8320205b83bc9a6695b51e5f1ce8089beb6c403dbe50ffc557e49020d5e6586524976638b8d4ec1816e34bc373515a1bc98a21a51dab17df2971d64e63aff742a243c890ea06363bbc4994ba1b45c233e187ae78b0d44677254740e221998c6e3370446bcc21684593026b8bb2d32556137323e9ce258668c7d18c44330c59d567265ad60c317bc2d083a3a599cac8cbc87d0192907209b851638a50a32e7d76d29da291f861cc7b979ae13099bb82ebe29ad44859860634d62f78fd6b26295d040f8a5c7ff7aa393d127e214aac9107ccc06d029da6a6b998736710c5fc3a6c9ecbdf00069a9eb2942b45b1626b7953886248caa59789f9e988fa26073bff9b703232859463a9335374506ac57a8c2936701fcfc0235d071bf9807e907734e6267d130c9d4b2406e999b6cd15adf7783db2309598c058a93ac043319194ba89857a59eb35fe4a3cd6fa1c9d7d46ba2f6c62ba85ca46cc8d450bfb0170f5ad6a2a0388ebe73a8b58627f6cc5e7477635ce32472a87b4b881ca9fc749ecba012187a5bdc6e9e12b668f32786cbb5fa4055f86590e00bc4340c04b8b0053b189a74d6bb22db2f75f6b32918c0c3ac7da62044db4a9c1c2b0b1ee81b5317b1fd734c33fa3733d7b37bfa36c16578cdb63cc6f73d661a35e6460b74396ec6a07111091071a757d962384940a1a2338a42fa68e81587fca304d8a86282230470c8988cd707437163cd46cb489b010d235fcb976e50b51e0a22c5662800e74903b403c025bc6df9d821752107b2e51874147645687fedb108c1894e0ac3801bc1398c4a187bea7d9949bc5cfb8368b296b2fbcf2b59c71321b5aa2055e5823f86113a1519c956d9c1793a5d52a906a5031e905a862fec5abfa0965fc49a2db189eb6bc69cb8882b703e0ab35e088340fc35812bc0a184956fdb448170a6b32b49ac0e2a65a1041d38d4512dea3fa111c7e428cdf52144ae0708c5c44382a0733de356ab556e0aa141d58cb1321058be25a543d7060252c9e87997c35295596c02bc7b926f5ba05675a5dfea5a3eb62b2521854f21498c428a23048fa38484935399bf07c64fb63f7ee793a63aceb6842bf05077d2b3647714332d259576182f0d9c508cf2321f0090a6c1cb0a5c106647101277a7b1248e74189df6b90c26a612b26555d433bac49a3ebd702e6d9649038233d6da01f77534a8d2038f615a502cca8526c314c5856a033ec97155ad79a2e2a32cc1e734cedbc6c0b94219d13bf985588400cc682294bf21183830b2bb51b87fd9073b9cb6237884df0cbb12b929f81448e5578928b07193ea4141d19b4eed07a956c34b6de59127c5e823bb8f6719ddeaf282650cfda0e26e57a7165b1afbf3fa9fdcfd677e3b27a966fc034fb10c5f08a5c2cfe2fd02d9289fdf022c3c86b725c5f2b54196b7d68684b9fde93be78e38beaeef18195321f4e2"""), - xeh(""" -697f53fe475ffe22de8a70436eb11099547e47df00dbb25b9ccf2c3ba3a48f8876694671779a72d10510bd703ab015a425ae50d413e9dc5e87548d70b84cb124e4950c1d546249c8c8d60fd06513bbbf6648230538bc5e88269ca0a961b9c8186abc70286289d58b96df28c39f158c1a707f75dd20371c63ff038d0ad388a22449ec4fd8f73fc82c75f1e3e6e1c9f510f3ad8ca3124aa47edf0cf150f7a664a4bd38bc73dc94a722b878b1ea51db19260f17120fbb99916e596ced350107d43bb26beca35978db929df046400f8094391830c99cf2d5cd0e1527f97419550ad1d1c31f94cbb95d3cc5ba06bdeeb973ee20b7961feee5b4c05e08b0320ea8b3be528b52bce8750fabccd59fa7f8bc9bb8f475e25f1884ce4255d4191863e20156318276d5fa1e7d2385c2744ef31c9950ab071f031d78cf28ac07c54f997ae8f07915b16b8490f1cc028ae6b4ebbe42e5d7b5d988abecd8ac22bae7887658f7af5c488d91993c72df113a6b7f435bdc3d90cb32af64d6dd617e5d0b0f611ec2a0575b347c1cd89f92c72bfa3e7ef1e3e3be4bf68ae05fef6da532ff76c9e9d7f7d354b2e638803509ec7757c78c35dee3c1149d2b25f8d18a8b6ba7b03a519d0ec7f18f895d575fe3c557d8dba332e2454281b676a96b3eb0d38ae2de00893649e1764e2cfe0b1d08ab1d69cf65049d3a2b7ba894910c6fea7eb94e64ff8a71c64ed4c9b6b4ad71597adefcddf0904364c50084bc6687affe770ddbf0e8e9268a64e70a9481d6065d2a93072daaa9583d9b2a20db31cb7d5edd37c59e4fd607ba897dd5afbc2a6403af20deccb1d4b3abeb9502c40b5440e5e9a7f850a38633bd5fa75bacadbaa330e7a401978a7d10c9332daf141580f8317fbe7c06da656e7942ea7d5d49a5bc28ffd15d17cd0dc337f7fe2f20d37ee71b51bb536f4692588acca8a3fc498de1d23c9a1b95c7efbdbca3874e91658cdb7755f5bd51553e1747737b1ce2c44604987e3c04d819d7449b6a40fbeef7b3cf7bef8df39926830c558591de535b8c5d482101a5c6a0715ec13910a243ed0d64efc997d2d2342032b8""") - ), - new DecapsulateTestCase( - xeh(""" -6a7863ee2a8102b695afb7842cfc7ba822bbd8526522e76f3cb9884c2454da31b967f939a09c837bf2add1c9a5b5a4c13dc7742167c74678144d05b830b6756ac963d7567dc23860c8baacd3328bb209a4720c5294a665bd731213b5cee4a5c51e58b0d19891c8ba3ba2e4c1f43b9478100067681801a386474b834a2ac3ea03961f7b34263c1ed08bb9623203e920b56054a2dd7cb9caa59ec2e25d21f1442d24847080ac45b80ad2caa4025aadf282cb23853da2221d3a5782c3e34bdc3478f0e77dd77696b97c4a0273bd9ee375085c50140ca1bcda9b14117747163923b4612318c6e6417d51ba0b94202c98575699a337ef379f2e46aa32d60c1af81edfc31c35cbaacc0726179b8be68ab1cec3457cccb0ac2888fca66b94d83216b00457a28b9dc064e59157761b4c91070a7d52a9b4337d661674c497b5dc2b5bfeaa71e362882830458f215c4e75157877aab7030a2b47c36c4176df159f8c5c9f8b726335548697d004ea03893b2ba0b54317ed45863f17b5be19b5cd712b8f833755b06e33da356d1ccef0379cf7838dddb9306bd482ecf16b52a8530ff6bce2a1ca269c318f707ee0ebc4145811ad92a21b3b009606191da83dd5857d6a4849b21713e5868da4aa78702a28b33b3dfa4c34ce4a642767517bf90550c687039787d54079f6054e5e2cae5eea711a2736d8c32d3f46b84b33c41761314e91aeff51cf10191310e1c3829c8560e0c5dcf0724dd00ee2364fc82001e1e4b4d577c9768a6ab516a643d45c4f731cb9503be1a71f6bd78987427cf253a4d54a202e3c389a0c48c386793ca79af99a1f1c70130e583fa36b2e0f1ba809bcbcb9da0c19042c3d9061873b104fa7070677159edc93e00b414906c774c6c221e187b8e7b4d5636667aa10e8e89425da282399504b48ae6c690ba216bd27aaa4eb39ab09d99b85f396e21a6afa874b8fb642bca82ddac76539f236ef349534769487d99741b1c43abb21911b27eb0abe41a453dc4876a2a26dd3b93fdfa7a1817c747a2acb62e96f013675b988547f3b8a24a008b726c971b797edf0850073a94b397804aba8d0f903b9113e3b18442e9b125dd762cc4bc2fde8007fca65b4817ef985667bd62bd8806563846ddf61b68a837d35859344e96ac450cc24303d9f116d502135369305a8cc8549641487f88e0f24a31c87cea974547abb569f9c312dac3fab517c85a5521d41b7eac40c62b7cb8a0776d89828e937177785a23ba0599381004c253fc90aa8332172f7366e6c756e6f266f2c5c9bc70a5cf18416c00c83dbe76a8a9c52ec5929217c0d2be88c8e3374c2111c2ac46a2a454ceab38f8d368f2281749d4109e90702bf368d6ba6ce212146d7a21a9ce6767fdba3bf1708fc359fe4e974b676bb9ee04db18b93f60759a071484c134e0ae29b135c5f2546562f6a471a826aaa3568bcfc721d707ccaf9351462098fcb21b441c81f876a7782363ef84eb9c59b2eac7f637ac205f0c1ddab4bc0868f42c4c2ffd0912a0578e9b81dfdb400a6a747c9bc8c97ba3ff8074f454367a5768d48653cad01c30212997553941780b44f3b26b9b79e6bc43cd56683dc9770a1d81ec0601e66326148f8645f820737c2479533a7cc3142341a2fba851cd304423d835bba5c73c3fc617f393e673591040876e670b94585902818883608a773e736f52c496691481b908106609366513ae14b618b8611539b56b3f466f13a5f59e5179fd29ac4ec7a92b5beb004b628e7701b11681cc61fd088a031d80d8e43b36042857155b0c5f207260bbbd30146d83a9c3c17a1bd804b56c96b01e71de75152f4b4990a001a1d8c736e39097771b819e58a2bf4498f1ca346cc851efb29c1551060998a7242c7fb5b04b6c8cf2f703056f18a9df28504752be88860507b1aa517914b278b61704f2e33cb02307a7a898e58a3a87221898cb57243000249709f5e53037728bacc7027dda1b7fbeb7739375811427b3f8c3dbcc0775442323289bd89ea0b668cb458da346dd25a45d4c9d6eb6ad98645a65794a795277480382ad7a99e85ae9e279ff5d38ac9a461d4a8aa2170136e69bb70c2c7734060421388330606763158f0c04788d79ded7b52b79abdbf891c2290b561ab4a6aa02e591637cdac7353798d9e256fd0286389f7d3b079e3e9f89ec0a68010202ca26dd2ea953f551554098ebaea56f782c33b11b3def6e61889bc262dd4337801b55bcf0b5eb53996785555ccca66272809d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600"""), - xeh(""" -e31362859b08dfcc50ad8f9dba1bfab3249b8e0b15347ae776b41dcdfaaf8596cdd6ad0eef2098b4759f8b168178d75f5a3d13c2e9af1c94d3e8598b779f14a5951928874d86a95b757816a5d74e086f81bc3313e72a1ecb637cac0212e57b3eb756056663ba1a1b066557816a8bc3c73615193bfb16543901948f7e0932eff974bd678be5002cbf91320d055e6f6245a6e3f384d88a70f0916dad162cd4b959894366032e0cc949e1e2b32a660717ef5cccb890df1357698c5f19afbe9742b87b0a077a67d2fab90488813517a8c4e35e2c58384e66d8076594ae713fcebf4c590c209c2eb015c24ade0eb37c341c922eda2220cf09a278aa4c63f97d317cf86bdb6129af96432fd53fdbf305cbd2d7ed9439760cd297d54d10cf7cb22434d51ffc04babf2b04b5acdc1aff426e9eb91e604149c8311b42ffaf14136322d8678e3fb5542423716ff4750c37c2e64fd4b772723b8c67c5876e3d99f29c8aacc118dd9998d11a0a7a18a29d593cfb1ec9a4ffa16efae2ecb4f9fed432edad543cdeb00025a734cd7f7b4c7ac96901468050ae981ac5846a6b7840ae674f97ceb5fd22efbb1ce9a003693883b84034eaaf39e87aa2ab39e782f8984b32ff7ee9cc832181da7589ffcf52562519c63ad3aadcbc04f479924b4ffff5d04fd683bc7f0c0612ae7b1d711edd39dd543efe54d87e6232005b2d9bde0ecf7ec6c0139da18161fff97055fad31f9d8952d370e25990b7322c8ee1ff5d4766e5c3ffa8b036aa0233d031787c5a6d4e788e0793f5bca432934029921014209478c6cfa5b4aa77311edb604fb3e794b61bb1a1a8e58ae4a537404df32a7ef520a8cfaed3cf45a1ed7d08059425c9bee99120d9f528c603acfadab24170c8f6cba3fd01a223324a63b5345a6def27bd5f27686deb78d0bf673f434201b9b1c24658e3f6b7f6fe2110e3cf4d8ed16c02ac9005ce57652c3307fc86f533469bd972a6d90ce8b256a9fdc42da4dee12be96954e71fc3f2a5f8192a97a7a22067bc2503cb51c5ab63e7b6f909166615b407a29b8cc8a2e9792f77836899b8f120852a53df8d4b3df6""") - ), - new DecapsulateTestCase( - xeh(""" -6a7863ee2a8102b695afb7842cfc7ba822bbd8526522e76f3cb9884c2454da31b967f939a09c837bf2add1c9a5b5a4c13dc7742167c74678144d05b830b6756ac963d7567dc23860c8baacd3328bb209a4720c5294a665bd731213b5cee4a5c51e58b0d19891c8ba3ba2e4c1f43b9478100067681801a386474b834a2ac3ea03961f7b34263c1ed08bb9623203e920b56054a2dd7cb9caa59ec2e25d21f1442d24847080ac45b80ad2caa4025aadf282cb23853da2221d3a5782c3e34bdc3478f0e77dd77696b97c4a0273bd9ee375085c50140ca1bcda9b14117747163923b4612318c6e6417d51ba0b94202c98575699a337ef379f2e46aa32d60c1af81edfc31c35cbaacc0726179b8be68ab1cec3457cccb0ac2888fca66b94d83216b00457a28b9dc064e59157761b4c91070a7d52a9b4337d661674c497b5dc2b5bfeaa71e362882830458f215c4e75157877aab7030a2b47c36c4176df159f8c5c9f8b726335548697d004ea03893b2ba0b54317ed45863f17b5be19b5cd712b8f833755b06e33da356d1ccef0379cf7838dddb9306bd482ecf16b52a8530ff6bce2a1ca269c318f707ee0ebc4145811ad92a21b3b009606191da83dd5857d6a4849b21713e5868da4aa78702a28b33b3dfa4c34ce4a642767517bf90550c687039787d54079f6054e5e2cae5eea711a2736d8c32d3f46b84b33c41761314e91aeff51cf10191310e1c3829c8560e0c5dcf0724dd00ee2364fc82001e1e4b4d577c9768a6ab516a643d45c4f731cb9503be1a71f6bd78987427cf253a4d54a202e3c389a0c48c386793ca79af99a1f1c70130e583fa36b2e0f1ba809bcbcb9da0c19042c3d9061873b104fa7070677159edc93e00b414906c774c6c221e187b8e7b4d5636667aa10e8e89425da282399504b48ae6c690ba216bd27aaa4eb39ab09d99b85f396e21a6afa874b8fb642bca82ddac76539f236ef349534769487d99741b1c43abb21911b27eb0abe41a453dc4876a2a26dd3b93fdfa7a1817c747a2acb62e96f013675b988547f3b8a24a008b726c971b797edf0850073a94b397804aba8d0f903b9113e3b18442e9b125dd762cc4bc2fde8007fca65b4817ef985667bd62bd8806563846ddf61b68a837d35859344e96ac450cc24303d9f116d502135369305a8cc8549641487f88e0f24a31c87cea974547abb569f9c312dac3fab517c85a5521d41b7eac40c62b7cb8a0776d89828e937177785a23ba0599381004c253fc90aa8332172f7366e6c756e6f266f2c5c9bc70a5cf18416c00c83dbe76a8a9c52ec5929217c0d2be88c8e3374c2111c2ac46a2a454ceab38f8d368f2281749d4109e90702bf368d6ba6ce212146d7a21a9ce6767fdba3bf1708fc359fe4e974b676bb9ee04db18b93f60759a071484c134e0ae29b135c5f2546562f6a471a826aaa3568bcfc721d707ccaf9351462098fcb21b441c81f876a7782363ef84eb9c59b2eac7f637ac205f0c1ddab4bc0868f42c4c2ffd0912a0578e9b81dfdb400a6a747c9bc8c97ba3ff8074f454367a5768d48653cad01c30212997553941780b44f3b26b9b79e6bc43cd56683dc9770a1d81ec0601e66326148f8645f820737c2479533a7cc3142341a2fba851cd304423d835bba5c73c3fc617f393e673591040876e670b94585902818883608a773e736f52c496691481b908106609366513ae14b618b8611539b56b3f466f13a5f59e5179fd29ac4ec7a92b5beb004b628e7701b11681cc61fd088a031d80d8e43b36042857155b0c5f207260bbbd30146d83a9c3c17a1bd804b56c96b01e71de75152f4b4990a001a1d8c736e39097771b819e58a2bf4498f1ca346cc851efb29c1551060998a7242c7fb5b04b6c8cf2f703056f18a9df28504752be88860507b1aa517914b278b61704f2e33cb02307a7a898e58a3a87221898cb57243000249709f5e53037728bacc7027dda1b7fbeb7739375811427b3f8c3dbcc0775442323289bd89ea0b668cb458da346dd25a45d4c9d6eb6ad98645a65794a795277480382ad7a99e85ae9e279ff5d38ac9a461d4a8aa2170136e69bb70c2c7734060421388330606763158f0c04788d79ded7b52b79abdbf891c2290b561ab4a6aa02e591637cdac7353798d9e256fd0286389f7d3b079e3e9f89ec0a68010202ca26dd2ea953f551554098ebaea56f782c33b11b3def6e61889bc262dd4337801b55bcf0b5eb53996785555ccca66272809d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600"""), - xeh(""" -e31362859b08dfcc50ad8f9dba1bfab3249b8e0b15347ae776b41dcdfaaf8596cdd6ad0eef2098b4759f8b168178d75f5a3d13c2e9af1c94d3e8598b779f14a5951928874d86a95b757816a5d74e086f81bc3313e72a1ecb637cac0212e57b3eb756056663ba1a1b066557816a8bc3c73615193bfb16543901948f7e0932eff974bd678be5002cbf91320d055e6f6245a6e3f384d88a70f0916dad162cd4b959894366032e0cc949e1e2b32a660717ef5cccb890df1357698c5f19afbe9742b87b0a077a67d2fab90488813517a8c4e35e2c58384e66d8076594ae713fcebf4c590c209c2eb015c24ade0eb37c341c922eda2220cf09a278aa4c63f97d317cf86bdb6129af96432fd53fdbf305cbd2d7ed9439760cd297d54d10cf7cb22434d51ffc04babf2b04b5acdc1aff426e9eb91e604149c8311b42ffaf14136322d8678e3fb5542423716ff4750c37c2e64fd4b772723b8c67c5876e3d99f29c8aacc118dd9998d11a0a7a18a29d593cfb1ec9a4ffa16efae2ecb4f9fed432edad543cdeb00025a734cd7f7b4c7ac96901468050ae981ac5846a6b7840ae674f97ceb5fd22efbb1ce9a003693883b84034eaaf39e87aa2ab39e782f8984b32ff7ee9cc832181da7589ffcf52562519c63ad3aadcbc04f479924b4ffff5d04fd683bc7f0c0612ae7b1d711edd39dd543efe54d87e6232005b2d9bde0ecf7ec6c0139da18161fff97055fad31f9d8952d370e25990b7322c8ee1ff5d4766e5c3ffa8b036aa0233d031787c5a6d4e788e0793f5bca432934029921014209478c6cfa5b4aa77311edb604fb3e794b61bb1a1a8e58ae4a537404df32a7ef520a8cfaed3cf45a1ed7d08059425c9bee99120d9f528c603acfadab24170c8f6cba3fd01a223324a63b5345a6def27bd5f27686deb78d0bf673f434201b9b1c24658e3f6b7f6fe2110e3cf4d8ed16c02ac9005ce57652c3307fc86f533469bd972a6d90ce8b256a9fdc42da4dee12be96954e71fc3f2a5f8192a97a7a22067bc2503cb51c5ab63e7b6f909166615b407a29b8cc8a2e9792f77836899b8f120852a53df8d4b3df6""") - ), - new DecapsulateTestCase( - xeh(""" -14b4a7b64bba73d61fe5d4cb3d890e4b67784e9a76c69c9a6cc53d16d2ca27c149e2fc0f6ad163d4b9ce51d96cc1cb2d48821fba89823a440e04d9415c675500091bfae270fa457a2432375e42c6b49879684c98cb37a82a794293a5c3b3abb1e6694a42a6924f372c79c370a60091840c752f287468fbaad7f907c444cd88f7cf4c8a56406ab7aefc4f7c90ad7eb669c36267f2c7a50a5441627990432b823d5a0a16f8a344b68cb54439dc3727b622179de14b7478ce14059966312b2d6719bc80008c689a7f4a590fe7726dcabb05e463c9d20e92c190bd1379db03acc0a90404e4c1b7dc07ce710b93f9161325815df392bb28562faa79670601b8cb2c33e8a8d384b2458cb45b8c09e7831cc2f6beae566357e0661f980ea2f32f13d23cc5ca75d461aa69b31e3e55cf6a9baf127022114a206e918675b522e11ac9a85092f381662596b56bf71f1c119a45f32f45239f82055889c3194a4555b6d68caa549487da6b2f61567a92ca9c938d25ea0b0316990274a348b75b70c100bec44c5612249c4697649635b641693a54741e471f45e579e6d343587a3cd1789dd984bab0d126f6e99a205a3077b1467e252cd4624dbc0b88c630a9604691a01c490157c928239ef1a140cc25507cb267ae897b1a030ce09b99749a3cc0119232678877951fbc33a6a0ab19730b6849447620497ce4a5605b11844d91b5c5c2490e99495b61baee6820c1eac72a544e72a168ec093e5cc44e9ac018d2b63d79d01b6f8a1b6f2273751767fa35120f43aab38876bebca28d7cba27e4590a8c05448a897cc0a963eb9eca5c31cb52815cd88be80a93356b4082c33c43db0ce94b0d1470ba2761ce6400616ae35bd992693522cf873956112449e5d4845a012422240887016d28bc73423237759384c280184775a481f6c97da1038e07b8afb0a4e5936093755aca20802438156258b5bc607d1d171246e2a1f4d7bb18e9c8095b69c36b06bea680b4e32b6fb8bfaa2269dbb9422ef686a1da9649414ae5215434c75d96f38b373ba2735a60a2505297493afc37228ad883749b558b990cb5d1911b5322ed8034619a429573756962129b459916f158f0ecb0cae396f60c4c84670ce3fbbe119055f1a4382cf2a619c31cee5842ee8c9c6979193ba82ce9f94337306186b20a276c6d06c04f41a414c3100b31e2a2a9984067fac4a7b3c70747c55b87b2512219d62c8b51a6b628766d63d1096f63bec8806311415919336bf9d1b038022d00d1bb84387888dc10f0290b752627c2d78ca5c8475150bd925240ed94af40b43762a99a3f5b0f41d702db7cb485405d5a247ff48635ba7719aeb8a876f0986f233212c40a3645c3e4ea3b5fd02bb520b9d8aa22c4595849b8a2769b92edabb4ba1528dd067aa86b3bdb6a39985983c89c9c916b41b34018bda438e7815bdd4316f6202c0e3c73d53124ee110ee596a9e3198f24b814dfd77f0a2a7aaab3a918b64c47fa44ff018332557cd13325a8081e0002096e68a293258928896532ac5b0ef4bc28bb43f68505f8a61cde0b5ec9ca8d62c261b5290e16b22a4a978d5b141240043c9b457a89a764d9565067cba987a23d5d6b3016291fddac50c9e5581d988088a368d1c9c633bc594d39c56fc5b4a996b7c110208de1394559915138b7cd8941daccc7382b60b47770272a56f846b15c71704b8b7e08595d51658a10b348617c8b552588a20a07c6e0670416636ba0982726671d796803320e0346bea80578f7808419f14b8be67f8bbb627fe4c5c28074e1458ba909581f317e70a66320ebc5ffdab20202143f374742b77d88c80fa8b9593d74a04e2c7113101400c4afb7893f634565aeac9eb8c144a3a172a1263fbee499d7895e298b195d4caf46514927d39f430aaf13c4bc43735670e5b0350a42506621dfd737177ba3736026d314675947a1b7315844da146af84c4cfa8227bc3211895773082fa22a8c9e7c20d1257ee9577c3f36a6d3097212dc1b149421b9bab30124cb3298a6b1505bf586070f52aab80a71e17c223184b32e9a6aa4627b3b99bf089973ab53be7c461ad57317edc3b79872bc50a391a43bb18ee9bf0ca100f16409caf4abbe0239b98b16a598ce86e7c07b27646de1671e915763ec8dc3c09a20181e0525c571a18d74c74c0e798d11d22db509a0f0519c7440e6787efacb39fb35c8cab4a38302c0a9e1969f65545a404ceb25db8ea6c1d0939019e0fb29d41885757f5ffc81000f865f638c38f0852d2d712a708ffbd7d96f0df21071d8bfec74c2302ea4c5adba"""), - xeh(""" -a93e00395f1aa0795a82b149b5c8ad8dd0d51c577b2b394adc282b8482a3cc3a8cb8aa2bba8a40bc799074e5b30d17b567895533cb28fbb11c05e07da2c8e080ecaaed70fd5ab2c15b33b32de50b2072a04c084b4740893c7caaf5b5fd037f91b75149cd8ce00512c4fc12f5a67eca00523e00dc7d4e60908189983848e2f529ef5688ee182ab82c44e4f5e57b3a37e6599d34fe299705de154ad6ed4e5d424ac6843925d4df9b5de48688397a39dd487ab020f38d7dbfb8a021e099d9e87aea4531c3bad076c0726667b3aae460a8bad9c5597dc49105abf2d82992bc73638322f3399d86cc6dcf5a5a8646e7100426d6f587b688d8196c8df3ac141878561d144ce12a49ac8292fa309a9b0910a23781f686e8b4915b96ec71372a9f0645caa8e0fb5e4a3a67f465f000aedbf2923bc9af8cb5682fa2fbce090600f4534bd3e384829f9caa5b9ad9c100078071256bb1bc0c93267b4a1885283a4e3d9157d48d19dc97203f19a28a9454ef99536f8a669dfe4432051950fd911939ed2e4e28d46a78d1395dd2acddc031f3218ddd4441bd5be01830277d11927e5d32d7f45494e3c3319b2516b2fb1dd7945ab16cc8227b43d356a12fe6f8c5e4e36752aeb900a02109427cd384ae6aca3869b3be2a90021137deb1f1b9abbfa0ee4fb9b4da554d83b37e0d9ad6cc28d2190d2e8f24e0c26e716270b1ba0312ace2632922a2d5d5343efbd2c37b5b4e8d1463cb8c925bcf9cc90b65625eb91e723e8a9284d165392db21b1b1d2430f06632dc0a3b87182997613b94508954cc95863a1b93808ec0c384abbb3bbb829ea6ac74864b2b5e75907d3ccfe077e461981ea59b78d7d4d521ea2bc68f47bbe403d7419876486d56a28ec5f84526e45745a6fb23cd61b3558f0fcfb408ea6963b8eeeb4ba095d30fcb9fbb81235fee1b0bafafd718e602b5a2343fd6c884b3c084ce9f1cb310f8b9811dbd94778ecba5db61e3ebdae372763e64a0e5543e949d0fd6d4b5e4a165a2ce597c704bbe6c632fb312361a211242271d8a5fc2eb638ddcaaa43586388b98087221ad59a924c5fcacbfcf9176""") - ) - }; - - static DecapsulateTestCase[] decap768TestCases = new DecapsulateTestCase[] { - new DecapsulateTestCase( - xeh(""" -2b3a0ad58903e3700b00ba4a6658209391cb5f7685e7f780d7bb8233e4989c0b2d2f8c9d59db9bc13ab81a87acc6981e4400033129a79552132e592834ac6933228bff548938c59869faa14467068bf8c4cf0a5dbb0a8fae2866067c2e406c3b353a4c34058c0a21792ee65c8d289df275b9fb231a5aca54469455efcb6e7ca619a1664bfdc31591e3318bba2bbb61670337a63bcc477dc20abefc5d04e816802084e185886fe08bcb620cf44c810cf786d20020c5f8458e191dc5ab42ab11b930d3658907bacfd28c0dc292e9e327d7c019fb770719f28961f019ed3cb4b78abef0a05c3e548586529f0e182cfa3ba0bcd6604dfbccf26182a1c3334c56b6fe571227b106acb7358156bdb6d1604f000f5da2928d099fba809b07912e80672c0cd07919dc41ef902d01779e9fe9a9dcd64648f02b5fb16db639422f168f96ea0b2887b2ba5a9437608b3279463ec17efe729f7421b161e98ae57764b75875727a1bd0024bc44a9b56bbc159f088d78080afa62fcb6095d2da8055645a8ffcce56fa8c04203024e406c5ea21cc4045e8e1550d016514924d7fea345d7c45c25410cff51450739155231f4ba73908c62f7c0343ab4800b3bb2269840cb3e05ab759ce5c8a9d62ac7200f8bb19b63b27707454f37dcd7c7e1f685aee256bba2c00ee076dc0d26399592f5a3591a128cb01e68830e66896e13be87205b33078efc44cfa1374a43896a3397219122a0ab030d1b2126f31112ac6690e996286568082c88b35259d23419d632b3aac7120dffb24ccec217e9883de4769a8086a8152363f42cbfecc2a13ac6ad9b6a4a8aa3287f322042c8671d6624c0490b1e2a27b81342672ac651236537b63cdda77166c585cc340a3090012f647affb818ac43d4e3bc559f0acd6157d12a86ba0640b4fd2b28694b7296738dd25089d33208002177819b46132217e6194c92085940435aebc77644aab97a432b184b172ca5370144ca9d501fd7b22b9c65b4b56796d854941a478e6d23ce561894b536b86013f1328059e7804f75bb2726302daf2b278e55dccf7a28e8192f2222f1cf335efec810e8b6521764e1e6174372a61c2d3314c53afb0755bd03bb48a280f0b3142efc08ddd6a0b6e3044ee4724831b43b0c965862b9dd9d88a4944c8d649c560d796a2372b3a065fd3c2480e1c0b32bb9625b47c5fb4c0adb0557427bc523bc97ac77edb00c3f5d6ca4a492009e182a1e6349f0090bbab3bdb0054b376712f1277c93397ca737ef1d612c7443be82996d2f95e1b26af9934c67a78a84b2559afaa1b73074040b052fbf0ab6dc546f042b1ef474769b235642480ea94ad7ddb0607f39258f73363b52e21b1577c2b5f1aa1829603647b9ba1eb17a6863350ac98c5c695cd86b090d3972c32d39b0370619998a030b2cba8998fd16c58c943af8a63c0b44acf7ad02c5bb5205795668ef97cd16aa67a47cb1b36977eeb905378a88b37af1a1a8281ebb28e5a05b248c9dd57b8836041082195922aaf073a04d8b2b5bb2c5be7cba621f08078651f9ab3a385cc0ac9ca33a0024f72c1895a698109478a9e4b7d3066466d28313bbc67e9319369f355eaf268e6d785ccc576a1344e38271a3189cdb94a4e3048a4e18621c07578243bc5c017af25da2ffce6abc3194c510076b1d0c5b5529a80b3abaa9658de03ad1e151751f54998fb77ac52a2739b09c4f0ca0b8827c04bc280ca4e7d214231547370e98b92006270194ec3c79e96bb16550692f988627b496ea4f4cf7e9511c014c2ef89ba9620896785784fec1da3458a6f5a11d3840ba4f8714610200d3a276679a7e395488d770cd5122d17b37652a9871357594a87662aeb3befecb0e82513ab90b414d60c66fc61e4db22a2a3668c05338ec86018f154c929af387183079a59e201cb512536ea4908dbd559dbc63aae57cbc40437b0d5b54e784cf7488dffd5ae861b86e7b8a57563abf5f76c81b595a144a11c464d17e6b871011f8f82a8851321f2455644d0156ac96fcc944a0ad89d52f896a2e84f5d4a146e61bd132248572c27d823142629337e116f9635a32f4647bbf2b281d6c1058695b49b51e7f602466a107fab60edecb8cafc47bfa6c65643c662026f702ac7b7118bdc6448eb65bfdf8b9eff908f354410c77bb689d9b557439e9704c4d4107cd6559d1cb5a9a10b83f9f24d3e7418d3781eeb8b07cc8c5e38189afaf64db11b20ea072674fb42c3487d74c392f278c274da80f7518f983152101b1ec941baea92c132181a9442106be237198401ce1b652ed41e8f033c3a364519b2a1edc41ebbb36529440ed398207e600e3bd2622d4534d7f06013047b41a895444947ea252f13d40d0b82b82c0405bca2454a8823a0789468f845441089e18cb89f940519756628a8c61db794c9e86c3c4820b61413b1b88af8b20a687524ccd51fb9eb76eac8b958501342c19eb3b6210133c3848a4cc1b2cfa730cd99dc9e5635b3560b0731e202453b31474bcbabb626204ba05b251bb5c63f85a850efac7d3ffc0c8e161d014a441618be32c94d7ed2818e41acbd060cb9c5b43226c05553b5bd31b310fca52389361b8b2389c952e6a275d17408bedc24a01897ff484012e74545eb099fb0620fe7523d7b49288773224a72a01b198a299036889a5d690b994abda1066072f3566a33c944550880681f716c87a9ac546ff218ffbc8ac48a8efe2b11c8c2ae3bc0a76de2173cfc5af328929d540561a588d4337d1bf8748f71140224c2e4aa458aa2958b236a6c0c77492a307f754869d9c8385213240b7a1cf70b3f7aceccbaa50a134064d64750ab5ab35982ed596913d84c74a8c63647a2f5531247373ebe23695ba767d0eca290b94647a4c94e3949b7337fb7e77ff7668f695b9beb8ab87723a58ca62efa3b75a6584768c229f18a3c26ca1a4da72972c02a9205aa08991873b94fa1f995ea6c67b8a015bc3b7a77943435cbada7323309dc74b7a92c92127b35c32879567d4e389fd5b5a6c23b932108ce22505d815c50e8e80d9dfc6c3640b111cb9c5fdaa28d199a00e405f061b6cd601bc602a6a491cf900937fe566fe3bab921c09091152592f6bb7bd951eb960708167d08fc60c40563173c45a76188871c696ce5585dbc66c65906d1c30f1be660ee2560dd6730fa4ac1b0cacb9fc05a17fbbea5d47e1eba4999f964ad5b88f874655b59cfacd4c36b818d96822f56058abd8ca410456c7af21d99462df2a596e235708b49c595eb94eac7573ff3a49697ce2a18d1c318e2340daaeb3475826b896ccff7a233709656603e1fb143844f26fb42a8b3803fc87b0e870632796732acba3efdf731bf7c242aeeddf5eba5b131da90e36af23a3bce9c7aa93a"""), - xeh(""" -d746c132b3940573e9dd81e355b4154e076d40bc7f84637981d39a1375b4b51f73aaa3e69bffbfe7dc06eacc4d80f96a5a89d8d682635b0ec84b2ef60f08cb6e29ec7b8c4aadd9e3f22851fafebfb22f7d6a78a85245337a9c8f64e94d73d2a20c39efe83532b96210b7439c39cfe6c5c7ea5badc2838fbaf8c31ea91484ecf476a2c46d52678e0752f9d011c38e702ec0f866e6da2acc91b4f2ad8b09a9f2cbdb7668ec16c62d584e6a5e8a6c7ab3b6e387e67649f402e706ef89f07e231eb0614339cfd389be92e2da2021613a38b6dafe4cb35c8af8462cf1b620f120ae07e7e97ccceea635f685ed28082a63591272426006107beb094ea22142e12d22f5f34ccbc72d444ccc26a3f1aa828f1de50a47f97fae14b6c77435b3127d248574a9a991b0d2311e334477a8e63d3524fa1d832b3308902cf0ec8826df24cfeed36b4dcc7c28ddfe4a1c85c13c87dbbfabbc16a36364d365c7a549ec92743f1eda2aeeb933be4179975a97ab436808d63b1f82e9cca1f7586369c23027ff45b66932798b31c1f06f0e001b47f59f6d66e182038620bbbf647b1003b3f57900dbff42fd0c9b73346a2f8d1168ff709e12c9e297315b084a60691d7846d3c881be21e9a38cd1a84454b848d4147242b0cc38562990ad4a52ba51d461090628af98fc5d3c66ed3144b420f639598261e947aced555e33dbd61433e1314145f9147b397e46dda0465a75782c40ebea2cf20afa74678cd9682568787a0dcd79318aa37da264d09af928d6c27127638c8e6b1d202cfe6f96a8f37367d5c275d6a5860ea2c2cf600d9f75c42756e36c4a32cac23c78ace15688f5f4d3fe9553b264bf29f09f2d8e5cecb1a7b775b69c10c66169435d238beff7b5efdd079a04202fe6c2ad0cf59309ee28d67591b62e763e634775f88171abeb7e607b6bf87adecb75c1306efd0c0f02307663a76b2e56b7c14ac40e6dcd180d778a0244fadd14ee68b23f13eeb6b7495edfb42529e61567b76c7fcc9fc2f8ca0b85e647481456edbef8305b6032f2afaf2863b4de0bf9f3e7279e6e4dc468291ba2ebd4be7dd0e1ede6918d9fa7e60017e88d2a982073c131da47a76b59604989854dc4663bb70bb42da22a1c15bc9dd7d0e856261195c2e726c72ae055fb4245a2702c2b63cdd3238ca040800631ff7f48ad62ef611042842d1ac379f51f6811f8d95b6f1f618962f2421d4eed7b8d42e6d942c62492adf6bc9a586ac4a3a4336490aafb115df5646bb3c69097e33a5771207eaefb5588741cc3e7bd92e123cf9e8ccc0f9db5ea2d4580a82baa36930a86865cda996dbddcb626edd51a698c352b834f0a198e0d8abec074287b0ff5516e1416590d889b61a4e1668d00ab94d5df6b57c834488a4f13b802abfe3eb507214081452ab04e528c9305752a72090673b1168ea70329749c07fc83ff1d1bd7b92ecc65212fd8c6bd972f3159c04e78e1f94ea0b70806e499dbad1915bf85311ded1df041fc0924d461d30c358d7f4819d1425afc0739f76566""") - ), - new DecapsulateTestCase( - xeh(""" -d44c7828421af9298976b2c4cf623bb149a5bc26a2c9c451b270294ae97422277547c09eaca491ac6ab4d793747d1106b0b9a6e5e2cbac9a69e1aa6f2c2691b6db3448fb8ca79226f3c477318504302a34975c8bc8407ac9fb4bf1ab0c99370c319801b20177ca5561c2ab0000133792abb7ee81a76c0b9d870c6e96c40963ac9b2ce230f8b3b365765ea07b45b80b8b2d70624c3acd6491170e94bfaabac2f9274d4df0b1edec5bc213b3c9f3b507e14360804e51f28d2c9c6a46a6810f47ccf09956fa361fbcb5be19d3c921d707b5948a39682443401f4f13a259982f73887fce1a522d21670ba2a3e1987912319a6c32b0b2444009064c30f2bdcbb93563e135738865c30a749347c55d69357df88ccb22bdd2d004f6a730c7950aefd5039870a9dd203b1458aa39e0a4a5a4b460048861b6a189d89240c59da830a9881365fb2b800cdc01775b61d4e35dde4b0d0b4a49813796f773134004841540cd3aeb31c6f6ad0390cf57d5bde23a5117640300dc7077287c4257566ab29bc736c0201b63636568fb2cb642f64cb7eaa24ebbcbdd2a424ff2b595972af3f5cc6c6789a88154dce59787331e6fa98a1ba53c0927c9ef859ded2b6c9c5a316a7291865452735c18cb575d49b1cf0c2012f9f0ab8eb85e3428a1d59375bb740d4868c7cdd5843128815ae592cf2a329c51c819868745203547b012410a26e3d2b0ab4905317351cfb6233da8c05cb88cd353abd84820cbe25c56c504ab4ab78f9777e74051ae222dd6c56529b56515f77a48a9a069c65785339d05baa517d97c3d40737fe07d2229330d3719422a619cc189ab72b7ac496510432a6ce3ced0eb47d4b908d8fba18aa3b60de06fb23b9534ab4c07141f7cd1c440b0734de911bcb2b48d71afd9418f0a446361071eab130756f0cad5452690b5ad61b0988ce91d2c415a621061d9104cbf3a9c1ee684a2e2432fa8c49e59129be3b72d23934520ca59ea83dd11ab51c57b338408143962620c50e6499bede76d3307be180640f3648325dbba887539aaea5fc44a16073c1dc113c587e522be274ba69b80eaeaa61d69074a96ca9faa0299048add04b9bf9948b8a3be4860cc64b30b7346019fbb61f07850b5591ffad7c2b7118b0adb9ecaa00a1dea3f40bba75c5168aab405fd8b4911d11b01f3c1a997cc35f15dc0a4863e611239abc22b774a9ed81f695879519cb995e27daeb793efc5247e6b0956fc444ab8832c980857a951b139a11b444b338531cfe72b6c66ada8268680e7147a67a9293b8a91d6b1cfa0ad7b7788d17977420b09b5db6142f0997db61f33637a16394202056df3930072e30cda7a7ed60c7b362b113105be60b713c525484a482f6ea2897bb7552f473a0bba354bea3688450218f25163b32fbc7a17d8e348107305246337c6e344c131789829a110373ac83605e24666e308785fc64975b50910791b40563ed141ca2e8154dd879495a26b9de249c58100eba91398a67ed41475c43c7593a7402bb88893b919e6d147995897602c729da851ecacc6d7b67a0aa278b635453080371e302b9a131af18520b47c294a44180a0caf2db37638d4c7f8270b9940b7a452a01dc0bcb9fa4ae0c659600c29817b4e10241e9fe717ba2cbab8ec2b959a255bb414a2571cdaeaba0db244af9405aa870deef7491b1c5fead4652599c1dacaa309535a073144e5273e932a1877bc2bd3b9125ba658feacc6de45092229bc84a94ba3f5c8bdb37849b5372c205f7bd2588cbb47b87779b004309a0b713cf428bd3083b0d6622b1826446925922b293db9747027b587a7677079cc1871a8a5016c6c04bc5576ccab31a2a0b4a7b1b852319c41f4b7855c2451c27454038515b9876d6fa11820c2c024408735837264148ff7d6062570732d3a4da3a27752f60dc2c93ff7d91607c70a13442fe4929184fb9cc4e33c1684660e1a1f6b575ff35b449c14527352c134a11a155cafeb214d12854753f54bb1a342ebb918acaa17d882074467b475976ea080bd23b256c477a0acf56fc3d9ba9b34297e71cdc37733a3d66f11942017bb8c16229a23c196de8b8411336742328ad6dc5d4ba77108342d6847abde81a4e1a4b9cb8023a1d442e245186d155e9fa0653fc4a6668691e146a6c729507c2589ac12702b08142b9745b2774cc0c44fba928f42381ca7a82d98c3b445bca7e343b0b1334a03485494a3b6661613009201961551ef9c38a2f7cfd46ba9f906c19c59386af69ce0003fdf03c880d482ecd206a0e96f54c28160064d6caa31e2902c7eb03d5f0979262591cf498d51175212aa482045121fb30f18c2274525205d7c746225c920e62c88570a3fe23731c49cdee65afc965883fbcdaf2306344c32d46b403ce050582345e5c0cfb2d08d0018cc33d1acfea146de85c1e93a3a015a1cd9c7580bb1583afa73c175645581c59a801952643da86001f065bfe6bc1d94d510bf3a0a0268a77babb675f74ae426934be0c64b115e3dfbbd2e98632fdc840f3336f31698453641a18b667579ad112490b452c8b7b9bc7086bb19e483453c4007dcb556b013801729ae23924298bac6f8c59e3ca971bca2474323cf636aa02b008fa08d56a500af032801e3157f29505fd93cf3791a210498405813d612858f503857a0300d672414bcb7b98868d0d156935b1921620bbe262223f43f3d906e6bec23235441da41415f050523b3617bd57184719ec9c92ee2b6bb4bf6427d7045c01176723c1283dbcd82782476fb9237f96b7d13697ab710291683b2953dcb9b8ff0cc0cd99a33b5fc54f6d07edac2462beac952848aa6ecacf71a656ef9b2506585665a0fa4b8c74701868070beca33556f12c0be64caefe6a1e2e271e8470c5867852abab93ed925f3837e9dcc04440607a34c4299a44e2a537bea16b8da07187278ae672509d53aad998b0de88a7605c99c1fc36edbbba10884ada971813e64815adac6641630635a73336c44a3e673ac24ad41e85697859f257a2781b95ad9e27c5ce39470ba246bfc3e0dda46260939647355d0024aa21b2063b19967eb7d7a65118f6cada035053374812b995977eb6cf1238e5520b6ceb67f261293dc9ab205c5c548213730585ddcb3b6a0d0b164f9546d079d3ae00079f6abb170603528991d71389f9113c08434d481808a823feb372437975b5624590c183c131507b2894b6a15ba6ac18b7d1a5ff0d16ed0ec41e214c1d055226b4b0063059a7486088fcf467cb1580a201b23912e571b6523869522bfa4dff5fb95aeb9fff2ae41b26e9f4a0c89217af42c53174292774edf2b4d334aecad2ae1838f6b7927d8c92060d235ddc4f334bfd91d6b7df1a4fed84c88c2933806f13fe06ef15aed96c9e1"""), - xeh(""" -086f65f0cab0b99ae1bb3c2ce201813dadc0b42886de6f834962d0b0f556ddb4e83ae7c9e85d6b2eaa9f9c630a95ecf30fb88a00e0dd473053738838980d24e3c94e751df4cf8026b38e81a72ae86bcabce780273e00f3e5b821c1758f9eeb5ddf61e4cf878faabca05fca24b8735d3ac03c1206cf9155e7ac758069f48eee8b3767b48bf22721ef43394df758066e657d2baf6797e6f489469393754b22d702fd85e4cbf635500bf3cfc448a535eff7f6a2f5d9f0cbebc1e364a4a37a11f4f209a59fe109b3b07ea354c671f1f5a5cc4ac37d18184b4e487ae59ef8dae1efd296100d0c059cbce1b2342914863cd5a86b17442c616d8110f1f6c58788ca7c74970a9aa7acbb8826a1dabb80916d7f8d0c8f1dd07cdabb898cd79c64adf7dc6475e7a1d6994364ead883d520a6bc67fdd7fbdd0a2c151586c09084c6e7cf63af35bda610fe2b393d2df26b2234d7a8bda45732632d7d705ec7d76ae77e4f3536571e587cfa029a758911aeb657aa638ccbc9ffd1ad76a4af195d483cab979c3fde5180761989fa347ea8fb9fc7cec768e5e48e74604317504f7c402e44ba4281b09a0925e7a6389ff5cac489cf0beccbb8c5d6c2a45c671320b177b465148782edd926f1596d177e0710cac012d742d5d9de53ebd5aaab0a7c66499a27ce5a896ee605547296639a067762787cdca8d2147c47e53501ca453ddbe82be5691edc94df900bca5f3ff49d7a6186bf803f91cb3006ee8dc93afd3596d71beaa477afa91c6bcd43272598c887e8fa190dc898f85309720e5381ae27a15c8dad038e388e2b45c895cb64c2b6a0547867ac33d4338cf25ab834d17d4d657066408c75e146e442cd0d4305a31bf43cc20fce7b74d0edeb820cd83dc1895e12d1c254c1a9bb6f266d069ff867c4e86181622561649601635d260e868cbdbd5cef6334cea88b692f7616b0328633fb6e7e5cf94f130d090d31b61a1b31c7411c78001ed8aa6b569e42c465a60ffd94610f61ec8edbb8f86db60b99deb2cfa8660a3129eb654d775a4cd04287e4990e48f65db3c7821aed88021734ee3393582c425c2f0299907ffdd6891b7517d16203776c0c95a6a0c4100b7c358013598467af2320a8618e0f29744f519ee6d401f0eb742ccac23d23b0c985a5472cb9a4582a325abf00b6f0c1a88f3022617b75b8a20335cd2b38da0bc8c3d85340dfc85d15623c6a8ee3cb955ec6d1b4b01bea20e85353f8daacc821a40866d5590ef1ad289ed2c8c4f4e2213b395bf9758b6ad9fb44eec1515ef73a5316093f4893177761b4d0c5e43443c5a128dc2f79d6108e1540b20228c4058a4e2180fd02eae9127294567adfad6b7a393c915be347fa293d6eb68e18557bd89c19cf80f003eaa761a94783a731926fd69df099aa0a081747ea01e91a881e07df083c1781cc2607c2ebdd867d52d8ff276802c653dcc497535c96bcb6a16425adff31fe8611c55f598575e72ca06e0229f92f57b129fbd7f6a33c4716763bca05102b74afa9082eb03492f91c""") - ), - new DecapsulateTestCase( - xeh(""" -337a1214847b4e068928d41e57d48b75296989f7b093760518b160b21515dec6aab4ac6ead05bdb5252e84f6a1ac02528efc6b87491f881ba1233b6d4fccbdaf6691b8c1883fa7bd47b1b9f2440811cc08763345cd6433d8bac1e0975d854b9f0b219d44fa19636616788b3e104a4b7ed32b80161a57e9452f5c3257c1b31663c54df544dd47b8477374e6618670d37cad3c4820910f88e870971555ca664b63409c8da2aeb7f78e52fb5bdff17d0862bc042bc6ad2a54d6d2292b4ca0d5859510c74536c605d78755d383993981aadd947682d3c6e33c1415725dd2c3730edc040b676422a8a88e33be28323e39acb2678a561fba2594d2244e7c73ab5c181050264da26159f6ce627a9e04f53fbfa5b7e5e116189c0606b315c1293949824429f340b5826eb3674333d7c62d5a2e7a9a5d0fe7bcb7f48eb39712dd53b691f62d67179f84f2848e9b2fd140115bfb9f8df6cdf05cc2f808b50b5470e1089aca044b8074ccbde39708fb2188e8352611a298d59b44680417dc35ddc93dc5a709fdc553d3e95987c1b149251d56c11d59c845eec726da222e2966886d33969885209e8972e26113a9634ac367a3fccc74007d7061e34fc939cf7f354d3465083ee143356a664d58a4c2897c77909d0f23929a2247f36c2f0f792654167a97d75aa93b1b13543e3e8591cfd29deaf56a5974c93bf165c73873db956619d6a982285084bc7cf2c4b58681a6e6913333595a07315f15d79ba0b27d590a146dc3b55354443ed74e524c2b486984e2e06622b0a00bacb8f654a205faa67a77609d89a1c12538c2f6cf6e019d11b54db176b9cdd3382c999a61a81e16126eeaca5320c44f44e77ed20117556b0929d538759619a8b57688c685bfdb8f918b0064029047d2043f2398f9539610302463a7b7bf436f58a8112cf1bcaaebcc19e94d0c3a8a53651d08b0782eb138d9741f8891b069e0b38fb24336d8a6cd1439f53b7b259c2eef718857112d9290ae9e402e8b5150cefa7496f224dba899abea69826490bc024b0dc080e5dab3a1a767ae3a22e49961a91257b80a04fa6aa48f3428e6041d6d64507c322b866899cf26adf5c48735dbc74f667d1e836447751a0da66e29548cae37a6f7c5aab572abc4e67bd58cbb5c65c2e41acf01b82019fc6c75f2931161cbbac2916250bc5472ccf7655b45d78402973da4c01b66134687f3b51349869bccb8cf4021c560209b184da65cba0928b01c45293f0b5e937b8cb6ec4a7e7a9c54a3b26d81c0fed81f18b764e639b0cca22824d09b90089995aaa2c9584f34a76d44e1092ad6cc6e99b4a6b43d58dc28a6c276f2140bebb9065ac6ad296a47cbd20df07a3cfc58556228b2bea47b19fc4646363ce4cc6bd286b912a608603bc2ac5a43eac45ff272be155969dbc764e630c0ab83197060caad34bd22b24beb25b2e7ac688ea552e8513b6422b9825112f39779dec761b92b391782bb239c99957a127352b68d77c55c013eaedc39efea650a7a214f0a8e55dc2848f84e792310aac629f6b2473a9b42783c6f870a33a197397e95652df3b646c3a9a2569d4dd333b7c62b7c7ba9198c2ba4c1110ef182c9ac645262b23ae8760753c4b88b55425144a91075cd90b31f9696fa1c326a8886765ccd67e119ddfaa185e292131128dd466206d9b4fc62250c6892be09bd6d379e88a86204226aa9449cb1f39efe58021154130e630ef70735ec57cf4f2acb93ec4434c4cd31f1a4fe798aeb50708cf90e5257991a09bdd3963f2fca8292c17f870a4f5af4cf682583ec953f1321b68f90722387136ad46d81e6a44080784b19cb975630116817e81b48051518ede43acdd9b9eab02dd481b200e3093dbb46228cc30d222c81514d1bf319bb239aa8db631f0849654285fa513b81149c19473b43caafd2115939464207076a11b7c6445a9837fcb6fea0930a321a22320658334d958a98c8921e6bea31b53b3d0912cf737c7b08022b0413bf27504eaaec33c7b8bce11427be219b945668baacb1c6e238a0a57b59d48477218db93b28860132647bcd69e8c62712a4abea8316c42e121201fb4a37e0d942464ac4e0c79805d3c61054a7e897809f37295e04ce42464d3096a388ea0b6ff5c04f3c665291012a5c4dd2cbc08d0996054a52d0a26d153aa54eb5a8ce66675bfcb657f0c952f273c5899fba9a01aef2b8934386d6695471dbac20a2b5936847da5b419ee5c34c4b100c36135ee1ca83b0990b7c405570321209a288d284e4bc7e56809591209d07050a39e629b3280574065d0f102788325b0b5b14d1fbcf2ddc0dcb6c9aa959ae2d2b7c011013814a3971d16b4d2c3480aa4c1eb135736c0d70829dea14ac862b46e9267f392ac8f1a2304b7125d7b08ed0839c61b4c02253045c2435990bc1b6d4c27244035a763d63e8ca6291390c417ee0e9beb805915dd737d68530ff27c943a39da835c49d99c0b6c50a770906aac0a5ba988e650caed744066c7a131eb050678837a3fa9b39379ef9e9283e2b0deacabf1b833b358a1a9f1c78bbf20498b9702b259ea5bb1d58844df66519c1bb0323a4b3f4866ae5ca703e6680de0253fc659b9491ae70d307f5aa4c2c888295b9122be209fda3a5a911959f6a9f0c550a3978991737a76ef408c27ccaac7443da67bfa76a79fbbc65ea72b3abb96b2b048ecd4116291852c568b59bfaaa9531524e36644112a76a809f9d0683a7d04a35cc4729017d70f5b1bb76b74b618cc9e181aadc8eb4ba5973a560c0f55dd1681ce91ca3e8e2275c8c71e5a536c7988200b5646afba80fe0c902e86d990a2ae91750409a5ea09645fa5521360051271ac6bc569b6d155fe8a379a418cfd000431cdba989872f73e2771e0b498e9698f0006050b5a06501a4b705434046aff69cc961077454795a6b3184f3ab402a22a819a24ca856c6a9e01d475c76aa7c71bfb692b182bb184b95b0fa363b76a93c7238a41661226c408218576b175e4084ca1d68b3edf79db991107bc106d103b7fa682189ba9f67c21865f2b88de32c6c757bf343b9b15b10e0a792dd3657e3d85be3dc5c3c52650425c8c62a735da286ecaa9aa15054f5245b3b514ef2c309dac712403a9d2999add6e351caacbd80a68995d67fe094a5c542994a88376397a7a15ccf1a9575e20b6a7b5c40c3c9739b02a53ed5abbc502ab66243c304b74fe27fb7ba7348b3a23cd65ad515755744839616a2e87120cb0a1e4f30ce7a6a2fa2488649dacd86c2e5fcd0162d826fb1e6adb4e0d9cd0d417b6e13a9ab1fd3fa49ecded0d3a19da325bac1a7b566823256fd56cc6b3a3696c752c98d221b9486c14612e7a22ec88bb5e9dcf865776c37cd5b1c6d1b18798be80b9562ba4752e1"""), - xeh(""" -df7636e15fc4dc76d7e29df36ec563fc89a4698147ee234b22cc444c389126bc96d2ce9c972fc6069cd53f83e2d4990fe1974e56fb71b3a6051c4841e0b9058abd922a9991fe7ac05fc9a84bfb04487e7d6b4bbfab626a8ae016319af35d498ad76ba40ce005a4392c2900a716d16cad3fe32c80a7648de0ddacbe00f6ba77a1b7d9963772c1a08a8b1f367a48f59533a0fb64e40bb9b1eb6d855d2dfca71559eaec8105e5d8150489ad8b58774c6eea083f37fbdb6ee4c2ed4eb7042eb656e4992613cc467363571bc2462d260b793664058b723af3eba417da947b8003482665e8bc16045bf3f7f6c1f3014cc15b53053ec1bdb450df8aaaa7761eb06aba76117fe6c68dd9a138ec9d6b48551ed911e931e384d186953d180f3dd484e37dac5355fb922de719c8e2660b490f903a7d40464ce7058b322977063392415a8558d97cda6d576fafcb9df2f64b3e7b8387ee99fb39dc603a717e6411b7cbe812b4afa69bb8c096d2217d146b79dd30fe285b2426f3a44240982de43ee6383940ffbfef3323bd7a9eac6c0cfb4ef222288baa0361246888911d91b4b6b76d21ea11dd80a36b12381b31d1305842262437c97e501cb9fcab443ec26ddd18597170f2827b5b1840a94ff76f0a9c52d57d9adff6b522df25fc7797335844fa90901502878d6bb89b0beb7da8365d6127d453cbd7cffe728d477fad58633ab3ff9cda39a84cd5664662c2d4a3715c3ba00b390b8fdcc1b6ffe6d4f5a70d0191630d2e4e2ef1d499521aab477596d0c8ac3110a37b018dd616af42f39c06e862fa5804522603ac1d6beae7d68fd6b4995fc6479b5ca9a8009208775b4ff90c613a47563554cb2868e17929ddb722786251658ae59e643226fbce24178cf44f534e55ee0853bf7ae8c6d2074af6c10697ebfbc14c25b80105d32a98c88ab81545c5ff80e94564f223d72165b975b96d68986d4861fdbe94e2ad7a39cdd1de612c4426bb6e17c22cfdc9dbde43187f009f8d85bf30408731ae68afb69d08150f63d4ec4d4493e6a5f4cbb350b935101cf8d43136c7df534614272ffed99a686823cfca16758ad5349d0db3ebe3a63bec25615f5f2c0000a8f9d2150aa4478119603b151fad12c582490be381944b52670c0e10e18a4db0fb44c463e14f71f7cb7182c5d58692edd26ecf3fb40e2b42a4d4f79e3044fe11a85a87703e8b1606b7940ea0cf57067f28a1c99430f7220fb5be10833040ec9e1bffbda6e791d3c200f6a83a271ad1eb164f046a4184c9168af5ee6b5497d7372bdd1199f1d684a912c45ac70bbca360c1ed65c433dbf2cc2ef2e0a94be79c581fb6b31f6d43acc43ebd8e8e62e7b8ce5128aab3f20cba3df5e433b5b64dcbbacffc7b0858184834d42412c09cc6f68499a7792e8471501fda7eb07f3c0f7fba7bf3ff6dee1435269e20ce5da5577dbe68a0869b211c9fce3e8d456fe661e5710fa964c9ac304c28b7d84b0063e175bb4de4fb6859a2a30fa4b15e5d4bdbe6241760829584c594c201b65312011c""") - ), - new DecapsulateTestCase( - xeh(""" -dffb727bba946a7a3a4066a2b14c31225806cec0a9f685a1d5d9a4ebbb4b98245dbd7a7303f13254302d7f428dfcc702c3b85780fb1a962529c0607461bc84269ac640f0a3741a342c960050940f06674dc4c449709a13449b190a28c8b89678df4924fe8288e7c37788e368b8c3a202db001cc56f70d7003bd6ca96c5114b28b19b13957231508ccc266ecac54f69120c76ab71bc9a1de3b9ad4c8b9c4c092845306ec68d46d077eaabac99e30d2133014d6061a507a0b1a4be09dcacfdf0cacdb24d612badd31cab6d710cd703b18b695a0d65caf440c735511cf6499288e45baa00cbbd904e629b8ffa40aad3799a5dbcaea9d3073a2b47a7502d2e53318168395576a65fd0c6639c9a513a87065c6657f822853a40ab25abb33a1fb834a14e2469c9d1a06127b4be271a09f7c70a948897729a93451ee67ac7834c05c44862bc291a89a7c27b829e7ce585cf4538d75c98c6e7975f62c3f0120a462cc93922156015b8f8615808c9ac8011c7282937ee3620e379c1227208fc2690030b46c71a6b08cb75f34347462763fb1c16ac23c7c37cc0f538584cc9b19be520f7b8186f1cba050c8da4d9576ae60c83d19563f620f50c0135a485a10425de995ec95b919443b1b7d87a27c3ad8046290a6677d3c8391be43f7ba4b46cdaa0431477ee94678f94a224ba1435b01b62444815022f9037a307054934640443207b0521ae9c9b0b4c1067da3151a30323bc5086cdc11ad549515b7b1455cacb3edcc4765b69aef4ab35094436a40b27d018b5fc77dcf951ebd214a72508fc554648679c9ee8089286635c45864ae591be1b5e8e981577a10ec7412273924a005b3219c7682e3c0671a975c463755e9941025b4b5a6cbbef5bb351a10ae38c5c19d113b13a8c11b36c40eb18a7b2ae2ad748ddc80e9ae011157c3c8c4041d0b2713156ac24a50e770b60c87a0d438a8b4570990993900d35421fa47f8283a9d4b9abbd0c5bb1ec02c0d9967ebab566e0a1a916cfa1ea52c7f9aed2152b852500a7581fe3fb4ec1b22b825c4af329abe6db87b2858d605459bf89bbe2580fb2e055387c6c33929ec0c60f269a6ca51c2323686c73e280aaa8138f8b2cea4cc27efb644c17b6cc646ba863aab91bb5dda711292a09257997f24a18b653910122965e873b09325ffee4b802da084c31a28fa6ce83da615b230cf1c11e16d9384be526e520c0e96059fc25653caa51a28657f96921f69c9f64f86805938166e03a81601b1f51a13eaaaaeaf420f83808429119fe017d9198915a6753cb35942f20b6ddac2e566b7d29b974ea96262f2a092a12592a73c383dc774cf6ae386200581a093abb9d7d5bc7d1fc694a909965c987dfd6b502fca685a6431fbaaeb85087c72a5dd4484e81b556b357b52fb76d234a24ec4991ec5863b66b7a09000e3b5804b575a5d06a0d60806e7b310e7804aaacf37d86e4c013f692d7f70912a1941ea0a7aeb5130ab43b3eb93b0e56c5cb242542b1bc3e9c9270b71fcf4028981ba7d9b60c3a6081731407acf2274021b607672528bb47afc2b39fe097f5c12f32c0c744961117212307525ab2e7a8f5f5302f2b90bceb84436a34b77cb1cae82fd6c63a44bb7312229f38375f8f405bdd3bc19ad9180367aba6988e0276031469512a6514a43902c6d66c06a236f247b077323d5bc1342c93ad1c0638f0b31aecc4a0980a543e488a39e726eceb54d1f807ce3aa556700842f1b2033871d2036ecc567f244c988242641c2aac1e31322cd08d2f95c5d559ba2328808618c5c6d8b49ca64c45082bca908dc5a75cffb1368c82cce0ca1bdd65128e3782d306829d608c2d40cd67e6ad09e79f39dbb6d9e41db559218c8263d1f6a8d4441f465a6e05510208b00522a9a6a77cae073817d99a40f1e84f4224289700a173c415095c7d35a32554678ee8087934c79943c7afdc40141a4810e94602d16c77cb80a2af5363f4444a9c32bfb8bc11e97c0d75435db0e70608dc95d85b70746263cf8c4def024a303807bb6640bee4176142c1be417aead89dcfba17eb319add262441a0c451847dd9e93dcae7c2e9c04f67c098123699df6c39dc90278362558df092c7292364c6c34cd0be104734fb1aca5282bcadc563ac571c8394b6fdeb9372081277b2987f3a26d0a812170303ca09218e842c1d2b886095bb25700e021abf45710550c4851fab4f7968460972144c1b6496f4465a0ab28478b1662b900353ca3fec6ab2c060d64caba43548c28654e1a38da32731d551b9ed03376c01be6466c74d44ce1aba9c2cc694db99cf1b09bc785ac5f0603c0248b352a69599e6b9225c887ec045a1708d73c263fea1bcc3782fd1ba1907064293fc4aced3604fd13c9d831323900f101534454bc7ff071372eba94db771dce7ab21e367925ca77bc3825db071e0f8cf207b2ca519bae8a2625c6b7b593888427a32462c0e98f009eab7b4bc151e7b727b6ba93ed0b686854026418272987069af29712c0c002e1304fa10071147ac1c6b4bbcd3232027ae2a0381a31812fb548360aa45bbbc711a7106c600af77535c51c85aafdbadf8ca6fb2c66bf66cb8856596b292490889a9b079c27d322ecbd34dcd8c2e637a7337eaaccf9c0654f748f73a6bc2921f36e1c6e662456aa66c55642c511c8376868a1a5c829da22e92e9a9af2b6ce7207bc7f94281c46eb76ab742c8ad0374973b36157018b9ba221afa3a3fd80601e85668391b97bfb30912038867b260ffc84c7fa054c0cb1f53d337b2f680d6f627093a21f7c6a065d276279bc83b759ae035288362b63b598e1611a21ae65c62f12948554cfe23bbf282702f87b540248219548fb0c363d19b9aa387353aec231965561397c3b4a41199615f02a27d7a5a6a8a93258b4466f389cd07a5ced1e75306d774c79c0b7b591fa5eb06b544bd4b751a3262481b300d1947a256f5c1a290c4eae87d0cb4b843441ef9f02ebc1100069b696c8ccbfa0958fb4551706306cb5c4d1e417a694718cf0a1e8337067a1a3c7981b81b868c8ebb71d956967e904f82c52f8a0865c05698f0e673ebe48c332293600986967559d9851bf75540cf7704dc35559b024298986d2f612a1ec18ff7f2ce1634482bf626939812c346174134ab65cc0bb7487e87d09ff7965f35a9474416c90a978bf29a5c3150bfa6745289473b485b7650ba78699b843e40c52ab380042cb3533ba8b640295faca956b0556a30be2b624942c97068f9d55db7c2d1acf9cf002c9ea2d973d79a050ba26ae235207358d083e310abc910d1bad823383a5154c8b9ceb2e525dcdc6e0a0eb8cdf10603a6185a3631d4ed5bf4a40e4ce8d367598819be8ec4ed706df4d26819f69729c2acf274515c8e"""), - xeh(""" -03788c19316364d84eae260acedabd726bed19087292fa3e1a00098d0e2d83f0001d7595ed9f43af93b801d06a1902ae53dc57bb9a6876c195473092bf794e390556ac245a5b8c25ff873d98f9736c2098852fe7aecba0264c080d9a94b353827f9eb6022e184a4825d708c64b4516b43de8badb525a1c97b2a449c9f0ec09908bef2904f609cc94728b7083d0c522bfc17f8d16b223ea19f494eaa917558e8c885c3409ea091cf7abfd250f3fd4d7d5ea41cdabe560bd2499cdced93e9bafc80fe740c43d6ef8eadd853785e6f3333bf1490e72191f139a591d08b68980f7ce8bbd4ef1a89c58ca403812f6b099ca5d9e1b80e4cb3be036b724142a90038abd5a9588e4540f8f0531714a039e9eae4b20b4fd7edc391fb366a1a2171d24bd627d9af4cd0da0b49e743d521b4d9c57f4bf82d3aeb1d0d58eb32f529587534e2ab9387bedb33feeabb68fcfe34b9e24758ec825060a1271639876ee6fe3295bc6c944d43ac028b6fcee8d127a2d54661bb2c2e91e4aee79bf7a122ed32c2ef6fc20ea01168af4a3e0d1ffb14d86682a9d7b450bf0d3c36af16f488c7d5cf0c3d6a02b0e88b85d2f92e6632df585bb4d3e2a7686447949db152ddad5a1266284fc1c37767d2a4d964dd1dacebec917bf84e92e7498cec4342e180510108acbac38b8beebde7271faf0a74cbfeb66241c6b27753135989e1f4c16cb062273c21666d5b1d68e34fdc1c34354c539d52f2de1d9c8b80b16a9065479e78406e766fcecb04017c31a2a31f7649f32315bdc6ffe2832f7aba29a76066df4fe473f47489ec783e36f591b607f5d93048bf48f54908cc645ee3f727c08549db2b07200d0ab3d7b31961418ee46dc954f493efa33296e722c72e4b69ae9c224b8b4ad9117f4aaa2c29578f8c20c95b3218f6970294064f9cc03b874a8c0907e232874164d4b8d8e1a573a2a894a3f8b5844e94a731daa17ad0d4c68443ea8d7a12fc74c7d930bdc9da13b322d2c12267a245d5c86456dfbd353f244f383324533ceb6ecb67552f9a9186bad91cce2c06ef328fc16159dda99984e03e624f8557db1dea2a42257e02c820939d1ff744fa6becadf1df969495411e141eecebad74201a81dcbb9ad80fd2ee2cdd2a34656d599cad9a62a96e83d10d6dbd1f2f0d6725f0c268627c6c6df9ae95cd972ab4e75277d47dd7e97a56a61ee3c75220c733b739ae941fea7e992c4513444aa6144eaefca06e26f998a503f33ee9840a66c0b4f0f305d55875a61c30156af670dfb236c32675d8ec124ef78e668abc8bfd20793f9b4a706de79733e4af44dcc003e55981f912fe43b298c46575aade5db5501582ecfd7314d4f62f9decace0b2992b17a0ae2c0c33e51cf4c25a93fc72cca2ab17125be2a781adcc8f686455a5bb0d328808bfe3273657c59aced7a486ed08ebb1427106d47278b058773be9bca944caccbece003b812846c81464de46cf2fd495e2edba200f92397d4c42565671ea688609267355287206d341213fa544ecdd0e4a900f7""") - ), - new DecapsulateTestCase( - xeh(""" -e9f8ce5f78cfd9f8bcc28488b4fc383bc2433228019c49827382628b9c77bfa29035cac08802594704bee56911d587b71b351e6e1c1bd9dc1b44aa876f25c7e9d4811359631993c0aa31214960adf186ad50f10b933b46197b365c631a5803c502875e00a364f60c179086a9164b3106687752b017771a2b1c702cbd457a113abcc380020b427e7ca04523965a1f797f5675721c588e17a812f1d96b1a272b290479c78612f1987ddc9818ffe53a4921c71f9325cba7c975d392dadc18f174aee598286ffa29f0412a21fb96d7e0776708ccdc615ed4d87145425992ba8c77709ca4495de1b75de367c704654c0f1b391d766101f65535ebc9a8e4795402ceaf06a0328240713565070552adf02749964cf851ab2f2b37162b52d260a556634ff26b22b3aa28745624f74139fbb1ac976b1fb54b7590632ff7150de75ba0d6507bd8f029056232a73493dcfc70582126f2c7933b919172d465ce1acbdc3c8a2a372b13b6813df686c495b915c8a7bc089abf732b7bc38f7d6a15e07022df5922a801c943364f942b43eac13930d3c827b8a5b0fbab35e62391204ca333648a21b13c01abcfe8800b4593b52a0560373059678a8d645267a9c74d98a2c2bb94940137ae68a1e441c4fa30a7cf1433774762501b588a07ae98c493e4b9003133a441acc50c4ac6b69c7eccd1c84729693d097280338c133b91c4531b812a40e5c31ba41a436a71cdd07813f5a8bf85142c4c03a6a9f338a5b1caae9422f8f30e523c34b4741937a9b0037b39bd4731d73a97cfda20bd3534db05bffe4b4ac879cd50c758035c3f912467a83c9d071184c43bb525483a4f0575da39b11c6b942479b56c413d54aa3c455aab2e5287768c7195221caa13512174a4ee7164e0eb3c0d32417470a388da4013f51c00e31d87452d7855541d2846d53a0446921412fb4a7e492e9c0637bad68f33ab424b0898645b824c996f40133dcb73a9cc95472ab067b32b20b939ba3d9265154b114a8b20fde59e7dc5b0af6092f90b93630ca416f0b648ec0c4d5711d652a2375243ee76804b3a63382a2aa260a99b11782ca88ddfa5cd8658b1f2baba58405ba2fb46ddb113373cbadb737f34f6bcae676ce1b659ad57bffe64c79b648ee44552a051296b839baeb1a20c3777420b4a8a342ad693b23db1a074605f6cb282bb8a360fc2cf5b5ac3d0541832791af9580a1f099d98f5443ab7c246a3a510a84cfbc9a06a57938f5608cdb33725b03d700abaad2c8145732f82d575de539bf66943402c8aa4f9021a144976350f37cc407ed3787079c701cca78c606f31f2bda660c7f75b6407f18b8fb81ddddb7aa013b725fbc1d3b62e2a9988cbf8c443eb8c12a0ab2cf04095c622f2b48c01641df12a940d067c6af0c0a3bc0243bbb30e477af82c18e32695867a9cf18107f0469b9b95111c2a1d3eb40921b155e0f5986e25cd036c85f176850e57289e868d27585b965b721832862e4317de0c7d6db76e657166e4b81b5f57bed27a7e097482e5260be91767a7e7a37649726a8b79b71473cd1a25aae10aa2f480bfa65f4a010595435eec287ea586070b9a5f31f05b72c743288cbfaacacbbc5792ecc6c568ca3438e812772071873b6b97125b613002a38c5bae914cc90630d56673b824a14dd20697f800b13b17769c450a8b0dae472a2b70435643c82b329ca6440e3fd16a23dcba5d859ec8837a49d18f5c61950702846a806318752588f88590f0672fb5cf02f48fc3a8073b50c17dc8ab60c2601ef15ea514cf965a42bd771af7b917cc28a368755771ba3069036f57e1206857159394cf1b9702abfc5df3fc1dcfcbad79f2bcb3b7c9150706eb520a57b547bf217cdc902214c1b58a7c8c585b20ff1242de6525ae10cb857881897319f909870b5a5a732093f17c2172688fb585490307902e1872a4c384624b8b27539e7db3c78c272c14a988f3ab48a2e787a794b83186535970c0d19845b884c5cd427dd5ea699349363c3006656594a48bb22337877917258f0a356a58b0d5da3bd99976dde9357658b1394843c800a2cd1c608877703e3c5ca1f282d8b4b773d1623a39833f393009441c8813698957bb86ec8f4de60a92e0c2e6178e269024ff5896e2475d65854cbe4466b0671684b55490240b158657384b67db1b0b8c0c07422b460d05a1323456ca73cf749a727ad0cb81e1109388af47f321cdd836f008208978430ff1b6aad03163a412f6b93e09bcb6acdb3633b69c47aa5acb004fc7bcc8e3e2a24f949e24d1c23b9346e2c3a32c1791b67cb16f16a96ac58034daae1ca11a838ac0ddd43883976c9ddb799d53abec005b00faa3a15702ac2187d9b13b4e0a3ea8b2c9fc77a1cc23b633f9087c188291c74c9db8622dc03b78f48a35716ab5202cdde6cf3b62464cb87064b7b02a8890af2969c9275adfd28ec6c2940c717c8575a84a5cbbbd983c57183fc2eb1ac35744cda32515c2a66e3c988ed0cdb9e6778e98295f7cca7f283960275ca0222dae433c0035522ca7650606436bd767679b42b4b69912d0553e276f6b6428b7d7ca99b7ba855448e495bc51b1871a627edbf535045b037a698c8833a4696073bbe6740ff222c726c9cc636402c912dc1232b10197b7440490b92ca8e683eb4817a2b866c85a07a38885ba0284da691f99f167e1baa2caf41ad75a7931a43e21a9671bd97a65dc415c03b368d075bab0cd216b9939e4325e1c9c96251d48dc7f064339dc062b4a3777cc24bf01c272d1ca86819027cad3a491600efaf961c815940977074514a022dc40cd503ae778015d3305cd8b04d4c001d410cee5538e9331982ee52fee9857ea5c685b41bf16bc6bd7754dcab4ae99024f69336ddbc42a95079668bb8fccbc6ff66a6b05768d6b83c03c759a2bc6ad2c2205b26b41fdf022da075cf1589d88954ba502875c28ad47c31b857998acc5287da6308f800d53f95797e52d0a29ae4aeb018ee418c4f7cf72696aa286addae756e619aa8121b481ab66f25117970b66e5866b90652190d184669a4def63219c025f02149f287656e0a235cf426c7178ad99c61294a2cbc9e34fe5ea735baa8da8384daf0a13dce458433067b004bc78922c3dcc025e5688b67ab4d7fcbce06756d49772d4ebabd8b94bf07268cee346d252a9161262d38a9f04eacd7bc76a82f477334a0b3c272b4ab84aba7205a1b158319139827b3d219784101456b964929fa96d27d48ab35aa1b6f914c1465ca9548559c9a8d1f7e328029954825a12a8b4f2f4cf320831f0edb16a7359738889b1cf1870ea47583387ef1a1a3f7e78a70c9da0aec4b2d1bd6f4200cc78981182b43d78c40b828554c36d70b960a02c66490c15a4caa6a7d5f1e9ce34"""), - xeh(""" -14b590d4c6aec9d35b258fac481f7fd76aab8734de44fdb50372c7d51a5c89e0eab0492d73a81289b2e144dfc808e57e4c2678d3d10a1174f11c08c67716faaf021a44538a85834cb1ba3185f03db791df8f1c0f2ba3515eaa1ff3d478f457112efee587d47ffbb0296d23153730f74923eac6a51234fa13e8ff0f849672e0e5b6fbc7c10acbbd9e422515cadcbf93709f6cb3b92f81fa4dfb44286752bf430e384058f6f5f0125a13bc7b86c3171cee73de2aeab726af76d8ad62492389fb1f29839938eddecadfcd2168bce9a954d9aa56d99cde981cbe9d33b3aa79f1751030699981ee68f4ff3dc3efa17cf8f93e3dd4b70aa8327358196fc77431f900c7741cf5d9c11bd0659920f2ca5f60e023dcfd6931f6202d9dc0fdec8b835dfef83b99d188935ecc9f4ed03b993bea634ff0fb77f9d2496a5125a3ea541b54f020442151d864ccd3231141a203496fa7a40196e9dc8618dd3a891677d48f1e694097569db4a52081ab1ff1396c3d930d3ee635500675ab1662f68f921b2ab6730de901b23121de37ef9ddd40cf62b13f8f48bd7e4ac2a38ad53f977afe961260de547be03d709e8316c7ea9b5415e48b240f5b97e2600c8d5f2172bc4d10f1a2814f650dd07373ef6da5486621f5131722add069526d3b24e97cfbb8ab5ae5cdfc16d944c524013bc71da81afe1bc9648dd7a5b0f0c509bc0251c08ed15baaf8fb9bd3db9ec006a445ceb115562f5ce1978781e1ee6cde9cd1ea2d5d32be612e7f2d9ee1a94dad192019cc031ef44fe5c1b3de9fd76062faa5f25b5a8da1342addaeaa095ff3295bd5002b7d8a2335a04f1c811d8e7c6cd7f3a43e1e4af1efffab01015256540b9c0b430ee65830fb8d1732c903520319776daccde5b9628416b422a36cfd5708ea263067a064fa753e35f08ec3b2a7a1839d1137b000e7ff2f95ab3484e9f1aee634fc08e217168450b2419955e8260dcb9b386c2e5dacdcdc1de195200e5ed96809bb89754ecff2d02be76226ca99b1be92123ae79a63e8332adfacbcd9adfc04a486b9c4defea6c2887db85e5215db4b32650199361a3fbe20ceaa0d6d578ab6125145d730e78566ff25427718d5a0fcd9c6adfa3db7f23017e5887ea5c4cec213abbf1784f548677ad209cb32c09d478c629e14944d9b4e699196ea771a4549d9b00d7acfb3cca68adddf4945dd63a6f72ba74da32113bd4f8631df7b750fc56ca49059839be96103e9f4266ae7bb7ec257136ef895dbb07ff91a63aaff2a5ea6f8fc35f345c52e0ffdb7e44b82755e80697b9a35c3f34a378c45b99ca31d009d6ebf23f923d27b3a10102e2e82cab80cd52d68f83e908c43e379f15c011e138de668eb2c74928356473cddccc209afacc181a054cdc6085af4933cf1177000abdcb405e9478e05ecf5b3f1a441d0c0069915352bd33a5613fe93eec63b6df41be11ca585b4354311569e866f2c188552bd287520b52b949ba6752e723ba887897787a53eeb114627c08621ba96aa69962abd5917ef33e7e9""") - ), - new DecapsulateTestCase( - xeh(""" -a52bafa1cc917ba04e1db8b8e4c308863025978b8d048242a744c60b50cf651b7670cb488519815a74b6a0ca7c8b82abdd168e9be479556743e80bca927503aff16714e60962c2c9e93576cdca27336796076568e0b5bef71a7434e532274a500ba9109a8a0b7b771e5643516de322da248334f1cb70d27312242e0fba31d07113d3299b388b3be33b7941721ba36c863849a32425939dfacd4851976bb000e61cbca9c6034267cffd30872462c780785506506b87d270ee0095e88641f877a838b5837c2418a3ea005b2a5fc62c9fd1861a85c152adc63637273a8db69e4b6273f11c6a902b120b6374154b7392b0483a664e36a88e4ac5aeefc2c3f765af3ed68369d5c1c1928cad77227da1c4265062cce00f1cd03b169a782fd48d8cea5c80560af611597e71cba97ba1e163c3fd318d9c904d281a5c75b79b3d1b71f6fa9bf20915c5c148ac441150e63741177cabb720ccc72505f3890f1a2696d672012cb2a73b9d7dd05d0bd93930c77bab408078b077711b6d08176cbd227f1bd24e56603d8481939852a7bb98a72c073b622244fc4476cd633383f19784e399c24b55db12bd30f4aaee90c714c75342435b509b38fc7911aef43dfa169cda1402258c5835515907b3b11be48e4a7770ede4492c7b5cb9739e2310c3bd9a414b4678883ba7d374975a269021ac5d300b0a8a9071b2262d26b49f336a6f79e68a1e5c2203e296c960ce3ec71a5ef794838ccd79c758181b67c7988f96f858a365a9ba48290009af0bab82a4a4b18a7990d9ba0fd4e23da9d5c6e0d353b2fc4caa1a5eea00a7a0baa2ae1576fac5c6e229ba8b71b23b247072e0b3f92279e6100921895a0025b23d334098d92793fc5a50ccaf588cb2fb51c3a07c005261696985aa1e90a167a7803c588839d4c555c18f73579b3e422ff1202717d4842e48a846c9cd1d6c2f647b98a48c7e47a0204cc6b6d007b027f1c1721388d5a3ae615ca2cdec18e3f09dbdc66249d77ee6240c8240cc10021a6dfb4358d7740558517658c28f507f3504007f619fe51947b2681f3d48c1a81412fe6a09bf9cb56ff648810b5fe5686bbea352e102bb9803440367353646b300122f9b16b2631329e8563a5abc29fd477b8bcb5f0ef95987d4ae71243979b201b0cb27f07c839703bdce9a738eb4738d6457b937a2e65a011389737df46aad436689b69fd7680180ba0770c0484c085e9499adbf7026da72b48ef1cf45021f8d604f2a761d8fac10e6ba71e215712bbc73c5aa1f4b801dcf278063690d31617cd863237ac91556f492484238111a9da46ab6a1c3c1e00620b62102bcb1082ffb54f1ca840518a3a75b845a59ad45111170921f65704f2c83a8281b43facc0b2b007b0e88206bacbd3c6a78faf904f6475d328bc935d01de6033f9931b3bd5a3e10a406eb9290d1052eeb374ef71b96755446f4a98b6e4c9702f7c7acd64755478824855d3d25c9f8733f55f788e8e91913737bda97c1811b6cadd10e9e90072eb81c37611168ca0699c24d1426a1b3f6ab8b346d0a287ed4a04869d94dba7160ca32ca3b7a8ef8b896148419e3a80d217c1304394273e10d54365e83f9bd09119736f05e36218d70f9086e178c05b46c32848d4c14cb6c567b994c1bfb75bf11fc3db2915f890c626ef2bfb14c1aacf9b77914bda70a37e165c65b03727e1834f2d6471f85bc705b8f63c75672336141c44e6c9b7162f0ad93a840987474b7711be7b8b7a587608604acce1b6ef5618495f365f221b5464c41d6448f87986fe8f71d27658f40a15bdd74c7ece1b8992c137e3b43b8c27e228bb9483255a7050a23755c671b4d9854a185b2707b342d051c262d7cc12439b258b30a4c14096e1c91e962944e7ccc11ca35c5d83c937aa0cedacfb89cc6c552011e31b11fc95626fa0d1c04023d8772501402187ab2af9391abe69f988a5daf8114cae6ab0010041ef4af84763e287c4368eba94e6b0bbde17585bac5a8d89e285c4569d9025b65b301374a32018366bb66f54aa4b8cc385f93a34325282f36c5bbe172ad2cb44e32aa876113d8c1000d94b7f0838acd2000a6e386e287cf77226fbc9588a5019b073a237029820bbb77f934be084318e01562eda6b4e0f01d2dc17caf290fc5b2037738a33ed181c6b4aa4d10982c38aad1143ff9530e062ab3f16a9177f145bf0a4b1a1b037682506628ab3fb127df8ccc36d0095074c0db42bf628c690665cebbd232b302802943bec761acb00065b1e07471a39d36449de0c8591de5cddcdcc3a1c43b5107ae30640fa221bc5262a86c0b0124b434da226d959ac55060cba5f32587b1892471300159c9d8045d59cb00cba04821f1a6e19a713609855e3acc0959cb2c88ac19d335b0856d19e34e306602d9c66ad1085edecac34c55443af41e76fc072741ae61950cfc174ff4f3cee652b280a39124ab7bf6f5283f2151b375a2668b71049042a421086db12e7fc7bff4d95605e8b8d5c59bdb47a71d06089e8a13e064040b1289a70b804481bd22ebca2a4340e5a498e83bb0f96c4955f516a5d125408656b72299ae73ca18a2c58342810f9c10808353acf006f93637e0254b6cc216d4c7336d5b5ce5b55fcddca0cc59a0077a6b939484eb64648281b51c3756c9c8bfae53a904f25925ecb719c25a3d378f0cc5634a4470cd839cca90701582383bf27fd2f2bce345481a2a80cfc3b6588a3c328a9d2c0105129472f5231e5b901be663016d79987812c916caa364450301b7ac0f463e87e3971f4a5f13888f66d5c78aab602e4a01a99992fa25cb303cce0624bc69063063c55c16b48deb9a5945f28c614b7e5c83243fb4500b27bbd232baee32638afa0a72f505c1ca7a286c90acba7d3783a33a2b18ceba62dc7287db9aac24a946f0bbcab94c0a2d08c72b437548b9c0d5c41f3fba3d32026bf8db12ac067cc37bc79d143e3a6c40439bc476d5b10724b643ac4d5f230e2a1c14004835963b58a231bc94b008f3f50e9b493e849cca03170a67e90f00d623c9704ee9f788514239c8105938323a78f34751c8960ed420d5821b0db6722ee07a5915110315cd00bbc4ead43719bb3e4fb63afd743c522c6dd03babfd8c9891549814ab2b7e0c66c8661acfd34db8db48feda502bb271ccc03146e7c5423a8182e84554a9349238705c250c8e579079c6c7aea73f38476f46e22c67a67b4eb20dcee2556adac841b67f65421a814c9770f84a683ac0c2db2f26222107d360c1623c9da4922b3f97e33b0bfb50623a2989ec50c6612768f42d5769fbb7ca62b31fa837d30774f7ec8feafbcdbf5805c634c0c430d47b759eda5d1f98917a2234587c5969cc1ed10d51b0dcf8b3017143ebf31687930f3e2c610a4850"""), - xeh(""" -9059c2e3a96472cd2e7bd86c3e78574ea36e2586c919b94a386dd22c9a816b3c9e70842584959abdebc1e208ea779851efa48a70258fc3f7d76c327d536e0f253f06c33698c8af6bf3eab1c4835e5ad76bef5da6e23a6f14f5d47d047a4a2b71ce626207e1f5d6619a992ba98205c6d1e27ba4ea52d450099988ad9a2800f3a18af4d4349ed0b7c04bb4a76b7c7f339898749aa56b8a6d274931904eb1e75e1f497c1ee28abd951b34fcc0dbc5885ebf91bc6eafe79d2286e69416c128ab3915124f80b6c19159064327433105fa13d97ff255b672fa51b6ad3722967f413dbb13a02a9014f6755c89559c40a7c6e9b61f4c48559529f1f9413824a2e466ad3dc3c8086f113edd0160bcf00574087db6b7288b1ad665781412086a2847f24286a11aa37f39088ad167344d0591ef98b458b75f5d8a4410fcfaa83d613166f7fa41ed17cf17ce4673f9cfda45592242d6f36df8f658dc6825d2ccc30d24be4cc553ac655e64477ff91fc70a26a7fe53a6ec2cdacc75872a7a2e6a30387443db17c694bbd9578971f1319e636439cffce1f46aad2f34d60ce2a8d96186b48e64240d1d0a5af878e7636e15664905f7cbceea895d97610cdcb4767c9288e0f8fb0e059bea8363f5cc036347eb2ff8652c68acd16ef5e0a77724449f8a143b23533209b050d3187e5a3ef08c9c5dc11d9836b6396f15d4218c98bd5b440853ae5ab0a921d476b0b143ba87d355b5bde28f751695c9a392bd2e29cd60e15d5133f0a636bc05c014cd623ce9c1ba5ffd69470767a9b779b03bd00971ea534ba1c5bcc0f66d3db1aa731566fe3049850aac69a461f648df35d295f91438ff2ea8b74de1937e29582b9abf960c3c74d41b63955348822c31d350b03de0b50e4233f8bbb3e3acdb2eeb1a6b5c68cc89816ad7266277a8068a8633af85f7faffb9d94efdfb61360d1960393f71050fb4a1fe964377860a0877d18f6449833f02228bcaf8b4eeb2bfb79fea35a4a117b6e5cd8c68262696fc3a011a64b5c73a524221c38b42f6e8219f418044419a08f670fded4634ab006403d85e8d03ed1a0d1550dc5ca41271f63fbf2b9361b5e196f765a18e35dfabbdb2a4b4b6ae7ce176a3a88eddde4591e5ed0936ba88e5be7b05862cdeff319dc9a4ec0f3446d8fd6545c3a240689872b9e92486a1837bec167ac6bad6dacd3e114b7da845b86a4b9a92ec3d7e37327012caba3dd22b8c4c2d2fc1c69f4d6ae6913f966444de9915d3d4a0185d82999277690ce9fbb9187436d8317460428cfb8e5869b9c9a48ec7f3d7c8e16b7d3c1111a5fa6b4f5ad80e5f2cd6c0a331afe0c554c01c61057bead42283e9f115689948129065b38ef077cb246c83a6e5156bc14c134a470ea44aba6c6f6d6b38138d0ada2ea680af00ca499801470beb646f820a427512146c60a857f812f7cbd89989d5a13311851baaa0deb66e7e2bd5f03edb21a9dce53d486434538ac17ce82e7c1ca87a39e31e039159b6f9b1318b5fa4122c3a7af4aee297d2ee2f6219""") - ), - new DecapsulateTestCase( - xeh(""" -5b6a031b4405919bcf0a292e27c28187e3a4b1541be42bc0d972c2d8580253b9658c80089d39ce86021ce1504c6838a4f2ba1e956290d7895255ca0e1a14394ab8c00a1506211b9943c98e90838dbc70c6a9c329a9589c54f81c405608935c4c5fea378dd30a4ed60a5933c512967867b283425a8e222b50128c5d4385266af316add0c4b60895970944b6378cfce8838922325d15c74d20a27e912661796cdb959da71b96a34c514e561d306903eb07b04a394bab33ce952939f5ca616f37b81fd79b7b988712a86b80c639a4815fb288689fda7c9e3017edba542f59bf1ca9a6c950b26cb5a45bc5bb20a9b9fbeace65885037519a9bb72842ccb21928105d10279a500e5036131c97cae02caed6a9725556ca31415a683b16149723d1e7be1128c177497a9d942b727c1361f65e8a186a8d612be43044f24c4f977001d43446ed6968a49312e4cb9683db08c731ab0cd17b63a7b0ee19b30bcc0ed2505bf5fb915be7410a9948ea31570574029c531675b64dd5b529ee221bf4e06ec5030b8de52d932281bac9a5c7582bc2b781c7b89517c1b0a2d8146695a694f7670b3796130c171a949aa0f4b8ab9b8c894acabc10be1eb9c879b3bbca990b74f941f2782d6df8300dec9eaf51a48f72cf0c01c1cab4c420d650bbe23eee7181a71872713006e334b968a22d9d3883a241b72aa0ab81847683b077e26731f69734c6579ff7490009f05928ebc9afd499525b09729056768b9cd713a5a1186ae1e89b7157291b8698a4e2a675014b864a4106b02317994da8d7cb9fe2960cf01c6aeb67ea2b5108c52970ba2c9062cc523c59e3725480d528f75c9d5cd19399e8352baa5bc1662eb9e62153fc044b65a4ce2681cf122324d3c69fc02f5572b3695718fad2808e1abef8157b2e3904e22c11844c1df8d639d0c6712a190da9b75a6dd62212fc6e2a52ba111280d5a801224860e54836ea650d2e25cd89eb5b65f21d206c4e8b5a3b60c1ba0663b458e805a14927a0894575e2cf7c191e92bc20f6d7b81aba73ca28155a4b3feec403523a1d671aada5a5a1863cccd060bc4fb0009082ac282a43b951c2e54a7c865636cf91a617f3863e50c9ac3c67252365ce19ca690286cf5ac7e8355b5fe5426e1031c000318b09b982b59cd7c0cff3e5927b030db1078c625aad57976f3a03a300fa796e2740178b4125d38754367707c5c9f08b8135b3ab6859575bb0c54985186eacb46bec4499d1136bd49965678d62c7c53725a0039727f51c4760751d8c418d8170c55d44c0ae02cfcff87292069728694efad712306929a71045a9736e08e6346f148a0d23316de7b839c9c4fbf35ac38b32e4a394ca61b686208af5fa3cf6e86d56b4cf008d74684c175b178a2fa6576bd7742cc5c0679425a3283361d47956565758f507afd76f3a3747f1369f89c857098040722a9901518ce2290e03375c7d29118a11527ac024a40c8cede69f54c4af2e69134a2aae6e0134f8c6cb53d6ccfb36765d137ca6e982ec85a7d4986f1744b3b6a8b352eac726c9729b571e47556521d76a2705a10eb43d9ccb35fe0ba3b6461b83425294bb6f0ab9b8aecc7fc2d9685840ba2a94167f4684b9a173d954c7246a3daffa8fecfac4cde76265e37997e53d8137c99ef4cdc8f0194f1984b7b3886ad87fb0227d569ba5783630f248add3b881d16c904f46249ebc73a6151ee2538fdc5b248971b3bbd5af462c36548b273beb06480b28b04b359c03af7df4344cfa28cd469476e3499652ad759b761697861f1479a4400bc034738ab9b674311374374ee5d73349c0a7b9dc0c158c13739a674532b62408bcb5c70ce4c54ae26c30118c8320eb05cb0c1454b7b06bcc013c7892c9b4693f40c6651925b0a3101da97d98c19ac5a5b3f7930061db8d38e37e37e3469ae6b52fb10300da5ab71a16e9d762a2d86473442c752187d33c2809272a16649f8403609e17bbf8003aff87468e8cb4e0e2b3a2fbc20fb8b172e606830666b6550a5c13ac862113b817c2c2f1415da33b9dc1a47451246b434f586a351c55b4c9b465fa1cc9578792368209655397c3761bd7329917497e3f357f0dc8418d474ec2f01af697b5fe30248de409130c3dcb079b50ccc73a1b709ffa5010f1644de0b3c2598e8580050a0b659c034ba7ab1c627cb43736b6b8a754dac647a1b94878529676426175c700896b5d123c5e125404a59507f5fac8acd5bc5de2035a33ceb680c412374c9753aebe423ab515886cbcab2554c9b28c3497b63bfbf7adb8db29b59abfcbb501f318b5c8d61c2f33336652c787348e00c4c15c911f7e2cb67f02ba5c2b8ec9c87ec1fa6d5dfbc05f7961c6c0829d7687df542b4eb42d8d373ecac1aa55d921f7319eaca181ba1c259e4118bc27615a866944a10e28e260f7ec1083229192212ccc9085c5436210a1392918567619b97be71f65c017555a4ae60a81ef0951165a191672c864f2112839596a343edb58885bc58c6406334a385512db7dadac2b7f510830f3b3b3440f73038d53e5ab143a6b53702f30407c6c824196b4bf069a812777a8b2c26e661cc083c52fd3259ae08b9181f06d8c993f14779300ba56b88647a5314066d4b771dbc76250a60fba5afee147b01396e91a0f0dd30ade7c82b6d85f8613a9354630bf669257b57dd563ab6b07c5a2a809cb16990ad98f23f34bebf6064c049f33913d54666892864627f8c4e64b20e06b43a5c5829bfab4eb774907c36ed5eb17ec3101aa8434a5318354510df87cc01a09d06806bd95939235fb635734068f1594a11a624e7b87ffb239dfdc864ba4322ac4357e499e80656db0bb68931159d759806b3c2518a319bde226a3c250ff0c2326750a0d23beb60b442ca595adac6f775cb06cc988718bcbc29c83e39646b99abbd5f7723757b9aaf63857c30e7f0337b8fc949cc0b4ced2260736298675aa8e6a1022aa1b8cfa3104387e429370689b398a317f0bc50d7841005048aa7e29a71d0b03348328c0c268e8f6a64f518ac06c4398d7b2f82abafaa1c9c37bb1e3a147bf870cd10c21cb702aed892346cc47e6928d3f16575f1254dbfcb910aa967a87323208937d1aaf7fa90f1261131ad4b04ff36e9f6696594a2ccf3a021ce852fb9043c194c4d3d704edfc5e3d2ab671b8103e8bcfc631107815790e5733eeb66fa344b9f276c531e5505303b267b6516b00b056780230847aea99cae15bb4faba0b9d461877419ca2d16ca437f0f2963e80f169e7bd65d440b7d6ed512ee105bb1690052a72bc54207b09e402819946c6be8ad1896c231bd52d35277981d8b9f8b4b3115c3316a7cdd3dddf022c3c86b725c5f2b54196b7d68684b9fde93be78e38beaeef18195321f4e2"""), - xeh(""" -90bd8c5e14744ddc8675a988db156ef227b724ca2e01095cb11f06a97e889db1e4f9de9ab6204f3c283e33d9de36249010686787e14282d3b7c2b074db1f0a509fcebae53c0b35dee8e46033a1f253f475eb9f09994c7d3e209cedc8d2b591739ff1a62e1f4c8cd833b8da55c8881ae07b3c84e26458384102722916451c642d19b47bfa713e815b37d63d2a9a7e4a5304ea1fab3eed37567d09ad16a4dcac45605b7ddcc65cff7aa8844c82e5999ed28f5d1109e7fd9e425b5409af85622420d21585cad96afa841584256682fbc10037a4989a55d2afa09a12bf007c569b25b937720623cb58456ad565f5b5fe9e475d00e67f7414411913b30949954d952a596985bc2786b7a6e697cdb6d82f24ffa4d1ccc6d8db78de1ac91991f22c254e3f3b5a0d3716e645af3c12c41a495e98115558013d12893c5fc8c21be7dea6d2f55befe296ecb980e3ba40267bd1aac40f378c67d64cbb0d053ad33f9949cf8c1d43b69c6e15a5aa2446681eedeee320c953a8f8aa8085d8454d9a6037dcd887c3499cc8e6e91e485fa8a5e7ce6492964dbbfaa9cc93a45b3488bcba7384787e1ec10635a092f51370421122dca671a5d670dc4a3735b04d977b1e378360282212024ad3fff86345a92f570069f8ff9f2ea5c28c44935a57e36db1caf6908cddeaf3896524c9042f3120f4a921e22b3ed73ae062b863f4fff402976fcd1e818a9069e594501d1776ea50377de97f71d9093bd7bebeb70a21154aa1c5b12d2b33540bf65e5fcd460c9a3e48386ad670c37b750fe72ac71b93b7f8c468692d95a3a4393b68b44919bd1e9e87492d9debb7fd09bc1d68cc758c82789e50027bc73a6df171de78958a112d50d50b9e32ca68c490061a4da36fe6bf7b0d1e8a8825045dbc1b5f6af55b953f9344794dde62414ee2ceda0c22301d8a84c01fdeb67cb8f3b5b3f66289d99a556985e09150ae36610f0ec8ee2d6b53ad1cd7780331f813f4397f5380ea5f1cd838e7cf58144bbe9db4366c126221ab1adce2b0a140a780495f1d8b2f41a6b5602e3fe66e449aed2e8cc141c7462c290d8f9b4b14a8705fc0cd689930f6686a102f3d90c6eeab216576d27112b6cec886241514c7341ea4d6198247d9eeb1e78af0d717a1de3b87af12536c37eef2242fe6d811126d4d587f601bdf739a0432d37597a56d518e4c5898037966a1bfe756f87ddaae26d382a04244564b90b103963a0798cb7237e4af9ac2fd1408b2b75583ecada700d9fef4b8f7fc130c3ae123a77f36c8bc3604fc9b517c7dea1bddf2fc0f820ae58fd889b68e079257b0dfaa0fd57fd2a4356b3eaedd37b1afdf48d85939a4b66466faee18f9c01c24409974f5e9e0b2caccb24c355f93a17dd899aa140191a036dce3d61a7bda069aebb7d24e1aca67751f2230e2ab9288e0a6f82489e8bf7a7409ade15e7b5c17c301e56e9e22f28c50047f2806f5f4283f42b9dc26d00783beeae516eb1f52c95a97de787d3491215b1007a3f42f80c969a926d2f56e81279f8013""") - ), - new DecapsulateTestCase( - xeh(""" -57c70235fb2cdbdb64c2f2c8aa3933f94a9607104169371c182b7997018335aab5bbe8ba7050a5d97538a3f0a1819a56433b1870f6718b63c688860b7e55960c3b80d7a0029f973058b9bc09868b454b9d549603a5187704b904151c62d36516c0bc195d53ca93a0455eb02eb194295bb5a27b51be81b45d865ac7c76a0e81131528c54e14266c49e10bef401211438ce8d969dc240a0812297b88a4439667dd8325406b97a0f91eb9938b3ea71621cb329b24cac98311ac443373b86e7c2a7825532abb0357636ac4276655f3b2b9349054d4c6c25211876359cfce44bb61c41e40316509d6349761633c58958e2546e314ccf24139ccc48c70313fea782dd7c41cd3f9ca2cc7ae61b65aad856d122bbd4d973ac47c0389baa0f7e84fbaf7c57bd38d66127c7c1a226d396e5c363fa76515a67494a52a74fda7ccce919a027843ab5b1293d6709e60176f78887ba4b2456bc5422c49fd289260527d7497ac9ae89c10456d2d018b0b0a365d92061f9744272c92a6388a7b884ce8f722a0e999495b2322f088b7c561c2eb632c322b4898ab3df25d90e5b1677aa4ace1a0bfa91b50a4ad721943da175fc4969ee8435315acb1a923bfb30101f6080ce191c91b18b79a09561b3a7fef5879f3ab59a34177a6f0087681080e9799a4e874dcf26ca671392f5830cf384602636b5b9118916ba7c9880d0202a5f8cb38efa2608f68553dd28d1cc26eb6e06f18d8886839c342447ae4468c1800b64ab89348a8ba111c5740361fe182812a3716c1b577ec75c9f14c1ed62182fff0aacc20c2e9635c18e6a44ba541ec748059d386c91bb94901a7477b6343e6cd97cc711871084faa40887b28721176d8762e993b7831151d4287c31050491228b6af6b4913428646b66309d055e0b470d3c3584e960b17530d63c530fa352d6cec88b4e93019dacc39ccb10a04718026762c255b5e515d1e381dd6d948cca73210b184782528a5340feeecc236e6495bd7850ada82d138b3fdfc5e9aaa5310db28fdc9cd9d7ac69ca869ac376f153c0db1e97632ab7b4b1965ece9b7024c2eb280cd6962639b661c9dd719c7cc39e576450201ce3b5747d982b9fdbb728b23c30457c7e537c3cb5a0580fcb211b43fae656d9560296f1c6e7d0319e5697a3202461a0c52d8488de70ab842970c559026fa88004eeb746920402725501146b182a2696909cd7a75260f78cb1124a73cb4b22cf35aa60ab6d4a612e56a4f135391367a64003a0113cb2fc2a2a27c4bcb9e01a6d17623be3119f2795dff488c733c7f1299344fdc80f5a8cf5ad7b15ef76a72cba0abb181f9c6ca064a9e5366cb7758af1ec0400cc1380c837dfbea20b2e2b2deb9419fbac7fab5b4e33691872a8d8db27f1799500a938d309c50dd364e70b3709c9c67a6c1b721848bd3cc8b0636879c965be513a12c973b2c17b07a7901919a9ffb70b101d5314e508f9d1979fdfa36dc7790b4b034fba6ac85a015cd82684a573fd142a05a934eb647143d9070ee99bbe034530e281a075c70e5ab266858c3c57c22b9703464497b229acd7997bf6a31b08fb1cf206b569ebc7ff62108b0f404dca30dd0d51a8800503370cdd3090710d5a180d8cad5e216438b4535c69165f884be521e5ccc33f22695aa122e5d918e8d27a390035a42b9c8e4abc9dfaa92f090360c9892fec554851c7e434caf9d41896741aca2f2ad64e8b1e3916827215beae96d2d190f22917ccbfbb3452914078607a0eca4199714ea8040e9c9945c71501bd1b6baa00628c62c220b5dd79846da4399536547b04811f6915045e63abb9575076150bce269c61390cd3a3fb3db7235390b63dc49d041788d25650858a062e49f4d9855cac7c7d403b172044e2234425f503f3f613a5b1a72fb32590c851d71295f0da4113705b306e6524c398a59a83ee6a9893091beaa78470b274680017387eb13b97baff06a23986251a1f1a4f73a72054640d6574b5d070582925b201b37b5a690cecab7bcf72e16e3454eca10fac9b760cc94928307c2853a15c47c6d29ab90e322b3b566a43166428c09a1b3ab3515704bc76778c38b0ed224ae727024f2008cf2b5128cb912a9bd806bad62e78e1d79cc90f3675f863df590210a18b6b629cf91738f23280e93ba04b3661cb0e040709639a5b495c7a36eca739270031c97db9ed9432a4ad86608528a7ff7034652571fc6904662116980201f8073ca003092c19df909989dfc6744274a2e01377099bd618aa443c883bf8b87a9bcc9d35c56aeb49068592d31e16e12c711cc9a1e9780329a92aafa84827e685a21a84156b29233e50f577c54fca9a3f9dc6f4707704b515d9f2492dfc22977a36dde51704ac653764b124cfa615dd5932a05b895987aa714c1bb38c3166b27cba655786c29fb733448381fa7606df0f586c3ab0f2660901ed1444512ca70108e180776078c417cda8ad2241ea9304f820a9964e455d8da350ec30469fa6ec3470ff4848da109cb1060abea4c3a4b733b97d04beda35e769a7f1f84bf98c8790e91199ef04a6ac80bcdd39ad4979c327b84c0e897a4046bcab450eb3cc4d52b83e2f3845bb6c4729b3508e064576a6a8caa9cc12c917118196000a1e478c278257da8a10d78734b44e426335c81a4e6988015a6eff43470d98becc9722d254a6df327ecc91174a3a76ab430ab40678b37cb098926823955d5d8aa8f4c2598eb8ace098da3cc43e84a4a205c00cce1962c7411646a1a4cbac0fe884db3d55cbc0531d4497e562cc0b6f9139c905a8036153ea18570c1164e8b73c15630b4d020380c63cc1847e38a938085bd74338704266a6462163a176efc248c5ea6568056be253306ad8ba7d7d6144622002daa5034cca3af106a7f2b61a0e7b8804677adec1bfe84b09b910f96eca5f090cbc4e14139f12b29b7926225689acbbcd7e4cf2921219841c68d900397a100937687a9d779efa7301c4b1d1f74acfa820445c851bcb874c3c5b6e33297c2b424737b082e31034723b05c6182ee8154f5f13d69e67b25a58f8a543e19f7c279e99eda3c53854791c20a1ed0e95a8db87bca83aa6925658cf4035ca0879d477ab8b4c104e149b550b3209b5f36e149108a1918fc29de294fdb250fc66b691c30c9d6016b36a83e73f9a31df40744b39410201049642380ca752b64a2d536b6af19365b434b326cce1bda94719bae4d418b81cbb28921c8d02b4452556a156aacac7608eb97a2a56949059a5c232a561f842f40228b99be04e4a6a52718dc4ba9689b0020bf1bcb8bef492e4cb5232db76cf0a8602a85d8427b11ae9d75a2be6796ac7f8931f1f19668d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600"""), - xeh(""" -b51200c43aff424af193d24559a9be52ec5a72f4cf45eb15f8d4deef3c3d80bc9d0c433e595f4a3f796cfa7a4f23eb5f8bc60b3124be513d7e5bcbf4fe34b8a97fc1a434acd645e4306d3c2e07473e321434ce4358ae05e1efd9c6fc50b7e46cc228c782472b52493287046cf91e202fd997e67a75e50ca3843ac1790fe02d2c0ea71dcac6d65969022ad8f9d832e8a7f1b872b97be28ff9f4519e705adcd341fcb021cddab2de4ea394decb80ce66ebff3b3734482d1acbf57fe6d4f548e81e831ef1eb854a6e05e1e05863a4dbc9f69351c4b7ea3ad95bcf64521bfbf337bd9c590f0c5354638f42cfbfa2cc31a5312aa208e2056ff61204374aef66943e96e2b9585a3245ef2c7b909fc5ffaff94ce682ede6a377fd71746e5410b1e6471b8f075f848e427438ac2138f9e24b10b0a7cbea823d6ee74cddb33ea9e92f81d5dceef0700eee3ab0ff8d97cd3334523d1fb7ec8b3b594a5a0d6dabb2b003a9bf156668b8c4881c9b9d23987262957ad351b9e576ce59416b2936877823bcdeef302ee78a74e8f8fa7adeb7615dc43eec2fcb5e8f328f7a865bc036ba9ce0f8f35257a9f78969dca4efda0617403c8767b97df223a2d40bbcc378f41f7ec4fa0425c04f61b976c0822185319a924808191f6f719f006c856a4f35b97f7fe64639dd7ce5916ecc5dfdef2dacbd0c95589c51d28e93099201bffc80e146e4d5d8f6db0ca7d26814f682de0a5bd2511acda58dbec969df0cdf826b957c69f1cfe409280f63cdbe0794c7c5a0593cca1b0f85129940d553bbc2f29d09a3c6c364d396a39decb13d29e9c649eba58c67f080396dfbd21cc83bbbbcf68c87ce2819cd12b10d7511ff6f73cc58f16eb72e2d689fe9a0e24ab338b034a7d0368f4750c30b9793202180c499db4e92c34803f94d2f2c9bec1e8bd7830f16f77102781c4555f9908c4c41caf3d62b2912bce732a83dc92a70b21a3dc173ce1ef3aff1f69f415ad749affde5e97ddbf7ca79fe3f0411826505a718a237eb81af0d8c4f09548dd37830ef49c34449d29e191a4f0b98cee0dad5ceec6b87707f8cceb2b886b33f7008eaf93243ea0ac326399dce281dd275d2555861e6c5f04c7b480dd563e3684585c73e28fad560950dc111d9444bc7e2ba960cbfc914e81b7844af5c290adcdff7840bd545db2d9318f2fad141e531ee95638b507b94f7dc7c0056dc56c614b06cd3639d6edcd21567dd810c252214a7a9405aebe8a19a703a9aadf60aaa44821d2e54038f9dde2bfb580aefa1bc595619678b5a98942d8f6284fa54726fc22912efd39d58d71aa6e5671125f51a23290e3aae9f3a3edb2a37daf9aebf4b278e5c7bf70881f093b64209dbd943d76a60018445496725d40d6eb37f2ae27fd706569bd467364b7fe89a944cf08dd3091a914b0bf36e6204c798dc98ef3ef0e395bb2f855f2cd1f6be7554c9402ee190100048d69827dea7b33d5433bccf14a0f1d40866f35e2474bb9d374b526353f80711bc76d9b29ff0e2418686a40a3b19""") - ), - new DecapsulateTestCase( - xeh(""" -966853f02206fc71828a50115622706162598f8a876df00138caa8211c4d023a22127a0d611bb3800059eb2cb9a23b6f03510ec9f064067b39418c9d806a7de70b9e9b5acaca2b9a279797ca347c9035716ea92141340672d52b19689b7f025d9493323ba034511a4bbbc78ff0fc915baa9fe01078e0b511a4127a744a7fd04c4ae3d84212146e7c529ced97660aa49dc5b0a0d9560029c2a9eeb11f4943a5f80a4f2517cef8a91a3f9a0613f99558c43870e80b23d01fd720930f616943e15d6b8458a4e51fb5d784a0b35588d19eaf088dd04aa6564a038fc8219d81adb9091bda455058276655fc3d21902ad257426d25436ea6621709bc6647949123486b642a13f51b17f5545f61c66e095b2bd938d6825ef8427e0dc13bfe2ba0e61305b477a9aac566e86411d06b4304f6a3c4092a9a845a0700b722e1af1db3cecec69879fa29db9997db1836fd6766772b93a1d713c93667a6f2495425bebaa4a91c500151f2abb1d6443e1676f294b9cb261103ca3761da75dc718c5fda2a8203c4231356fa03be4016a9d6a24a2b04418c279a94911bce16507e450c3da684941a4a1ecc2fa8f39996c185af609e0867c24bb42cb428049497012180a942f81180c3a87480524b22b6a4dc5b6c5112c3289ebc819ab6ea7302e835dfebc525531b6bc80a84a196df896106d73b63020bbe794adfd08ad6cb0429dc3ac0f11bbd3c5d9dfb6c736386842303b15246d9a57df7d2971e169a2611bf179432a6462d5c9303fae68790a4769ab58c3cf670d6847240549ceb78432f63b3c4632d18f9a15f42532648794d056a138788eba86c1f71286f06979621a41d866765a5726f5ca0976268f505c92c01aea855a32f74c4f05454ed1b232803afaa672a0f841d0fb0824a512dd98c8adfd06269c92b71880aee691fc546b2e6c0c99ee18c41db8fd3aa3108a48c4f60b2698b501b8a39629cb1b3b027ec00c9f181bf38c25767419e6bfa4a2de982f5952396ba076b0b0b0e891fe041a5d7235f8ffa573595b02c550e2df02ff6c9a78707565cb5be1d5234a45b9a9d250679d5cadad2638f9706a8dc558029a9602c6638f366333ab989817ad64860151442acc4083d991867a65915a52b74409344498bca11433cbac3a82458c0ea647d8b9a7db51023a8b6b5e3356ffa3fd6d3ca7b0466518a4f8cc78f6dab6d33a6cc3cdb8aa1acafcff9cb22b3090561179f9aa777b3b6272c9f45f1cfb848b7840a020b51a7a017be69660997ccb96096cd1a92b55a4c5d1a831e2734b11ee46c16128123480b03e714cbbb632ce487e4a906a358a6f5bc14e4e92039575a43f7b96d46711aca37207439e3531a5d877ba1d60bfb8a0d58247727e7212db9410ad6ce66ec3def428d644b15a497bb81954a53bb95d2e51f2e7559c165c61713453959a51319bdc4138aba87149341cb4b114a22150133924fd5544749141a9abc5cc3336f89834119250a1a537718301fd25888e2b78efd3b0c6f42c9ef3524780049ea4609478333c5d386550b9ffad18f24520158330eaaa7110fe649e1aca827f16cac8b73105bbefe23c48752cc1ff65f4913616bab71458122e2dc0a24e54137c5737cfc0d9aa743cb8ccd08dca5a5e735178993710821454608015b34746800c7f8679d72b0c628757756a50a61186c553febf79c00430bd0709e3741886ee10667aa7f7e4c91d89820e66ca9bbfb029f5cba016b6240e2bfac3815afd613a13b04810a26559a60f6628308fc45238269c77428aa370418f11928d5b3c211cca7bba2de57898e132035a16a8ee780678b213917c725ba8dd1818428199c672b20ac05061a82246e3b55bfea529ba891da6320412108ef0ca184b44736dcb05990031f3496bfc96c50445040e27df4fa2c28205e1d9090034285912b199b909efd088cf4ea4241f5c3052050aff92be505a355b515e5d4ac55b859d5a3cb1a42564d398ef4cb91db1430a7da96f9e96cfa27cfb12664f9f694a36b211a7a79b46c70e0ea14219c119006bd287467c780b7e6e706dc30b230b20c3f8759f2b2326d8422b16c124ad4a8e031412efb450f881302448e26f383fe01d0b26770384638ee1aa51df773fce34a9dd00ca24c584f5512c108109bb9499922019381022a58c4494241b2b62da8ea0b784967d86c7d8fc5c6a8f6055865173854c38d6b407b3199cb44000aa90253d7790011a9d4551d66278d559808835208caf18cb31642b06164558b06fc615953bb1c5fec2600975dfab48e9123b0f3d8757f53555177766e819f9c5487c9700adfc917e5782c82c681ad8105d6427785c862201140c5919addec3f10574617201e4e35372d472f782388c707406d73b462f25e3ac846bf7274a721b1a05c36981093c3a853996552c85b4a90e0c796c790dd881fb255557e0731eaf8aa9747b0fbc64f2db3a7667a11b6c7718200367dd86f0690be472b5a2fa4b914f91622b78be310719ecb81d1eb8b6c76bc4df0116f84179654794b39832701911480601c77229bdb571c1110387a78d4510dc0705d66e189e1f80bf7e5c4952c083693c6908623be31b1d2c63eaec178c3523110ba13bdba64e6903df028a23167594a12b64de601c90b41231a29eb5c2ba2475b09091f8389363030ae56fc686d024a1f838a0fca5914941f72470ac5052b8863aee631a3206c9f79dc479c925d906c86d3e5797eb2ba45499690b3799ce39cc65a9887eb5785c1a6ed660502d85f5b169ace240aa6c492f9bba48c61c81f0722f8377263a33087814dd51070012a103a93160359c3c2a945933c081409cca0963e99883dd27cc2572683881c189861ab10e17e400b5da3d40983821b4c45aad97aadd35b6d7296cf2ba029981182f5a1b189668711d528de7c7b07a71a47056074066193936437016b5afa3fcb245c05764af1d77681325c0fc2bfd2a74f1490c704e216d18345a1e074dd440b730a0464db2bc5852caeec23c0bb0d754cadf8f050ada71d85061d18a6138d8b70f77aaf45aa25ba65c643f6103390168629bcaa10577070bad8119619320762486e9e340d43a04bbb408ab86801ef55647e43cf88a6c0772b8d5f274f1c12593b07bbad80ce3bf1903f24c6dc976cb8c08d2411bffb92221deacc5f2783b6d38078f51d42eb5ff1a6b78a5899f044ad4d57c582a72844a98e9d1bacd4c081abb44117d20a3fd3b18352a1f2943c29d0a4832a8eb4b22cf69030def765bc527aae51010c74cca53b8df382df9ec3e8d9d492fb165aa4df3ee6a45fc8a9953ae56be2651a7ba8719c565e02579ec454f32be2888fd5dd95ac20b8079a1567b365865f638c38f0852d2d712a708ffbd7d96f0df21071d8bfec74c2302ea4c5adba"""), - xeh(""" -ddf623ebb88ef5e69f87faaf620a10bed3440299b2c788981fd5f782671a5d2db99576baa8455f70250ded987e3e94d9822bad551c86346af95b86a4e0143da4a4ee58b66b289c37e1180b14a2594dbdb1fc468964375d466229c95182dd5d02b85b75b9eb413ba4e04a927798eaff56362d804fad7534ea1f2bfdb3c73cfe4b3c04406a425a3d94b71617100493f9ecfbfc9101a1c63b9d6cb991aee3e94983b4f162ce01a151658c49a465f01a5dd9b7a888e55480de880cefff5151086557c1665e818d9ca4e0b50859f8020a6023fb8039cdcfb1e8951c5ee63f2bb1be2076bd35462a7cd225c1c8b299ef2f394714aedb8e37c21a1ba751633fb94c745ef30f6a3a13d8023311a5602e5fe23ac7d652213a1d8ac19ea24022b2502f982f45fe0261679fea76d0ec9b988080e7dd018e7cce9c0ec7ca496daa1a11d86f9cfc9df15e2924b585fbcfeb5bc2ce2d66cd7cf2ab3aee35b26e1c17dfdb6da77cc464f454d91595fc82d53d7148333d9cf8d3bc7528108c635a960be9b5d243d4423f2692c41c441b4d0f52eb4a170707b8004fe323548bd9f4aa8aa608a5e2e39ac77495f62511223c9d5615ed888c73250a513e07f6c0867bcd84561ccfc2f7684c655a1104dd59347b6e0ae57496d45a93576b1b5e7469914eb924f5a391da1fea99f8f42343bc85957529b41bc8d12010ae1338b142fda8bcb0e6249fe47ec6217027f60b27a45b7da221038569f7ef6b8d5669e71af465f0c373695e2dc699697d07bab7a28ec7438b3ece4126f549dd3ebfc181ea6e13f31024a226d499b69f8f41f1b2c66643c0d8a3051e3ec97e52573aeead5c3fd2f762e0205af6418f2cc10086cb9aed95a413687f20683ce21b02c695dac6a079768982183beb0fbf92d65e28c6bb9ea294a2cab22497efb34a1bb8979fdb36fe968985b26f4567bbf103be28f02b1f709d3dcade83349be35d3771355f541b48745d86a3d04a9ff9e8e2742e4874861eae4efd2ffcd966855864cf212145365f003e0c95564e36476e69371ce9ac72056936ebddaa41c8ef74e341de5400988bfed7b06566980419b355d9088313d1610c4cc5872406dfd5bab0d2e6842fa7a6d9935b1b9bd4bc543689123a1cdde023a3606a79809909873175eed8580f4c5a987cda884551e90cea3ce850c689fff7fe7c43577a2b09ef4c864f83b1c52641b81625208fb47029138c6dac1af70c92a391dbb1e80996012151aee86bc7e4039941e3149d3ca3709858b18c77eeef230b5482d3399baaa7862197c0d82af8be727763583a3964dd5ca88a11804fcad1d9a6f86901ee78a7482f6bb47fa33aa21288bf27eb60d92e5e9d64bd5440dddf8b4ab9836a42e027a8d96e999661a888d08e816a5d217f4b94543868f56b3e5a9c348204277090fd4d3175d72f1ea2cb51693e6a29c808fb2d518f206a49198504d44b71285701d70ca36fa695023e6c1d79dcd761d1941996d7f7f099471b30e9f5448f7322b44977dcfcd7a56491144f57233f26e613""") - ), - new DecapsulateTestCase( - xeh(""" -89cbb4263b87fb3abd58177936748efc870d2fdc7f1ef00a58ba3a607b5ee49cb69de049b5d88f29503afb655ba6b844bd991ef17c13277594e3082c8c7342733447530617d6e9b5c2013fb33a4b7a20618e078ebc046e841547f6093746f8b79a987c31fc341172a1b6768ded603d11f52ed9a399c9b23aa984b0f3995545196e7e0080ad6c884a5cbb120cb1db4aa729b6ab1a0849fd24b8e178124a7921ea357944d35b778b823c10cf3da46562fabc7ca28b5cb8b6f295417cecbb6ba4885e08a9032460558a0364a1c3e2a749f2da4dd7eaa76347414fa868f7819bf5d91650969fec1a4c5b01c0df820bc63cb6d391086d49741c84bc28aaaae11a29141204b025a4bf867f259749ec99043c520c1ca46e73c2aa12f9a4a6f009f5a5557c60c1fccb148e0c8080e9aa685212ce6108689618e718278b48222bc59ed4a4b541a8c0e4fa8e383303d8677156607a3281b2b2f7979fe22ba62742c8c734d17b159ce0552e713f7eab01821a0b71aa6a418a4381f572abcbce44e586431cb45f0b933d1c75299c041fd50a97f030ade1ac46e07bafebb6a98c7414e13a99467adcba6390379206441e1027012d967eaf747ebe6428f7518236e34a8c37ca0e92648b10be47bbad8c28b49cd93340e8180064b2e0362439824e332c379c3003bcc69018329e4a657b75f2b1ccf26b24207a008d04dcaca70993332808014c355013d492a52a879f1bc784bc354c30b4523a590c652d4083b532c79e8c4a554f052cb3ab43abd734f8d920de834ced2692c8310c8ac229b04aa6b533b2c3abadaaaa65e3794bacccbdd39cb2b6d47ac7aaa266a2145d054fd30c9612c451bc0a5ec7a3b10dac389005b27b6b7f99e7766f813823b36b797cad73c71f83229ad6ab46e1224d80aa0bc42b2cd0b66a3c322f4a35a6544b3132c9aaaf2311480c86d2393ee2544a329192c1f3201e082fb94b5484907600516a05b7b9a8c26d3452bcf8b1cda0331adbf713ff023af0132010ec3f810c85492a7341c0294c81773469c2da3a74f0e9ab46d45028823e83aa016d57cece757dc7461a88b688a8e97ff756afdc291b8d755ca1536a355a571e721c042472f87b4b32a31423f2c7ef896658296f1b520cd515acd01ba6f7c1b34aeac799441ed54a6232172306c3c0b51220dff0391a1526cbeb64bca256f5919eb8b7655b142e36e95b8a479e7f596d481aaddfd653ad7922dc988333ca77bfa1bbd49966c25775211332a81194b452297cc2a8c8f7b9a2d013eda34d4f5bc7d9213d7cb721fe18b532757bad4229585527ff202240ea09eca0740656b189b82a68c75a82065b40e127842059453447f4b144f002a01d69c7f7f62c8104346067ca6b899bd04c075fec6a462a0735a54d36541f3b556e4f0189ca8c8b2a366799e1a72661851635250b4317f0da80ed014283f4132896974578b4b3f2b0870bab58c3acafe84737aaa8a614533b61b471e10cf02c87b88c940f5620c4e81542041f8971ae6880a71bac55064a4a91a2347e020be3e81158997e07d32d80d8b47fc52b19cb8e84e09f08d14da2459934bb5adcbc7b6ce833e0da95ccc2266343257e124e3861b8041288b148c1aa8c5c2689044d7cb15005ad5928aed39889c195c94ab0366f91910658388798b53c6028343664f5ec4601d4acef04d0b6f2460e75bbf32405a512ab2474b8da27acf70bbfadfcc21db84ea0b73b548066d4e4618a355f9c051b8b54977c3544bc7151e4ba1710e9a00e86a46d1149620c291d3673adc5101499301296cefdc04bfd5ba5d136ccc845b4e69c629d1086e94b622054c5fd662952345b48d988e4b7198f298ef6a925fa1a3f912ccad5b46eddc861e69130424a8d952110f5820c776a0af58c7aaf14922466ceca0aac3bf1261bc73df001bb7a081a9440c80453b8ea8b06e22689127cc9b2ea3d8e5c2bf8b25eef8841a527729dbca2ab815baff343aa74b4b07c06d5158e820c1fc440a86d44826c754a7e3b05d40c1cbf32206971c133c80f8f678d3c30ab99db0656f4ae9ca12ca4fa132265232bca7569c8624730b234065196d773a290a3633605166161d86bb169981c956394aa602d5ad37cc8d800a8770bafa1667b04ab37a668acc268394705e679594445bf0a7987b86cc8c8f48e180279a193a187025648b22f53d9ac5d8b8a760978181a9755e3195754530b907ce992b939fb3740e626ad5534256bb7dd538c6bd2296d5675567c2277552c52930401fa09b581b87c18c70ac8a4076c9ed8dc001478757f01ae8ad3adf49a6ab590a61fb2c5c8645076e78c58740aad2990cf3858e27ab151f797165550b1f4a0fa9b7d47a8c4dc47bb53b359742aa486ab776b3a7582459f229b969038379099c428c53c1486cb23911f50108032796e46ea04842b28a84373332287db410390563c2271be2ff14065f22b7ea32a284cc3d0654ec6ebcbd6412d2f5c29b3720182350b82b8b65fc57de3d90c0cb55455527a469097d913331a7a0cca8692200bb9711008fe5549c945b306fc48f58b8abd835dd339797b9c508bcc8e8d76a32d560cdbf7506b1c2d32fc35170347b71a3f456163bf3116794324a46651f359bfdb4a65cfb754ea47064a2336f85bb82f2947b9fa164e11a55ca10086ec5af899bf9f7a3c5130a9c4880412946ea6ac478258a67c58131df3b7338933b77c064bc9231a49330a1a7c85e864b17c56501697b3e22b1fc468261b8eb8f4b0c6703d6a1ab764496a6eb27f804631071962c4a8062203148cba5acf2226b74b66fb305ea88040f22779a5f3486574a7a2833cecc69af95c64348288bb1925abd5be25878d9585c540134eb2046d7bfc5fe16581677421c1b59f1c69a7717744ab87902480ad1f697cb7f66286c43b73702f42720840d598c3917f25da324e5aca224a9ccd9757e91b2dda2186d56ab2191b46c950c54e7c570a3a0d7805096a4718b57bcaaca5cd6fb1a6e1272ca1ac7fd9ea9cc72440400bb0a35abed71c3ff0b9855058891555c713783386bc591a9663e61bb9bf8055283c2488e198a6e991fcbaadc7885f25295b3d531920d880213b410c1763aee1beebe665abc1ab64c6ab3cdb95555004c40148a8530c22b06341c301f301970f51479199c785a4c616813e6e41bd8fe078a019a33af92df22b207b09972a60443a39bd11c5c38de24770f3a29588abca32283650a0587434b74bcbe6a7bd6d70bfc581848c9b2ecd6184a0623c75c1768e0f3948eae08ad7e7fdfa17684a3c63b6a10dbcfd6213163b473bc3d8caf0196f53711e7354f6151a7a2235bfca5f2c1b1d6ac7b65ca6741a60c9f1715c42a5a9e67b4e69e5f128372002a6c4f54ae5869500171e2541"""), - xeh(""" -04ca3f0c74332cf9356674d23c5a99177a03dadb1763b9cd6ab7804cd81cc84d079ef30cd3e536f0d6b119629f6c6afe1a982abf3f5738a1f686883766fd009b393c556f92e90cfe6ffa41439bffe299c162051231c6439d83d6b542204c532c4bb997247e18b85b467c3f19d6f583ecda477268ef89a9512daaa80533e19fa7fa5146a0f23d17df32afd12cbe17f93ce23d9f8d2b9a1f9b6a2f3b7413c0245df5d243b632e95d7f6d16d6324c594a989953ebd02e491e61c0b0e31f33659c57c3fbfbbce1d9fb20ad217d3236dd9418723a3799d7cd1bf119d2cf0dd2044ea2ef490a4e5d432e467cc5bf7a8340a2769184ea1782487f2fa91352b82a787955e35c156d5ab42d57aa1dcbc032634cf53dc4a64d080f057b023d453b34f179fd685d9fa6d57760d56e91b773295c10b90ddc4ff84d4228e55eb51654d8c0bffc2a4574d80a45d6d48ca8bf1825b46b16afe264dfff1d1c75c7ca83cc40df842f8c5db6aa3f92e74bd1dd5db25d8370ca1d25f5bed0c8db2223c75e43fd245be2088b3d9f25c8742f356a5abdd43328884835d135781db0393262d7e3fd859ca637ff54d833c03381d2e4b8ea9390d720b94f014f09ec691d07f77f2bb7eb792e45155548f4ac8da20540007c83ad66ccb403f9f93d7cab15a5203e4d0852c07f0c350f2da9f4477482777c14ff9f79db9d6e41a42c39631705c2307d26e54fab94aa002a5d1eb7376025133e737a93e88427fe3c3ac651cde934bd7a13f65a5af6de7e8d687c95207942af7b2c7d4a5dc1ecca1c61893f461f8744a76f45546a0ab023f7c07191be7ab9e3cb18b0e2ae1e3ab485966b2f93384ab93e331bfb7f7e65aeb7e0a6299f7b4ab81e25d95ed51502b9cb8d7ae752459d0164700cfc0f983d1a4f28b41b1e279dc71996b77b53f8e2bf67dfd7efa14886e43dc327793ce965018367973108056ced3ee94cd4aff4ee43d1b720ecf57097b0296e14433c2636c8d08c5fd37a1624d6b90309f93ef1d0b7de7e140694865b1f31c1cf4a972839a3e6462c053209498834cf5cf34d7b45b174ed86019371bbfd1a7415951d05fe7ab3bf59e25a67e5bcd72ec9206d6da4677fbbae005fa465fb0a55683b47d07bab6537c276477d0b660ab92a003d55bc8e645145e93ab0eef825475f7d53b173aa45fb6975cfe46c28c76fae8d0b70640467cef9256fb1755ae34c280f83c2898e908eb0d8680e25d982448f2e044543751daab8d7cdf2525c9d3f1fa96b7828d0ebb59785056c0b27b2f396e410df72291342e5bdf91f73b865a64a519aa0196997066e5cdc29cf2af335585fee2b6ba6eb3fc2bd57bd1cc4a2b27dd291a3f1296e7074b8f58204c0b62a4e016ebae22319f7ce4e147a4823bf70e5724c97d0b5441fca2e33831fec1cf2c34a95f2c6b78c6f714035b0f9d50e1fcb2549bb621de83581a498a79c1fe5d44288ff57c80245d5350e5af2b20d9983f4613ec85114c6c5afd3cc3272ef984ede02ba3fccf9315f8cb9f586ec036e68b8aa73""") - ) - }; - - static DecapsulateTestCase[] decap1024TestCases = new DecapsulateTestCase[] { - new DecapsulateTestCase( - xeh(""" -63d3868f4a29b1b1a87dfbb469d278ebbb928f612c1cfca80174a1d19396fe53cf33a8c1f1a88478c667e784567f43794aac9d135293bd754efd504f7b668f8a55bc51054573c95940a977a26255c0188456e2a1d110538939227711180dd36cad815221e47e8e8a48e61c7596b019d2b84e8995c3c7c9c690008207d78cb5640e428c36e92a67a6eab32e2164e35730eababa199743a4297f81b471961076474080ff6735c2e8cbd43138c3710e002829a7a5bc3efb9854c25d318657889940f58259b6466ec1b823a5d7aa835b76dd232f3ec9979005cc15ca84568785207963e476a93e585933129d25488c02d822093480e06b7459739fcecc65fea4b88ca58af5588ed577cbf15270003c0e02bb082dac7d84a19dc24137f7650e0a43c7ad064043e02fd73b1ac3460cba0b5948c0192d3851c36105144026d6a5a16ddb7fc963ca91800aee7b96ce04786780971359aa6862b6ecbabd74b5729510714867c77df98d3097b33c62b0dc7bccce1b10d0a518f1a2652c01609a3958ed95414c73b2a8b6307805504b6cbc5603649ca60e24672b4fe4bf88a3cf82909f13e2725094ce628ca2c0f48f91448a1db937653c4472d21107450926505dbb79742d38391d254703c2ba2279b522dc6f27523c8e6c193ab16d8c188dd5d452d5700310e22dac04bd3d98778923931758645098a71e4388cb5891b03b37f0ccb33fa75e3fac3627ec58310b4a6600c0b3c15bdc25c24ee245969264213c42efc96e09a9989515a632eb33e3692ca7fa67fb1319e7d82ba4708aaf611c6f4818a3798b7c27b828a57a4e2a49b8115be8002a420bc48d353a27411774341891021037d72a5940b8a41b5859aca1b142a80f26722d65588a1cc6e5a97be59cb116c6b8d4e88bd7d6061c6cb4f877cdba907abde86b5c2c73cd03382a50ac1debc15200a7a9d45b7f87ad046ba2d347a2ad899d51e73c48560f42b989d1d92ce9193ffb746a808145655028e392024673a8186c3e8bb63b30dcbf2302998591435bf534a19779683898a7a28d015b5aff84c229cc4f8784b198b25a47e0b1d2e3cc065b8c4a108c4bb64612da64db905e88b13e4f0b18f9f133452229bc02ad9049a8fe44b16581137684b3fd081dabdb389d663097f405eb2378112b2ef9751f8fa4ce6464220c1a8ebaf91ab5b3736cb465f9e4c9a4720ccf6338cca11d786725e7203770ba5e1111a84b75048c9399a94c014ffb8d2f5c516b4638a06067a5138265c98861ba50038804f7505b198c4a2775cdce2623100b8b92d489290b076c5a5566c62a969b4717124e8cd220ccd05d7977b2db0534a958183285cbcf1a6665cc2ce7d1193e16288ae06810640da7665cde163e20008659da76aae4c1ab787984704c6eb28d5b5078b971aebd77b20793117ca55671267c511480401a0a2285577ea36815d39a41d23537648f9eba50603a2360b2ce98952c34b2250dc876c5bbb7fed6708fa7cddcb15f732a77524001c972cb7533b9ab9c8f5a894d5a9c336b0c942249a39c039a59e789df2a6474610d9fc2bc4826cbf8812b90f5317359678ac78b6818b5b744b35773aedd3585aae724863818de706b05272459ca6ced128092d1b016fc76594461185c27a0433d2c7b36e807bec3fc527267a76d9a58edf3ccae8c251ba71517aac370902ec3f3600d5b995ca1b7b2a6ad833107b39ba6db71bf3d025a5fc81acfca9b465909740ba18df95a342a26f5437453fc0826209ce13c69b7b988f5d1a68fd484a2b1854a62ad09d96d6dd37795e29e83f9501aa21a89a31994b34a9131b65a2ab13d142c6099aff44b34d9a62905ea883102881f380c2bfb5e357040a29b7a2d1b039fe35aaad9936246cba4fc84af5066ae1c5cd7371bd1bb305d18873472b969e3727f17bb6feba5191680612822ccd96734b549f0c193c2fc0e496067ae05c75f9c39537533b07c297b463fc1e25fdec2526b30adf908bc8fe125092166939ba8257b33dee403b0d53f766b384a2a3503e9ca43f042d289bf2414b276657671a5c8c9f3a924c26286624f0e99cf413914cfeb4995994d082a6ea3020ca97a52ada836bcb28b53239724d712f690122591a7b1d7261ab798f644cf58076d75c39384f3433eb1b99e3b3a2d190492b5398bb9144f31c22cb34ef4a51478c635302525fc0abfd221ca8b3a6e224338bb0b9116ba54cd581cb7a3813c878d65317d8736881c8a6b6a7030441b44dc6663a6919c7a3574463b706105c332693d1918682d2a0f2e12b1a545a8aca6a38f0b63a216463099558d282dee3c33af3bc160d48b889a9d80e9cb6d83786dd826cf2c58c23c87f0279359026458040ae638c3eb5c5e0f7b6ff2e76ea598bac5143941d50d031a4906bcbc826a364d92641f68cd1b43973fe9b802f778963515cdd47eba329fe6b50c8bc5bf6d3aa02e69965693997afbae7e2c8f06b85435403c827a39d63c8cbc675d4fc31a5a699a0f2381918448a4471eb5aabb24c0685e6a1ce042553c360190ec470b44a7cebc153186be0d8c8996a9b3bf46383aac698758ca7c9b4a993b77e8397cd3a3bfd11b31b961c90875c900157f97e211ee6c853fea2dd83212c3f8861c0a98963820d6d73c7b3693b738519deca589639462db956bca22513b9cab7459a51296443076ff732e3eba57ca767d4374a8b2544c46c54c2f46cd7bc6461b8105f0d41ca4a532c6e4052629929c03bbd0b3c6b52c51cf3195eeea6aa9a55de0d9063bc57722a72409a59747965b4e6a5e14ec112a103bba204977d43822d20c92a2aa0f4882798216cd26a857c6a12bc78ffddab1d73a9b2f91ba4de83bfc54092d4359f03a4416230cd6616dcbd916b989856f3b0672b172e20732be0730d1a3a6a837c59a05b846ec1d600841594b306acc67cce4ab7b9715afe074a75738aed749c1494dd683ab6791522023acd8e5c403f77b23f128f16261a100497e0b1f906b7956c53c1f1a0d65d9422d7a3e234c252675446f085450446393c0c151e751ce25cc05b12a58c334ee1334d16b813c7689c6851b7662084ef05ae30bbebb5c2911859db6dc449165bf8b41626839cb37814768167ebd24300306af259941c7628997bc80156c6b87c758d6c40b55076b74b2b9942093dfc979ae59ca16a6ae33b523a7c687f3f22638f37c69c4946a26bdede88477c7b67538115cc890873ba223a953e1b79f7a902d0b20cda992a25b235f30164312111a01cc5d82d4a6e1c4961ad96bf48b797680bd0d04c83463bf92d86279c994c88b57f5a14c45645f28fc19ee835f0ba480bb04a17f5853c1e00c37f0857e88504166a230344bbd3180e6421432874fb6767d0a0c52c661bff33988d3e3132cb744df5b6c28ec4e7ba2b25c22a179914f043bb93536602d754c92cb6ebe42832f605d6dc99a8065cda1ecbdc589a93ed321c529c5f910ad86b9183b827e1e8005e0ac102a35b5abe533e31acf35e649f967c064963675421990082f4897971ee4204e3611bb3bca7af3a5507b239e9ccd49c5c4e09c14f3a3106bd961d9d649617212832c54f430140c8590dfb1bdd40785390384bc9640e2c8564c4a4f700ac1c6d1895fa40ca309aa5054b04934bfc190a45f78ac1a8811046710ded3246ef4032f3b73231913db1a58f45563e3a62413f6a0598264321b33460578f682ba40d29ce15697d6373bc6220c0931bcfe87326f019c7c746e0136a98a6bbe8c7caaea8a222e80915926c4fca60dad75a3f03a60375c09b5c5b120180b51f185157a345dbb91bb5aa6b704183ea0ac0f374a90c02206668224f975ed605ea1b01c55b9a2c159c2a096b3c4a98c2cb8b81682864188cceb3bafe825016381b8b2bb7df2ab4cf2a71f77347eb84314dda92f6d5a5c34d9cf3a123a16b892099c23dfdcb5b8e67be1087ec5b38b081289fa8c3d8d560a2d882f8b8501b4096d82602e7960a2c433abfe928e769b3e22965cf7f7350a1cb4543c52c8f3983dc84709c1909cb76084771c3a59867208c1bdf869b85548740c8b4390a2a7824d2b8a283606aa04a78b79acbeac33a2e4490a44b2995c70165aec4e37a79ee3224a8c3693056b67b1021c5c473e7fd31551a24a3383741d082366398b835389d4e4a34f7905a4c5808b27b44e86aaf02032ed07ab30452bead1907ac28a1a98a97683895ee583ec59316673213f9b1e5c2339678c0b6770459509ba5478830bba25239c311231b796c8225c9206facc138cbc2f58495f106b019041387982cbc656604e05c06e630b3d84aff82240b7a7cf6c078b9fa99fa426c197a5aaff94a93ebcb61de47f9c1c368b4f0104a0e8d4f20f98b38f6962ea4d6e053a96a8059c6e564a9ebc6cdc60c0de1d36c87ca4279906279ca2baf7abe635ebd3b63eee5bb0d48f6dae10796732acba3efdf731bf7c242aeeddf5eba5b131da90e36af23a3bce9c7aa93a"""), - xeh(""" -e7264e0af8a23070a8c6e9a34aee33c43edd08518807c80517f919f0b4594b220e17825d8fbec1e0d915a64ec7c248f2337184a2c13faf74b1f7d39034daada6422850ee9fe4e631ae7cf4921aa8d2304b85af8ecd09cc8dc87970181af62ff056a03a21dc1ddb2b4624c0f4abee83a4f040b98bcc1620a037486379c4e9555242583190bb6e952467cba25a05f9440b41d8dbfa34ae84687156d44e8a08cfa4449904fd04604481e5072942d85fe0f0ba90326c8a9fcb8dfefd1a391f80fb5dc1e6ac7eff332295558a0567dfd1218e421d7442853cb777f36bb112c854859711b988a9b58e07594e3b33484cec55c2ed39d54a762dd518137e91572d9265c71cd5a039e56a9702afa2f9059a655bae01ce9c0057c9ae8302dcef0ae6063f08757d30dc8d2b32e53e88b2e80739e8c715af7221fabf57df76b960b21db21c9d85db13f5336b0ad56b7e50b888f044823c5233759f0056775d8baf2efeef1d6028c6ef27964e01ae23290c1de232c564124544e9224bf4616e5d54af0e013f41b7b3986d1a8ac822d8a842e825b3f1bce18171626caff262275cc30bb5f18eddefab0cafde8ce6e7a0feace3d3cdb47757c756b15a2df7127e0d21d232082daec8fc33a1f0606c0d18d2767ad7890d196bf0735d97ed36c994d21fa28c3c3a79c10dfdc8b83d40b93023a8ec9e44b26ffe6a959ef6e1017f77bdfac76633d4d33f7d90be2c4476e0e80e76b66054f37a08a9b75fb11895c6c2c42da00947458b151ea2901d0e407429935854b2008e25427d924b4649cb2130a5b3edf43a0a0051b431ba6f8abb0951ceceeb1dde5a29058d85bb7e40db68846fd94aa38cda27979ab1298ec80b1118f2659c5ec9e8ab2cb538a64c0b695a6902b27c00ad1be5a200b0f9b26d6934a55ce6acb44cb3a97fd3f0a68261cfdb32fd986ebcb8ef537fc2b78477ea72fa2d3c5336a62db5876d3f0451866c27f1d460c5d9a473442f908176fb1162247ff5f116849ed6b7ef943197c1d0811386942f8d8b2e88f6c780aad8a648d6dc1533dabb0d05b333cd436f7b0711fb2c4f604052f0c9ecac0e0317c893d87922b23b84ecb074d1b7d12093c802b3666ee0a9a37b33f0cc033c4218fa2a8d735252f2f3869126c949d4af918f70a3be928ecb25bccdaeb29d87a5a8995f4d33510e133027188972998f0e9efa5fa311b4193d29e25a84e25fe203120d1dd9b83d1a3d70f8131db19ed072cd2c84b95b1808e325d74b675b2de30b54f0e739a54960bf32a523a2991ff55ec23e459aba6d3f84c1effd79ceb2f821d9330e4c6dd5be2bac39e8cedbfbd731294effbd53af271422397395806644a1f7086f2ed55032fbe7840139676b79dd84c3837a4dde7f5ec6926c9223283b48d26af7c6109cc290f8aa201e5e953334304e6c49b8fabd194e0151702e50381ff8bb8391e157f072b3c31ae01a5766f5f27dccfc293a8846e279fa43deb6937f14e3208b3111dfa7530f9b53e05ecf55d61bad2a2f5776edf33e511613d2441f19994930c00b4c992dd4245171566da2f536766ca4f2f9d6fcee7afb81197abfbda64e841a14370ee08ee2a60013ca6166f825efd339459f206f1e43e3dd85cdc5053a84a8aee21764c258404318baf94ff261545933a0f6db252e24104e11d7eac64d1c6e091f66366b2c3d671e28d7d6c6b39da5e94ad94e81cd0371c44e940169c2971b384c398786a8fc1fec41e212302b421acd0a6cadf9696937abfae7ca60ce0a09c3d487fbcd100b0b34e24eee164b484f7e665bb623bd3ae914966cb42ce2d176d30eeec62f717ab6af75557df9ec572b20c59b6bcc302af8dc828a3d9ee5613325044ce0f28b6748750aa4a25813f97c168efe87dcda7135019b5a5e399dfe8b176d811e771805aef02432bec8c5b45c956b27916ddf67cfda2733e87d2d5998cabc88e08b6dc8a843a125323f66c50af9801a6e43b1b959bd14bcb497e5f6712890358d1b60d660f62980b2f1b1d158db5ba0d3db1457efdfd7f45e7cc7a2ffc3b4a85518b9403adf9a901397e761af1b653f4b9405a2a2aa07fbc517a16155d9bead37d314f22720ae353f4a600ad50e1e3fd26d27235352314be1f54f97966d0dcdac7678632d8768c00dc80b54b1220ea459111e9612ba4b0d4c693e7e32192e3b339181bf0a9f9b54ddb274a21c9bfce46846fa3a84f46b""") - ), - new DecapsulateTestCase( - xeh(""" -1a320473966c4aa3087e3212af70b1b11ccd746a08a4c738e39b06e74685bbb4a9ca6a6e43c27cbc4bb3ef3ccb6eaa1ad714cad82a2d7adc59db821b32d747a9da182b7503f1706b6db1c2e518734f60b41d6cacd61c1451676a49d838f6e2c7e9f2ac376a312e7a7d6179a8f6b498d7f2198d2815e3517442bcc5778ba5c45642983430c5125b7760c5b523284358617f1cc5004bb237fb1ac7d938e210294033728fb69c98789c2c05cec3ea565b145f6eb2a662300a1ac877be0b73dbb01c7c0a2e3718aaf45a770f02c51d579c630332a87b6d79855651f695c77bb55676b953f749827b4f039593b04124282801bbdac214fa2d73a30e7513b919304f954349f1c9bec729970fa90538b2a7c9e85d510231b12bbf8965933ddacd221a1c7c635468180d752ca46f586c78a41c06d83f9dd553aadbcdf36b5733087891870b3b661b600458b7ca234ad604213165f265476c493c235a6d9410a43a641150a93788950e8905042840aa55d0ba5beb78e9f03cbe290875505806863ead88c660144317e1c40a2bb9c966a22e956e1eaa28e9bc10f0b7ca466828451266dc2510ae677cad9375d93261a68136a617bec3e3c2d160033e477d33223e5b0013d859b40d187d6dd50d1580632724ca3d3201dc1bc2b4f59cbe164668952e85f3152370018ccc0b686b052d2165752b40e9bc58ff6c6093a4257a824ce4338b2e366c60e313a683870739391caa98f623aebeec020a15c1f74a538f71634093a9af37ba7d9530ebc363296a60e4818e8d4a0d5fac200947842304bcc68b2eb4a797f14a9accc53375d9445625b49da5663d7659ea600f972766c9b839053a57ce30975a1b45f84b0433267d4ce2ad20e0adbdbb0aa37092e8c486f78a508882a1c7f34334785991827d4529c98c5c40e75883d35246fb5b8615567382574b1113cefdc8bf41a48c8d7585eec6bda67295d6c0ac5eb699f2f9bb9f6568aad661d638943e211106a42867b26cf0cbbc986c2437212c5f9b83b445bb21a7a056074d969182265a55d6179f50d327e6f39098cb304c6a02abbb046c9ca42420b2707056020a2c3fe973a974c1008d955941cbe2001937b7215b106396392724e305df7792834aae28003115208b2a853821ab3c4485ba7e8b2b0a715803ac25dfeb23c8ba6f46e093b3e30abdf20b4f31ca93ecacfc1509b1a9a3ef7c8dbb9aa3f9108b042b7f89232781198750e5597e78651a46217eb9b462696056262f3f4b4c7d36ba6b59b375bc8b64d8387301a00b36c2afc36c7f061b27482ddbeb55bebb3144c43a72042e3893895f823d90f3ac0c18504bb52dc2f574744a98c73183c01257b2746936f530a51ba57f6a487a007f86633796509f714420e143ca2178bb04173c941c768308804ce92b9ef05e89b36510ba2a8c8c7c8ad46fd3e614f0baaff2582d2821785814c2a7c40f6f224a08d4a732a306a53b2f03f556eb0b86f6f05c7a20b5ece842550521960301f0d3cf71460211635a5b2a699c2ac952e06fd017b811ea4a14841048c2637d3123fe3b6b67848b18ba49128a8f42db474ea455bd801603381a450504a137c82e71501cea1403a5a4ad22cb6d032c84b2c62f8552a3d02922d9491fe6673d121895b55e188219432c4a5f00922b57956bb292798c41eb2273a066a1ed06a25eb60540042fd201cdc3986345f80d28b99bc80bcdc2ea41d166a72abc9ed546207c17317858b79be46b33f7156bf511de1bc18cdc883095aa47d3cdbb3a582292b0b1c67cc722b7d3731a4f3bb63bb4009562925b4b2a68b3331328244879bd34c258d6b28e8e54a3e59c552be15e97454c083b846cf50581c373f7f73f3ea8158f92aee5bb43905c728125adba1c0d7d4110b6e04b0040a9ec365c9e8b74c4059e78950bacab2c69a5709b379323365311613dde867e6d44094961c876db6b021b203beca1cad38c2d565fea49bcf59697ffe180f3f6b6bce65ed6212c6cb60dcfa0a787280e7eec0e36e7733e246b6b1a99fe91a053338d43ec3b1808c9a782aa44bbbeecc84930e568d58705a560ba11901265885956086feab13795822c14754009b28806e5cfd6f223607525a6fc087ff4874cc6b995b9c7f2645578987b5b6c3fd485834287817dca09cb75a0c0e00fdcf30ea696835000919f0159cdc7aedd3148ccca020f181b2e3888cb6c3c8e271449bac0da2a2042e230895818cc5bc87e38471d3abc51f6c05fd80bcb43bf65d55a0c4c867ee28163618376fa5dada52c5f4306cdd99f0d4583c1399dcff8175f465a02d61dbb98680de662b49b762a8353ae15bc76bc097b789ab1057d2595363cc043e56c5b44562971c0097188a30e488433a07e7d934b89f4bd74b98822518d2e06932403bf81e97347c203e5413bdbaba6d4107e9ab4aeb1091d77a326d7ecbc09706a98499a70f28300a0c80c3aab68980c4d1cc662091bd370575e7986c38cccae743efaaa63eeb9965ae8605a799b447b76f91a15c8f16b6a52864431a19839543d86ab02c469ed7404d0eb365b7bb643153ee2737b9107a8362c4e3b05c0136c6d1510229497bef7819fc0a30030f899c0bcc6366090d4eab165258fd1447a3b12156bb6a4b3320914d797a2eba18bdc5615c208d1328808b667ec39a283dcc331e83b9d9302e3145fc003230c8a2365a5b3bb52104e698d41662318535dd9557df8907b6161a404e946a4b00a52829c8bf911d79385f254465bdcc77a31974fa6426554a12e399b8ac57e8c94163f3727472baebd458cece806446842c48659ac6c7262304fb693befd3b67b3237fc239a782c83afc72366cf9cea621989d801fa2477d564178d5c13197482f373a9e4ed9b2c276ba88e0348c1708c93a7c54d21bbc64496ac21969b975e5f56d033c287af7ac993cb87965818d26458844103957834760aec8c1572bcb0aaa740cd23b71a1a80396e45bd5a2bd704474f3d232041ab51404a768d404fb295a18275720b205b470778226abb26b775c972505eaa461fc52be230359e736cae2299cf47b1f1c0cbddc7472439ad8033608a8994825326b9297225c8fb4c0ab6a51c74ff2059d60aecac1cb8e9b5b0de1bbe00038bc883c25d23be3198c21648271cba8559c3a451624a403a6c390cac13412b2c788d7ab93de4790e8230bf7491e39019b1feba2a551629a5a012942912d2631b5f64e2965c73205bf25fc451d8836aa944063925a221784a9b5c99f13c381b5ad71c6581f28510ce93366534e8cd137faba6c53d92e25205c9cb43d7be5ca2940997ba3c903c04ea5ea4605503354d4bd63e3070a12840e2551f15c20f6769834761bbaf8a8b11ab94b69807a1ab2dcc396fccc22e3168e35c444efe876dc4b7d22683b6ae49467d88e08b795cd556b975155f4324dde94ac7a89ce5d802a91b4745c2b6a86cab67836030005c70944864c0835f8039c23d7a999d43bdbf7428bbc83e8e65c7b81639ad41bb1f357ce9080c3cb57319c1f37db4a3efc386a40cd60bb7a06ea70c38458bee0baa58a9209682e73fc2cb7a6aa55f863b49acd9cb18186b2b64434a5b7a38a2cab3b8baa47e6da377ffa1d6a432c847c4c0e757d0847933f5962722a92b06abd6ad28adb1736c0a96ac8130caa309f2e5893b0190bd67016f04b17f38218853300a05a00fc30330cd907fa08bed95646db857f4edbaae9847af03729205691eb715c2aacaaeed21419b187c7b99b1fd83ace009abd93586a413de2d9313a854142f076ff76a9661a96bd11c2e8986dd9a7b3d9e1076cc21c0787226a66087f13591c896da8e521f6117a9d7c5028692433e86959450868272445450aa42429478a4df821653067cf61638a1c676b776b9de76c50e99084e1d71202c8a563c9c4afb6bbf49c851bb939311b79a358a5118c945f0b9f54c7a5d0c504192a94e610153041a291f450bb44995050a964264a79818e6717c89b4046f16908d7254fa4f571548b01e9eb37759c7e4544c5e5f98ea014200fe291cf40bbd4c3a61213c2ce862ef907457db3b39f82c87690451c4a872846c86ca53681030ff839b24ea655b8a868fca9188cd2afc719b99fb3020e547ba9e1c35bbb7d153508889c7d33526dc071c4e89632fb5538adc58a6a304b17610558b302efe55a0c631e4760c1be689b843633aa31bba7d9c4144a14d7ea15e8895061c025bce225eae5570dc375b6c449672ba29c9c848ed16aff85785953cdf0891aa5756166db1effc3ac58c0969edb54428588055c9fce4b05c023bd386a9c19c33d33d59044f9893bb98f3a77b35ca101ff518e6eb4b056b816afb48b7b1f4f707d29344dc3cd4fc20ddee4ea9cb19d236d7d13a7846aa22c2872f73bdcef6fc0ae6bcb0db78f453b452335a651c8329fa3a35d69d60c44b61ecbb96360d235ddc4f334bfd91d6b7df1a4fed84c88c2933806f13fe06ef15aed96c9e1"""), - xeh(""" -c79699b8ef9b89c2e49b1453fe7ab6858b2da61696644d42d0cdc229fc9d8ed9f38043053da70a864565598b4d4a819187e5e5e78026cae4d4f3a1e7c0775e249b364683de669993e18a50cdfcffae79a31e1aa288a4b6f8827b28cbee6345db8e91d8201b19d1d80454574f170aaef523cdc9ff92b10bbe28fb8ab5e6e7db3e68041e5a9c2e47573ad50e15805d1564837819acc59de70cdc254a283670d1b6aaf2819b225d925449e373cda59460b7609ca12d6b22deba14849de7c6eefded5b1e1b208bf788e999e6307b6ada075c6c94b7deeeaaa423084a4e8359cbb5dd15cc17c50d2bc266da206e5325e6cbe0f6f60017342cf5c1f62536934aee341f184069608fb6f012c3d01056abb74f93eb014aab9ecb011a236d3c1a06280ac2e568d77492cf890846f5cc693a1195c99505ffd7ca8c0ef8440cec1cd3f98058e30295697aafd6dc09a5094670c5d289cee2ab00d0bca1be7c11d85d0017eabf6ebede1700a5b7fee55766785ba95a082a7335c44e313efdfa61e220a288820577b01194d7a581de47c8b238bf14e0eb6d3d19f8f6c5c4c0addac509c93f2873171397f2e9acf784ff75eb9f4004699bc0dd6a44157e48a8b4ba4a43beaf34be3b1702e43f454f6984de2e62493c92fada8649364e46587f0d9218e67382f07e0b332a2096ac209c41e0e7f11be7e7fcc10d11f4875e772a23d2fa91dc9adc605bf1b430e8ffb01172ee90ca1cc99ddb896dab2143b65041c7f4c3d59ccdcb15de31ca6c58f763525ea0406b1333cdf4242db129df0d2dff792d323963d185be073fe8278a8a41ec4e2b92e2ef9c7ec455d63d957af57362d717d4fddc772158117737e5592dbdb75f577cff804adf7e33a0363a505b4cc9839b7d5af46671203e894bee7ef6f49f4158f2b0dc740d008eba3ccffa57e2adf670e71d0391b237fb0385f2dbc6e23b5d425d446e71e1455a0d42071969c08d625f1ef2b448ccc9e7811a1e2a37f645bffbdbf924ce82cb529586f2e3cbc20f27b943b21eaa9cd18019308bb48bf77f0862b92ad3cb47e7391d57f5769b064d72b77cfe21c301aaf15939bf9700b39c9f9a4540dd7a98e99770c5035dec99463d716c8419fe26f6809029ad924f69283172e65e2fb6fa468e13050a0a28245d39c5fa5e4d8914772442f7efcede8155d7eda49d443e8bae0d324f845acc04bb20b462ea33e26e96d3d7c7d7639887d2209072fa81ef756f17af18a7c309a6d24d5448c9552da0bf8d753c7e5d00a4ccec78da0e98ff7545556d014083704ba4725e24810aa3fc407b7c69f8dd40ec0c992c1f56bc66acf78c1dc8444b93ce924bba5356127b4ac3dcbddac6e50962cd4815343b4c07c1894703459fa00b39f7ac8f2476a373910573490e0c27de4252f93a0397195311ca501de3fbf2e8dc54cab6259e1005024934c056b6a84d8e27bcafe8d645ad3a30866cd3f3f85b1685718006242d5ec834afd8a310f2a1451a0f453861575bd1148230320f80f9bf32be14a7e60bb0861840c9a578eb0b1ad3307b4f3ab6e9da924ccdfeb95ce969e6756de4f50a2ef107a19eed220de2a75bd0fc29f5af6b7d45ae9f2189c311bca2b3762b85d4e118662c6790d042ce4ba139e57f4527ef413bc2d369478a2bdfbd13678efd2ee9aac0c327f38dd7d7215378df392c55d003d29a33a3ba8f5dc802008cc15948e19e927c05ab1b877f2b8b7470832d832f3becf92969e5615c16ee4889b6eab1db8d979b5920d8510213dbb7fbef97113faf3f921d250c62a1fc09f331581e38f22bb4dc0721424806741cbb1184736280828474fe39a94c8545a63797a36eeccd6a285187665c06bb78294c40c33e23619c58b8894afa386e7608c374e0f47711c8ef2ae63c18a4974d3f1026d9d32847b9d0b99f00d56f4d249c661bef930d4989e16711c0fba50762b00699802a2a4477762deffd425c4cb737597e2f3c4c4ebf04d4e6225668a95d5180f7cc983e3aad5166a713460d6db2598a220e8f979c484415f5eae35447db6df2cfec6a1fc6c891a1a41a14e7f717b0550afdc112c78111f2116b9143100f4dc03e0e07f9f1bc14387c0873bfa3664f7dd3967c912a78552837a148c9951e8b5e082f194a640baf620da0a0c591df26397ce8f4dad2a421827f65ad7a674236ecde9638a6404e9b3337debd0fc92a1cb9b8d8a49a1d9357""") - ), - new DecapsulateTestCase( - xeh(""" -15fb53c5e0be680103b2fab23e8c1f8a7c9c06c089a1929eb4c8184030abfaea1be6ac4fd64b7b46a2ac0b84a86fac8b2da83535ec3e2b833433f047a5a62cb3f01a9467ca71907644d2832d628433f90b4d047aa6c1854eb61b085b09dfd6c2fb03b82c429f93949d55c993c94645bda692e67c2fde953960d0617ce613b0f51a0e300850bc1f233046898035a0e37b8f1064ed67caa3fa181999a9501c281b8386467835a0d3598cb98e361ac800ad4fa794943bfbaec427809739c5d21253ea721a8ad75db9f5a88baa356bfa5494081e3dd4bb5ce1444fb8258cc867eea28522da5acd855ba744572f28b0b3772a195836804a585351b1db059aa2463e21bc00ddbb177bd7848b7895727472e0730d52a058b3d9b2e8534e29062b84da503fc219729641e2a94890cbbdd8613b47c24795aa5012f813a8607b4ee3873a472167379c7feb14c661cbcf094a38473b624c9f3d1c13719b361cca2a788b914e71626032aacf02143376a331674c00121dd1e2cc27f6aa5ae7604fb224c55a56e6c6ac4e112259666a450728abea1c2ba0b215a5532407334fc823f2f538b19c41bdc769bb39016c6b80e979448c2303e5b369a0745cd2a52e09ea78a31656b5eb1b9911cdece131f012b2c1a4b58c7b5fd6935d3dd4537388aa6ffb2aec95046b93a42c98b1616c50ea3381d5a663c28c1ff5a6c539d762a2e069b79514dcdc897192b27b6704764c0e3272cfd76b06f18a52f10b843d2c245451155da8a2ae11bfa6595e686799c7a5a2e9710881008190974052d2be87f30cc7193f85364f3e7691ace93e546c4a5208bd0b18ac8da883fff99c555b4990822627904bbbe577766ba2b1865a787a2019bc7f70829a17ba325ac65b3b8ca922f2937e01179ac7184e596485fa326ff10320e68609c87560c58a281c7786a36105278789544ba33237e45b7f0f6c51d7aac94b4c4b189bcc6d01a74cb4841d1cc35475735d88a8ba650b8053693cf3680ac01a7a23024746ce36e7a86d49a9843bce16374e2fa845277207c6d949aa869ea7bc560da4872daa20e882330f6250a7cc9fe879a805974907b7bc3e0a06f1436370557a90842c0f6a5460917021e975ba21682339240db26c9a20b8b453487555aa2a1c5928b0304d4aa4d009cf290c006fdb5f64b94824ec1e2f51c3774656433b811cd33c54821800f81e5d48a5d43035d6dc36bf6466c231690fcb48d086aa5fcc69f5a70e5871b29c469e232478a684a09a4683f84933002b2196db7b37f08a2a82a494a15ab69ca901ea289985b500a40edb592628a16c4f827b3fe29a0f92718a8ac57195bf8bd5bedb9c9035c3a68300181d404be29427f02027506079fb9534e882715b388edcb05e5281674f161d739039232a57afc2ab8c3bcf03182463592ad5d0375e098c3c951e1e1284cf2b604475afc2a9af4da0ab3cc583b3991ebdb0babd1c92df9104b0c1a3abb8a95bd96a711c99b7b62ad244cb4fb243cf1c6714db4fb2a7c9a21784135a5e00b1b33857ca4a948bca6abbd212b1c06aad751b4f787b9a7169aeb8094b14f93869481c9e66a4c97c1a7fbc18fc0443679827320689b8901544eb2eca55c9450c1f5a4379907a66def76ec3f917ab7c39a791a44171a549f93ba9a5c8bbc19998bbc2bcd712b224cfe6eb3874130965972dd54ba21f5886be038f73698e3eb519578593a5444e918880c345be03e19f45b5028ce557f454b2aac808b1f98fcfb3c19c214a2db082c492ba02d9986a570b66c574d2081d80165c72f9053061c6454561d280558fa1bd7921b572c78773513560638691657b632b8110bc31a372a0ec6b3b8a3a9259c148450c8427a62fda54490ebb6acc42804721801bf83c7b656419f0801ae2a722db4037937d08064cdc3216e6216d402aaceca387bc56123954b8f724368ada1e7f01265d0682ffe847fc44565e5577125b815eca0c97f2555ff1520e2c4c5e6467ac09143bc797ac6326c68066035ca14663a335b5137544b876e9156942a3cbc9ca8734ce6f76b9f51b0a758b9b50877f925c4842828a7afa4219928173b92a3a7692477ba098c966a42001103b198b1a2094c42a9dd6cc1cf46c84945aa40bbe71e48a20913d0ea600a33164eeda16a811168fb123ef887496d20f0799b60055b072088af992055fd18766111d70a92dcaa1881c1b5d03807e4a948d0937b9ed4385a6479a23930878102c0c9a04cd1b51bac6a7a81cbae47b15f33a331a5303695a4ab229585d27b3a7105419952bde5c659e089d38789d3a82212e03cd0ed7a6efaa913362b55f386d2e4b8d2565a5781642d8e970f6c9ca25d2acdb8a3da7f493e37331d26432c530bb401a4ce65c463d24194b2b1d708ab2a34009cdb02b1a96a921f42c90488940e7033090bffb30b17b06bf5f3b7115a24baa94a1620434247ac6c9579f42294e1f50cbba44829640bb7713c8ee957174a85b295bb1e44943db036773d91b211537fd9584954726cb83c4498658d1d2a10d2b6b1593348423aad4f6bcf1807d6599a24c4544dff617a2710e119bc17785b0a8c57428ec993e5991f76a9503fc580e4c62a0b296dc52a1a2c83846b7673ca308fc0877d5f473012c5c50a67813424792171e87a7ca555c0bb380ac351baa05074abbecb602610f1c095a4d3aca0bfa11092bb8dac09918449149960dd7d0928dfb2fc23b7b50d85012416e2d237afd47348378c024ac5b14c9ab4c5507a1355685550de7dace35cbbf20a679c9b76fef5b795e0a14c803c36984669cc88acd814d9380646edb1cfee159040c8366e7396af8977673400f5ab2c21980e2a184a472563b1c32886c58a0d68a2d39275529c3fe1a744c877a0605c5da7556dedb89ae8731e729b6911a6194d71102fb42961bbbf770873784af83c596a66c2a94a7c851d9677c779a0ec527bd761dec9bc9d1b22645eab949e31f1968c649c811884a765ae00e98f3228fb03643f47890f78fa6f0369dc37c98b593934a3937084f0664b10c091e7a1315adf4b3f34b5b20123905009c6f24c7f0c601b8f53664b6bd6d48cb487b0d22d45e00f19409a894f3ea32b2b3ad0536ac05e420a74a710dc8375aa9610d2640fc7818ed599598f60e21113670b99cc0d96447f6069e0b193ae79277cb29883506180743678b3c9b53718974210f043140d74392d9be2c08bcf796b462211d60d618faa152e461cebc3aa675ea1260f4585e810cd4ea8415687d3b2405ca72a46129c95f9bafde87061158920c4b13a3c5300918c8de4b0f840410ee91077d611971a4094f3a236230337127c5a789209f36c39b05b6618512ea7c9549aa4552d30ebb5226bf06708b4621a5cc8f58b8153ddca32748682e36363df63bc1249ce1205484048fc8798ba7929fa627404f072a2e0c02abeb48ac9475dc1c087e427309c2b701668a291a54056047def6b10618a34c550235aa6d39f05af809174041b2140640c252b604e81e56f34f2f711ce6d64e56ca0fce0133244481058aa477628022f2c2eb6c544d1045dc61aabeb0aa42127bda479160f582cb075619f810ca2ab886319bf87b12ab710db03b4a1a170be0699f7f333a46b18d71e6832c356fcef57db82430b1bb745f2215fab44571d4b0d9d568fa5cccc2919b2ff6b8d9281e07759069b9a602ba7642f570b20b15a156a1c322447323a4e9fa1219b812b03a5b2e1abe8c5b7ac26a8589733a3fd33480e18ac200362e5a0dfadb1252c0b2d8c139e4532507329ebc3910f05b480ed196bf86166bbb2f4a96a91053b511c81ffb748f420a33a6cb771dd0129cdca037e4533624aa16fc8f18a9bccbb475ef0a8b978ac9090a4539ca1fe06c5501f2b34480b025732a90a01e60ba9dfeabb4e8c61ed5c4396423af0aa79b86157e687c313e5623e6137f67a25680eb6bb841b80530362bd1425ee986b18830509bae9bd9926f020cd02713c7a83e8ca4318a044691637d03386dd28c3ba081481ca7649939bab47668fcd4291a4885317025e5250894e968168447f9f5c73702a5837802cc4593ab99242a59a39fa14935eba3e781a7f2740fbfca7141c821c8921e7c52b4ebe24732118cf57590dc919d09ea18d2ca63a605495bc2a88f9922eb356fe0343e4ac2666c49adaeea898b1c023058bb5bc4437bb6b798f59ecc8b565f811c8ffaa13cf8a4af8374c3221c3e1ab89cd94393053acceb40fd6a2c1d2c4c6316993835b9ade3a4bb396a5040574005ae9f1619c2fa66ecb363be8a7fb424927f8033ef8b2397a691d2670195590e9299375ca9b5dcfacee6eabe078b28e7aa1fa314cf3c866667cfcbbb5b57f2db74fb19e5e0ab5683efda06a93631032380727b6a801b309e8e810537ee79b47e8007d436502f14e7a898d48484c4c8886f0310cba2c14612e7a22ec88bb5e9dcf865776c37cd5b1c6d1b18798be80b9562ba4752e1"""), - xeh(""" -6828da82ecdc732f9f2bfc44c3d6348f43edd227f8de2c883b9be7f10b00fd82d457c2cc8c8bb275ea493eb0bab179eed34c870bfed6feb8de10c782e20182e3525bc437fe2d042807afb232cb9d93671583781bb83caa6205c4b7d800edbac31fba90c06ed3cdaaad0a876ed6b0b36baa080cb98709e2bcbed2422dcaf3dd4c43661b71996e246ae507c6abec79be6cf0569ab80e959e4efa0f1fc70ee620595ca82c77d86f23f958f7696f3d02c98b4fefb8c0605211df49d87f03284ea641f66ee2463ca442872bebb75c69d3b86f5e0fdb4c87423464362daf809a818f4a6f123c852e37e5695113f200b3a5563863942f41225d11277c456d238815a6ac53b4d0af38d7ab3109991ae2e36fdf04abffdf4b79efa8b10c52029dea1ea3119681531451fad6a51eb06ec1d162cdc4e11d842e283a7bd4be32cb8e2b086d45484710ab0d23dad66816d914f1b69ba17f9fc8c607bf8807e17f615ccc449866103ffa2c72cbb7efd44df0d62d6c2d8d801fd75e3bbfb5ec7e28498719c28a86cf1d69275f08116125f1a72f5a6c19b38da8a3561f8cfe2d4efaccf39f77e9e7a3413d6a556386a5350f62ca7c33591f94c7853bd6d4e5256a13ccf4cecfd2ba450ec6c03d7a3a48305981634ffb33533fea02d8100eb1ad574628a56f986dbb5eb9c603e52d7327490212ee4d1632ed4f5f85969b53d3549c63d73eda74479a2e9c91239b30c50aba979fb2f6209c35973822982ab252acb8138a0e574a201249fe2e0987e37705d714fe74892dc690e4c2b8dc6493b55a75d100aaaa160ba1e5e71af05400c35a04f3b76d103ddfc79435ef7e83f2db5541ea16830d00554ea942dae48b9485182634312e70c4f0de7a9a9381652f3c6732034f768a07883ed3afb5bad9fcf9fc19963db92fe4c23772e5d6859deca5359964597ec9dbc06c0b988fba9c26d03457c89cf1418b5c2552e51fbe66a5d49a39d69279edbbc01c8dba250dd2218aa0bd60bdf9ae3c22e6e4cbc2b074818614be6a9e6acefde06b7a734efe82d061e479fab45d255381098d7672007d672df5a08b0d659544340de907aa63a803f188c8ecf09b27ac79dfb10ce0ddb09b71b14d839874cad31af07f6b13e4c6aef06f79359d131db5f56653fd135b0b553bc03cf9c8c24847239247c6b29f646e56c08fa9735c218c9f3ff895738555640518fe8f3a21f5752a04708ff5b157a5f725ad3c0786240b25d8e4033028349691cf58b5a17939560ea81e8d721940405d44f6e093c46946e496f2ddc4fd77c0e059138b5527ff2809b8f415f00049d07a24c97e4162c2023859d4b1dc18e45d8553a478dc9fb93427356bd77da7e641011863db2158a75ab3664496ccb0dbda445faffcca2d841438d6988ac1f636993d833cc8d44e7ce92108d7b904a59944ff47312f117850268bbe7676dedbc5bd17a8ff5040107ff13b61c5280be9d21b9d9c9ccdbbf3031327ed1d2a639c1fab9c3688eb514be79ede525d65408c913cf936d219f0b8d46d4861e109a80489a7de53de3b55809cf5e2ee1d0e4af20416c51d3d4d5f5a94e42279fb39af570bdf558527f9df41642cad191302d3c23d5f1a819996dbbae5a29e44dd9edb8a32f703d0868ab6a8d6714948b6ceeac635539ec9baae0b365698065c5091275002b43df42cb83447a7e26fe865834070be51b75e066b00524505b01b9005c346e662b874837f53b9996effacbc37ba75d271f3af3de97d0c1f6bacd3c8394c7fbd5218e637089175b74f493f7006229231c21688721a5254498fb616ec915d7b5f04ac18520dcd8f6a025c6564e6109fe19d0a746450454f76fe192e4e90aaeb38f070a65b8bce90c956ba2c007659e2d3d729ddaa117895c8e0fb8f757604bf39eeef565ef96ddf146a7a71f0004dcfa36a504701bd3d36d1444dd95848b7a2eb796dc311dce1b83ed731684d485e1d860ed2573509c15a71dd89bb0199f92c54636222ce4ad5c034806167d925b47625b00de711455c077abec03568acc201af169d36815c78c885604151973b305ae5a80f0cf5ad11834a48b8023ae6a4f0a60f087dc96fc6fb52167f251a3308f09ff1ab754eb87356ab68f6dc88603049479a5f2d535c10184924034b51e3824b71cda2373000ce341e0199781074a869953386a6d0ae36b6f692c38913ff9a69c061042612a80bbb4f9b4d39""") - ), - new DecapsulateTestCase( - xeh(""" -9a17699301bda8f100aeec84b6c2ca606648db979a4c7410f29c28d6c5ac1b2b86f6e8a1fe878a5a7014ebea98d9069e88705f9271422cd62f51579357f5035477ce73c2cb94d422b921b5efccc962a81f1ea74f57c8457023887b93c61d02178cb5833c2ab733b00604a84ee3a556032063685a710df1712b74aee69007f1bb23bc7b2930e7c54224b5a9f3b204c070a2fc82cc5bb16b9602c37a659dfbaa31976c44619fa2d8997a08176a4a383761c3295c114a2965b1b11ad32b4e20b32b4d39692772c173a1c0bc45a87a7a9e4cd86b537a226fb165bab458f5a46ab0aa050338a94df46d46a31e059382860bbac2ecaced47959b98213b2855553b351ae60f4a2653571772e0421cc9f78d34500cea44cbdd5934535678cf642594050babfcc176e30325a96cc0b360081bb9ce618f51d23eae86c8ff7a4bbc37cd98351530bbb8888264c46ccbe02b4a638ca614702238a240c85909ecdb3994d8b1b34ac30de4481c08944f454d95d761a8a05b024bc563f5afde38124916c5f4011a8fca0e44eb1292458f1c72bdbe15c2812b017611a09de22942112df5fa8b7b314c50aa4107828ec70380bff6750e5963581b9c26813ca81b5a4c7436b5b5962169ce0047bbe6c07f76a69cd4674721c2244a09cbac849c3dd730167233aefc6ee7b72b81896b56279d9b861a97939057cb4a2b6782ad485c597932963738abc022b5b2c463ea1dcbfa4edec34bd1595363a7800d6c32030ac6aae65ca671c896336f07666aa2f9617e924c08e93084586afe98b1ab184f951a1f485943262728e1b5c7c1209a02c247e24caf0f74445a22991fa1624010a12dab52ed45523d28c5d3902cd77b87402bb3e9d6b422ea41f033364d645cd6240e2813c8307347a0954bc3907c31770b9afb4e1d907bf9da59da9cce0e8a1396879e3706662022b67d489e7a501e46580cf7c4037573c1d597b32b92caf8b87106251e40e897c491072c358aa0723f942badd4920cb252042b330a9283b6f4859494a453d22c5d70f03d75b93495985c6aa0b0c7093b4b103d4efc4dc3d079d4d2b23ef44c5b002b41d80f0e45919c76939df63ada491ce4a4225ed87487d1931cc28b3b2658a6c46704aa327dc3870a7067c6114ba86c95ab42bab5690bbb171491136db0e50266595faf8a171fca4d9200052a668590021882904365e6195ad2bfdbc26dd518790ad447c44a28cc770094b738ac5b9bc7b0c64e4cca7161a99b2c26ab28535514a277c983c3833f726b9017e98a53a93e27652dbab4675e304bd2e798b50b27aafac6386bb70367b58e2853d71228b19b9b4a747d6c81041c16a5947a0bba44a26d761a2f87a66d4bc272ccc79f1b292827a7f1e93a7967b563f8437b859f911176849b33777a1921d73e5ca0914f137e2159cf4ce575464147f9dc66610abca6061127d126264326e4e404e5fb351caa251ec20808366ec9f447673a89d52b521b54a3d87184f4aca669f16c9e48be599060d5d82277163d6cda0a2d5805ef65043ae704d992839d28a1a49a675f843a2a063f05cb84ee234218cca032f32ea8e31b84d59506312aa668130579cda14cab0808406df9b5fd5c5679c92053d1769830c5a565b5db96522aa16f9edc1aa638073d7b875a4c5989d57be049a2c52a51406958bff911ae72b90e790f9b21ce15400ba4ab0fffd00cbcac8e4c6bba6543ab4da9488d6017d95abe7e477901ccc3ab935d67086c2ab8c576e1a1af4b9ceb31857302a91bbac2d02066681a5464eb0491b893f3611a94e8b2140ba407eb074164bacf341d4b375e143a57d149a424f00fbb5730646a6bcd1b07ab25993e29ac7f29a93c954b796830a4848b78c0c1a40a5b3bd3c329d33669c07b47154e2d2c129efa6d46600e3655438e98243b02a1ce85c73b05072652c9a68072c9b01088581fe919cbc55b859631a42b93410ea5493d8a1b1b36a1f200523bd2bb6d5993a6305610fa20de08b2302b9e64b5ccf76274bb20279a7b4a3e39a498c662cf6b095633ab7ca05977c36e55b9c20b226e5c648bddc3ca6934630b389815c38b89c8001933b4c715cab439c78fc55c81d003065054d5061d1d80afbe083ff9071ac28c47b1ea8ba836961c97ba6039325df1b79bd51b66790760e74b8315a75f0436c441361e37075a75830c1b0310e763205645d482c4870336de131a6cfcb2435119341cadb7e70eb3a7b7207237c654814c9a6e04c5955e5135c9d311786802df76bf33c37a04f84ec0f9311ac371664ca11dd56218f65240b97819165d90b113e955a19834a144e1ba40f97cf815b90b4cb7b06612168c6c46e11d4d79857f04cf00bc8e11b930588216e7ea3a5c99caae7b076a4680bd76aa3e1b806f428c8301641640b938743770b5c1ded957b8b1aae1fa28e6f19a3ac59f50a59a9a346766c9ae68a5c920b0377891511cc3b3fea22a0b7216ab1c1d8d97139d985f13345a073434150083cdea7977d9a5eae98314d6898fa14e89e4cc7d417d4b060baf854840e12505fca30bdc0d60a12fd30bacbd62287533aad397c208b0bbcd50b8f19431fe727460d754668309090cc81d8b7946333cb6fb890e152069624a923476369879f04771a0db28002ab860578fe351a2a1a2a11c198dab6b656a4580caa45e45d3987c4445f312c4d14c7f70505272364aa8341b1753af08040af6501f69e96d108a48ad245ba2663aa154339cb48d4bf55acfb9534ec42c06a11e4d4b3659f65ccda82661b1700090187cc57b17b50d66ebb7a44672191193dee20e9ce21bcb36be9d312941d622062c7906f5ccbeabc861d85ecff006300ca549043dfccc4400118a18b49eadb276ac45469ad69ce16c60bb717368d6c7b2f068bed1b2fa930552731444f08a239bb65f173b7e61730c68bf39656ce5f7425601519a2773aeaa3795d98db1146912683396b6c9232b498b9bcd3adc70f0935d71e56737a422b5792f75b12457f8817d926c44f8a8e2a34573ba7228204cd5ba24c7f245dfa0c1fc50be04e36f407043a4aa7a6f62b271ebc30bd76a80d242b934cb8448535ae51dd43b7614a736d72c14a577915f9c6b62cc10d0315442614a36f32d94077e65978430597a6694410888299939784237c991262d38a540a5e84f326906a7883a6ac3b05bd6051c5a11ae47809b30ac9a31226281a39f63be3876bbb6a896857a5177a94b8193acdb441125236c9cc291f2d7bea99025b282328c571e93f2bcc943b3d1f6ca4e3784f4314e570b48d483b6b20b9dc41280610aaa3a345e2645a3afe5b4f3b507b9c1a3502c84f581617f2449035ba524ca6a454c87c57652db9535b926557a19b157fb3f3896116ac1488a000f20c5251017c34416bf6d13c178204484c83da35817d0975183170a100c0b24404645d7b551ea24569c5d92235e6df27b105c065f66b23f4b119e5aaf6eb9ad73f3ac55826faa55021ee116d9ea096c350ed1c659751bac4a57c8c70126e736ba26f276b5391096541236b3360d9b76bea1b519d141f8fc9f4e8411d02702ff366aa7e1a5629295de395eb251c63e5170c1db22af621dadab30ffac21a9b400c8a7c30beb194f027858569029b19e43929901e18fc45c1d7dd6b464b64b14984f21286ca02124beec214d354ab820b4e4aa8a26a35fded6cf0d95a26f20123a909a7fa708c74580b7984ee082a05f8b481086b109d61b26fbc171844bc29c0ed42bbad4cc167935a9d1524a4e162a4d598a6e23ce1d404cc4a5b9b80481fa3b1e416027a590880b38517ee34e768c61c93cc170c4c8a8d3abf3e79ad2b53e710cc521027d2b8366ba7583e9744d68ebc33b4b45b8f04e44b98f890bbe3bbc0209d93a9d6140e6260cf28740fa35cd68513d4b024d5d5463d664b3d11a261d5bc5c1b8ac71f247eec4c66b72812c308b3b93a633b80e2ecc502813cfb4339c24ab91129c93b56b4d87a132d835986e994bf61432dfa98477dc70f7a66b53f88843e86ab729b5f79cca14e2263dfc868e2b81432bc47fd1aeac51c3a1d49549423d40a86210317e39d9ad15019e90050bcb882ef7dc09377a961465098d357061f8549ccbc7f951639e3a73b3e7a6db109ae463ca41038fa32418ae4777372121a5470622964f514c76c108535d7913fa16954d6668e2e01b16b492dce96a932532baf3a413a3c58967a46b80c5acf276e2a86cbf499009a5685f392dbaeb4621b66d9f1a631a60b59d03a8cef18f87c9c2cfe6290130198e67b8d095019b0484e0d274e488640db473d1402929cb501e9291cc428d37c0264d1c3edaf23921b66855f3b90ee38931192e0b30d24650e4c7c62b62b0bb885e610e1a9e542c7ef8f4f03f8ec111302c342652fbfc5c1267c0776f8f71fecf641804590c1fe43f2ff453bcb84289c9ed5bf4a40e4ce8d367598819be8ec4ed706df4d26819f69729c2acf274515c8e"""), - xeh(""" -6bc2d2cab5f1a65e54cef43e6e70d79e001ef07e360312b952de8f41e1ab8b58ca8926a0e5f037ff2c7fe755b47e46a7f28d2993d22f0e538415adf94d3dcbad32584fc0706fa28bafaf0f29ae6cdc97811406ca855f7ceee962c863e0b3cc1e107a75d213a550265c5ca4ddbc573e3ea0c7fbf5f7ad15a470b71452ff4af1c0fea5b9082a210988b7374b1541c6a36111884697b9780793b1fb755623a3e2119afe55d031d751b24a8c77f5fd15f7ebec6f9bdd4debf944930afe82e0afab87a9f7629bb146d6ae4135e1a3a280479347c409fc5ee0f811a267bd959a9b476e7ec49df9e616430451c56e220d49f4271b8e8c59ec7d640fa582683e42d7b07d5cac0aa26eb98c17e7c3c94a2627d1fb3b76748856cd1a5c5e1f6b0b1fbfb396c681e809a60090dabbf2021627ca06950216cb8c5d51e689ca76ef9734b23e3afab0069982b6e033b852e7494ce6bcf3812ba88a24edf15caa59b1d2ac146b18a32ef7ab377c12a44e0809790826672610d212f675a42df93e149a18f610ee55f68a08b350a79416174a488618daf2ec8c93f1f466627dfaf870c293e4a94e38d144cf38c2ae4949384c930dfdc17c9165d78144cab97daf68143f3c40e957220521dc28f8c82f3e14091cfb78a5ebc4c481dc2717616c36ae8acc74421ef4a9d88a4bcaf42882e39cff6a0eb52a9b6571b0c2c9ac18fbee2e9a8d7c17d2008912f89801f822c28d0751397e5283b02c70b33d736bc5ef99fa41348bcb68238b47d32a915f8e0999bf9c5e9afc497d7de87fc8f78ed60aca03d5831316aece8bb1bd5ea82ee05694497d90d337ec3142ee6614971f925156cbe074e416c9e052865910f03c9057c8fd6c8cf12c2f03560403d73e3e96e9e71994f03d0b8faeda1c866ccbc77feb536eea7103031b0037e9d0c4d6ebaa3db432fd1258fe7bae3c4ebb639ffc7b7a5660efeda0483ed89a256041cfbd8aae8add367160efd72a5332c8386725ed754fa6e2057ee5cc0b3d0f87961cc2e22065aa1cb22f72888ac5a509b9f302645bbfa64eaf2825c6c30f10059935bc7a41be3471c7e8dbe0922a1d6a8beb91b21e2181c9900c93caf5640d8a886312451b7c620b0516fef8088d9ab966559be634d965df184fc581062fcead1b9675a4c620ec5c66582ff023fdef67153de6124abff36ef884ff2abdac8c1b29425616b6ff8893c2ad7cde0f2a0140baaf912a1a158df9fcd45104766ca3faf2f22279e70505e6fedd1bcdf005d33d0ec89c8f82084335e6f69396d2ad1da31a577c64c3c60afd20022067af6007f7a35e8fb410cc0e1e906a9ef77034096e8a4f32544517f75e3833210cc8e5989f440fc1d92e2106244c00ae40e566080be0b2d14544a02e950ce73dd3653168575f8ab0f6931b58cdac707574a432bdf9d4c6bf2b61ae8ae4dc54f7e48cef7639b29ec5d918a06f468c8162cd7b33a627bcab108dc94a4976f1be7a9b376f8982de227462c47cf07f7070816be5256c59eb2b4ec6268fae1b50978722558abd117f5399b071a5f7f878530dc877394e9209c7e4f4c1b5c417c402ccf0ddb247b07e203f71e7a94b7d41ce97755b983fb376e0da89afb76b5df6f166a822b15c7e614afdd9c004f1883fdc8ca12c264892e1d82ae2e675e8d5c9ba11836ea336150a8b49f29b0b7d98122cb4fbf6594723de1f1cdcb4fe0a44976a5b40b087df6c30241ab081b1313c396bfaebe92021151f8e2ff5a917458afe820f9bd709b4c8510f3801e091942c626a802179d704bcd65c1ee123fbe72a68012dd5a98c0d97908b1484c56ff7bbebcfb6d2aa1426ed7c901d61f01926d348f20a35ea40a186a1a16cd872e9bb53f0fb9f44dc5f098503f9115dbad301363ed7d60efacbeb8ff02db264b9b23baf595f273360d093a36f0276154e88d413cc6cbc9cf64d133eb4cf6ed845827263cde49c116c6e6f4c25f8ce9a611ece5aca8bcc348d57a884ab926c96251e534a5313e52aa7b46d61b85d66c5edc065c7fc6a62909257fc8b6c0b171283e25212e3a96224d7da12ffc3bf303f16f5dd96101a7b816b260774a22c449e25cfc991ca4153a093058a64ac5d3fe2113646f598315f3e1e54bedd65680c6a2614e1c8af922519fac6bfc0e589bc28e3e70b53dab591e6a8942b2bf62bbb9a18c09b20cbfa4be5d7cb0f2fbd8fe948c3f2d9411845f61cf371""") - ), - new DecapsulateTestCase( - xeh(""" -8398ce8a287994fbb98d1515027626ad0bbc20d68e8954ac322789e8ea8264e6b060279df7eb3109f63d68d8126d336e1f0ca4dde11bdbf11378d0ac967063f8b91563ea8ec51346e3b21e886cab1d39b368f77cbcc021252299d8e5a571f74a9e2a173566194fd161bf1850b24925fa85058da68f4720626c3c96c729cbc7bc7798d3725e2411eab78843056904b6b760137e790b0595960915a4934351ae7d0b098dc9c603e1879efa3685480a1a3b3492c5bdef811bc55c28e0ec9ed2546512736552427944a1bbe21593e8b630d4dc25ca2b31310423d44223a751bc11d0b9d4f60cdda5477e6406d47b7dad2b9deca294786c41aa4047ae664c86a05128eb1916b6999c12499e3993f4c15200507b51f237703507db46a881f4630d079cbc95825f91a89579ba30004ca7478786d00126d22759487ffc192c2e77c81d40a05a33b613152a91b15f293027d8354df9754abe701c89c583858627a50c5913850288d07279865bfda15750ca82e7db9dd2ca535f882a75a6ad8c8a51d0232eda653e033ab3afc242c3e77940258b355554a1eb84657bba96ac255645373139b1c38b14ca3c773d90012503579a69c0e42c4b263c23d8dc6fcc09491ea83543028f757838fac956e3052659ec2f6c66380d9b51df627e7a80560a4728c4f583a4434eb8f38a258117f88639669ccc55a67e309c2e788319ac543966b77fb498c43ac6a2f7d02d3d88b4dc85a57aa17286947dc2d7a40088c26922cb3b0a53b02074621314f6c4c431dcc6af3549ec5158368155ffac9bc31941b8c60e2147a73f61183cb67fd144ba0090832958056a65c88eda50518a54ec637d8c934a2230a608e526b55b3b2c515fb4db3ceb528661e17b2c44c1b1e5a7763cbffcca5211321f4aa9252138cce7bbc1e234bb473a845775a2fee466195ccaf6e8c0c198c434a389cd8577cef4a800a984f6c002397c3c2706cfe96743520ab2a9257206f8c6cb387bc4b8ca913a992616296e502d4aeb8ac5b96ce5e283b6b98d289a2097b02007e17d10129a55dc0e41781b8cd292292c542a2b9e180a95aa5bbec8e6a4cda47ace3536e8b6c6ece51537551bb1d47f82f5c0962259fc4909cd85b2378a4d4416ba2536829db4c8e1f561677ab24f21b853c93bb6a54111583cc7a6721abb300964959ba667a45508b81b15b2f30e6dc2562d5131f7b7255d4cb769c47e05a9509bf2c3416212dd2a3cfa788b76f44692959019ac16f240892eda8807f93b86c6c92c2b595e55c349463db2bc453bb137d3dc94c8c15f54221df02b8dfae58e6d49b87e71cef6e48336686a1e68cd841a49ed107e91fa26e29488d98c281bf27997c173a6f9043c024676ea75965b7bf5ac221a291ddfdb2debc3b2694c36373235ab8a7e1979678c6cc9fe767b16491069f59f6cf54476770528f84222f223685307df567806c64f4d334abc3955b7772f7446059e316bdf6ccf69b6169a52724e05a050fc4c5bba010089a2e35b8313952f68a3197ff95556f29c85d5a397b54f05c9940cb655270121b3c48e6af77e7a321bc77a90286548268843942b5e80514a01dc12c1015a8e1abc83e684e97274d7866f513a12aeec103e59bf7a6b1bc49672fa5486d2eb436acc3a6d356a1b238fa3a5648dc9ca6821b902cc1167c52764426783b3a39fd5285fc142859637ece183da73c899b78b20485ee80a502c419a70db4547114ae71aa6cda695310459d67ba841963189d75d32f7a767a1603567534521cfd68511e23a1728c693ff316a1a21751162501bac2f6f97548e0c5eff67b2fcea8814b12c38d4680a54a1a28a64c159521ea08c901a0336355c8fd87b003c8e49068455c733975512e516b4a7c542f2592cdc7885e1299e1ce310eabc295dd0416e673e564c2f37ec9482f880d772643c779eeeeb0c8a06606c956b2556936c7ab0871416dfa9a9465279930621dfd4bdc4548f4715297ba30fe4d9a23f460fa4c00e61335ad50c86a9a707713b3ad32aa7f45a2a376184be72caf154b3ff93b873543c1c5c90fcf77f0be2b5f66b54ec6754c7a50ed0fbb99f720f36335e634857fc8c9e3b1cc8bfa5b53d371bd51c67ee564855c57b3a250022056868f2160cb65b758a9663438fccf2c39b866062f668d194a29dd1c809d4099084b07199a5cfc53573e6291a7978b848844c008f3fd45aae742d49f4af1229c49189bdfe177ee5c2c5315940f0024009eb4bafa5965a472d87767d4dbcbed6f6af41307cb48ba8f9828f229160df4581b59617d34203450b0426593947fc84d739784528081105c2c0fb9a7af8be6045c8606cb22d1324d5abbdb773c69f4bc88fa15e136509dbeb698ea0bdfed69f8ed67477e10244304f866a912d2c01bb4c428081aa46b862a6d420cbe7386596c34ec87f11084ed0493952a656939c5614e6afe7a022756621b77bc27648be0e86a763e36f8015b9e5e68684f73680773b5d5a9f37e90186fa13c11604e9f231ebe02a9c531370778579649f33c70e4be811ed668e62d28f67f7133f86695b790bfd2a39a0f22a49195ae4a40196a974a1b3424f4c574778b0036b21b356835eb2a142084aa2b736e4a810f08a2199c86c3e8a5ccf8386498592ab3570c6677ef089c0d05b06ccf4049314a8b29c9d9c18ce40933cb857941cb59abcb499ef53869f155bf2f4ae7e1c3e41889bb0682de1b4ba1ada65289669a55807d10672fce9142d1a8a7ca20c332b4064ca8a1fa5a8c4a898c76cb837b44013376fe1577b0104c95b3757c40a8c70d926216c4e9cf072ce4798b8d38776b3786f6136dec4b9c3a35ae088905df969ece6bd26572c91d78242060c54c9573a789d5110b25db9a5ad1474f2694b31553d3dc63d69913650287f6296854c46a10a54acf869757de3bb21342d26825a34704966e5239ad16b57458ad75881157988d5b0577d432b89ec573da15152e89afc7cb0c587a3db87bfe0db286c528c4b211382172064c94210f3b4c698124d860a13e12b87756bdd0002423649d7e7a1f57676c6e53c1ef6bb6152a932a110810ab80c2001aa53cab449a6d8b9a734e48de8f4777fb7c6f7408c2c8928f72482950b6497c2500af7568d514c4c34151f6749a0a6b79ddbc12e03c5563702ea733ea142035ab4149bb58ee56970378727e6215607a64fbbe7888323bb1e265dccea33d1f96b8e797532249092a202f3f9c9e7026483e78251cc57c1977c1e5a4ce4f9bb6eb4983823998101a58b0b785823b3352c6a5e2a8660fc143a5c2653e6a3920a8d75c29247a846f578abf56c2dae289e62d1a581dc561c946f00edc202222e0489b697c786ddd18f38a937c7f9b9cd0a3d85a9960ab2b470e5c57fa15991e74517fa9757a4a62a245392f3361f7601cf0040e391808235a593a88662895140e468e88ac4553908630564e61a89cfa2c2271a27c848a08b97adc0444a7b72bc0051695e197c91eb4af7ab869a4b9325ba36d3636645b23660b0a101eb0af171470dac7e4d72c53bf4070706c840f11d8514913873667f7ac5ffb6c011aa6dbc34c8bd22c597e0814feab71a99b2969b8679c4368282bd5a109781b02561b59164832b6096a13b204de5d8592b9045efa538072331f984b42f43a44d4ca6e2792bf26a4beb24089d046b13c25ec3612a73c19a8332a9fff70d5ff71851da2927a13942e8aac355582fa347920443f9a76c1d942d624c8b696bc3825675a6150cc56b0a3e5a19bd6782ce9781f4f2a4fe6b632de07047828713b23d98c91c99091571d90c3438c8b64592ffd747f29351d8ba91a2d6349da30247db82e2051cde3b0094c4aedf7556596968ae6acba7a790cba9c1de26689cbcaa4d61bec738a17f33b666764a2ffbafb488530f0c1b93617be1677a53cca42908c8c7a051ecb6a894273becd75313420b3d763a57ccb7cc73c8e94aca79ec03873c2ceea96b16d67c34c99f1f3642eb6948f4282e8d50ac30a10a47ab8859d54f86011a652913194c8b5e3139fb65039b4493a07a95b89177a4d1798d35cc1b10c9f0ea8b1afcb5ecb2841b143930c58ce8ac90b3b11f43837645a6b9f6c08b538a2b7b9272464b9707ab4faf9253012cbc985ac5594a7609a1b82c13bb886c564b577247f886382872d32102d0a31ed410942c5b1be910bc63b0212eb918eb0485e6734fc5f736aaf84467692534e0161c4258eeda24763894d0598795d48d99c56771139fcc016e516a29203774d038610bb5a57314a9ce0c677d192143d34c8b2148fc190f9514820bf8c8686a4413387cff6863fce50cc85cad03b350de7548972a4168f154337006e6873a14aabbe7a7f23ddbecee63d35e15fe156d0a508c235b058056ca100bdf10442a08ad6ba0238be525e8f98c76ffde6e11557835660824ccc66d3e78981182b43d78c40b828554c36d70b960a02c66490c15a4caa6a7d5f1e9ce34"""), - xeh(""" -7f0a07ea9e9359fa3b7aceb9b0ab5c41ccb755a103f6becbcb4d4a5a1b288add3448e1376688839a711536f82b6b1fd4b24294a074f0ffda82d2f8d4f7f5ef11068736efc9b9206c032b942de82f4abde3fcbce845ba7a32b4eb943b0f5051fe5cd99040ba07bf75fc6347968666c2afb8af6ffd55cecc84ec7858e5621d0db6918077aa12a475840c4258559ccfd14fd8afc65011c8862a50393755eb9ab5d297069627df3a673318b1582e2200b14fcd61b1ffc814080515c2b4fe189acf5d194b69a402b93963ef951d86f80897cf85c4e09e054620fc7e2581bc54949b58cdbcde49da1997cb4085d32609d71ca1a210f1e47c06d407539bc6fc2e58b6f42d96bdbb40e1a338299886e1eb57ada636334f8936b0432a6853df768f33b0ac4b4e393f3004aeeb993f9f9e230dcd99cd6d34f9131de3dff2789f2a1d55d57c2181ef8531d56201fdd1743abaef92ba6ccf2b38b66d330d5011ca0733ff24cd806d9ef90c60306234f34053ebc8bcb79e4878259871a0be9222bed289daa932556ba1b3cd11242f2e3ffe56b0223e8c62285dc000e206eab3c3a271b4638c4d3af6b738791bb1988b32e57af74f1009ef5352bd48419934c8ba18074c8de0e61695e2ce0d0ab6a0924e39d69e8ab93d135b5e142cd1593eaad8d130920e74fbb063a66c21999e421d74898f031d98e0947e4a91954e7b9fdea147e840a931fe0ab5e59324d18280df15e1736e03b0644cc0a84d87c52a348f5c82953a3c86a63d456f83a772b7f83fae2c2b21ab5a9fec90a3947616754028be3592cc094016e1cb6079910773d9ac5957c2c6fbb11693c9c3e49fad6d14718608287af29b743f68d5cd5080b838a50d292ff62fc67fa898a4cab37c547e25146ca7362a54c8ea1362c03992101da3e84f1b4839b092603a32e21f99239f98bf1d01cde96a550b70264eac372cb1b9dbb034a0dfa3737b82588fff82cb80bc6c8f38c15ce4d3dd7aca813f12996f903a0f4ce0023f33653a9328d5885ef2752c14e58dd8d6e95ee95e74edba1487bbb46974bccb3108223cb685b0b8518e8320b36f4664f2d45d6d0f9d4035de9ddcd09e567efa1d8905295130026bd2d05cc6b40615572428b4ee33a57a993faa3a0eebd0dfe8be4ec4672dc824a22bedd8a8f956f6dd3842e1e5143cd64dcaa728805ddbaa09632d8d2a1b4a8198da00d0e0fe275e83cf1d1127d249d4539b34a704a1ab78c4e2bf1dcd716ec5aaadedbdccde9c08ec394d17500a49d08772257fac9d354adf15e3b3f1a5623bbcc393c0d3769101c9e9345f2a15cb5d664fb22b12009d72f9ce0132d9b04a8b7fd1e7d87e42795521a9dc20f54ad9c7150a29df970717b0e37bd746163c5048ca029e2e9355923ec9ce36ee5a6d0c5bca5dcdd2e3050eaf2dc8f010bbf22fefa270427b090fcf3b4d3823c1c335c6a0794ab7119224a5f7b6cc7af188b97567d47969401f62eed6e1e4ffca075a7fdff17e12923a03d4f70165d9202d6e0816d97ed71943c54a0c5137a3f7e723b3fa178a7680845d56460cc9d05e87e92df648443a9430b91994d9cc55caf0fb56976bf75a1fbdf90a7e6655de4d2d37ae2b785ed31a1058c7f80fe89c042fb940c4c11e91d3eb18e0be27b8321c6c999953fbdd428f57b0f52b254def8e4620c07f5fffbb373eca6b57b6a8f6f6189bc6f9770ed1015ad089e9759c70163d1b9f2d4756c75f82693a13676e752db4b09d855b60e38337000c2d126665f794430fc261c0032886a4a76e6693f17cfdf2261a052f33aea417e7ef8a9675d851b8545d65d19f458623d7b94dd1e4a587b416385dd8b2b9528e0f827e66f4b5fc350fcf7366f17135321b6c998b203019b21e0e62e11851273441d4d6d0830a16cd0951b0d5b69adc27de6818229057f9f96c89911a64a9caa6b50ba5ae2265b8a6c63bd844dcba7977ea0bf1b8304c1412239056602e80889a26ab42f73d7444954b9ecbe9b329998bd15f8fbc4fca07ae0be6381c044dc30d7947da3efbc552189bca550580ce843f946f783e06169167c068f0b844a7c807e28ea93b31cc1056781bd076ab4496e4cfc1fa582016f080a80e86b8b7b4ed0b6e7f44ffcf9288ffbb75a0c7d719952c463c92fb19386649db9afd7855e9b18e235b46208fc3d39108fe6e33f0c4e446021a5ad0114a3ce7b1967c191f415e9f7db613a2d9""") - ), - new DecapsulateTestCase( - xeh(""" -d6424525c08d11e26c59b4cf74c0b97165a85cd9c4aab72ca566240c3a8d248012e8ca8c75927021936901682a9fb98124e6b00ad2aa6afc20c9d15501d127186042c6e0b13a073e7bd100a2882759e487f8b70dbb391711ac6ccd77b07ba72c9d8c1bde14ae224ac302aa4609d77bfb176062616ba7589eb597475f1732acb5a3392582af7064a6d23bc1820be326572b403573378586d4cae5db40c1d91285dc4a3a9ac43c07362761a5925043d7b63030113a9775513160042ff79fc3b1155b9c2df8c75338817d174774fce4cc0508958c49412675845ceab7fd9b0b9d1abd0a6057a1e5079b266162f281d9f399062b672c6754a21b79e5423069117fe785985ae7cd5eb43fc92268140747b20983b85205ae063cb9e18a59a2577b4c7e889b16d189894e5788d459070f498eab465d1250812a155d33dc4b97b45889c11a98e6183232993b56007aa6544d8527244ba9ab55c3d2b39a839a1fb6988244e6c96648a2872202c37a35f2204386ec414686a52c8a0b9f976237070ff4762c21875508384c626262c38aa248090a7d523e429c8ab417a3097b230990c9c3810b0ef01cc9c29d8549cd4dd3caab37c5ed650d41158e34443492082e91ca574e96938cd05e3fd1bcd6c57ceaa2b3b657cf35707cd12485b4605e06100a5de0b8d0abbb6fd74d2a93042f8c68f88502953a66d3d11ebd06bb981c1250d0abcb86824358c77fcb5f1df96b93c2c833d51aaa36cb9a5508eee473ac6b8768b49fec81690242006391a3ff6a7b968802275c6274fa965c3958c3d7b9009910a7785801988c5239882bb2c4a79a8db3d09d25208a9e585e379c108a925716ab107379a3fb8404ba1393213166e9a5c58a8a9a90a41f4b530e67604ee8f249e8448c63e52841a8b1d35c8b91d4344bb1262a8b2fc513b7b20636b46708bfb347394cb5a257ce738c72aa4c53726a3c931777d1a02e68b49d18b2a81c89206847342f22c1330b883fecc1f8db292ebb51cb021329c38520a0a232ac1dde91552a64752a2a4246e877ee9a7028737e9f2bce4c7bb37f4848a14a5885aacabea49e6146ad9bc255e02b8f38375800912b23b2659f94a3935307f9932c0d8b1a9360b133b6528ed8732e48b44af7733f1416c98202a6aa127e6c8b110c879ca17039746b3832c9b916aa99e668a9b7ce78bc44b8000213e2ac5ba752fe3704d94b61fb0985510200b4f1a4bdb9aaed09704c9cbec39b09d468c5eed73a4947a48d57519be1afd4aabaa406542ec819acebc4b7d9b8b99133a6337c48ca1d2e5520089512b8daadbc3ba0de3941d1fa0e261bcd6f3825f29166852227f2283666019596941be6a807e39cc1dc23a7d472b56c71a2791a316ada15753a102911a32d843c51a2c6a8b947f65152b2941a5794548acb64e30961faf40e89d5354e658b858b1263911092c43d6ee8230512423d69ba49d865a1228402ab954b839c45bca4d83162ca083e910c05e88247809bb7aa7055ec8b7d4f996cd9ac59e2f982efb015d822c388eb4acc13870b9527ac70794f109fe58caa71817469b97debf66996c551284aa6a2505500927b3ad2595ca152f19825a90733b4f838019a754873a8bc15b160c5621759344fd31f96b4b648622f709c6541c09a4c949a34f82530f65b39285ab721ae74d83eb8ca5d12a01aa734bad0b15c2633addf7a92dc598adb817575926f9d021e4130b246e202bef3460ac7454a54cf66110ea87734f0c90f45374872950a3ec7b436c60c06b9bd25fb44d1f96b0383bf7736cd2f21b5f2306fbe88718b26cf45b31b32e8059fd87f17e70ecc74222642a54cc99a849012ccd818bc8006218b3deb12bbc92038735288195c5789fc932e0174f35b1975b611cb56a1eac5638492caf349abba8c526fb7280ef556c3b69ae2d15e9e108613466de9fb45d620b676f81c79598954e11091d2904a63749eb414987a2a44997d5ab40e7fd98d4ca276f892bfe4a35509fca06364444c7770a0c13570826c7ceb3f65b6b77637bf0d28a3a227bce187810386b40c0418b2e27a3ab183e8a28db4ea7ff8278c64a3164fcbc7df682ed98862aa965ff5d107b230b73e745339122b99897264ba067c186bfb95be4ce1435ecb23c1cbc67c181066e3c408da9a2ce36a32f1bbd3aa9a1476a6b477cf20196569ca9cc4202176926f2e6b76cbf4b4abb4b183847e068c585d7c65ada8c29dec27a32642647901a23c635f6751ae131c34815b362ca00618554c4a9d028a6aeb81c0014815ebfc7f7f7001edeb5890995a25b89332c466c39888b9b542d741954a27b5dfc72a65a0cd453b8ca9529701d49d3cf21922a7a365fa3f73778161534274b3244a31a192c6075f2562f04c6c819111fb1a099c114e07e813a472a802a0af3167c7d1a68583c57305099cf4e9a0a5c724eb2a318ce0582078090f35b856f773194245e6678b9e77160201cdf2fa8d4456671fc9bcca217a2625784e4052e2f339c544a5e589b24faca6e3c332891b2bbb5849c6ab2805a4b8d01199feb49250bb8d30380ac3651c7a07525556c9d925001568a73b804f0d1b0e9b9ca8453c9303669618f398b95ac2e304432256811b910ae2570009c5199a110ad8424f135b93d99c375243c37fd36100ab89b88b1997d3ab9eba0bb6b33a8774b07c33a589c236be155b2df1420e75a0962315eca254a1fb01ed63102fd62f249c79dd051addd531597cac00757014e01366b771d9e06e825082a4a310f8f72b7cf644e56c59f751affa55985e42447adc6775187170aa0093ba12e65b1b3a2aa5b3739cf2b09c3677184d6302141b8eb4985fde8a993782c256f0ce35dc5f973cc7b4987b29a333e38ac3131b63638003c600b5077b6b5b7b9a246a02f466621ed67d4d419c65ac1144054120439424f58d9f776a9a3a2596d10de267b20848c6245350e68b593ec7b49c877e5614be71a624fde99c0423216302b3106a29c85698f1b3a96895aa97c021c9b539fa66230ba8c35b068c5b2565f974b112140db6588be7016bc1b2082be9a0f5394544141643b75270752bfc6920c288468330ca4b3171a715756dcb467ba635f7d17753e0c1d3778114227d8678cf63f580adf5407e9353cbc546068207f83b4f16ac1df250a1f8d499fcc9471de920faf2a23e27055fec098f791ca19b094fd7aef23201041378cb51501ad0691a39870dbc8d6c9ca2d6003de995b2cef5957745c6d04194d067a2c1140d7c6aa3e271b4b95ca49ecb9bb94254e562905a0623cd670befa9c5fb971e2a69151d209fe4494ea753a926b4524b05793fe5c1b55036a44061d8d1668bf0094cb14004d3759f510703bcb22d730091370e09c1022141c3b35035c2a08921e7a23c5899ece95136936b68e839b021a97499bd30dcbb1341141698594225cf52740ba1b68ea20768d7a8cf3af91f7c1b1a49817c04f475014b0b6ae38a81f03260ac672c6c5a7bd2b8f07b3e5243028a0c15aee58ade16c2ac72985de1525bb34f99090d67097c11f3303b219fa68453fcc03ec6c84aab448d7c308d76253fd5078764769fde087b6c955c1399b54ae068de44c0a282a7772154b50177b56c6a6c10a317d292bdfb4d447045072857a0a67dc5b87599424705ca9d6dc18c88134ea1c746ead5018d00bad1eca2b84217b53743fb377765b674d30aca06c79ae5c2bd0cc06e4f8249d8e5acd3177747d65a8692a3db8b1ea49504de28b67fa1ca3c3bb1b1365fbbdb3d40d666ad72b286b221ddcc505388819c993652c72397fb158a175906546e1c212609dc7b00150987b408b479bba5d290e0130d4c98c33f543da186bc514ab453f13404619e841c634b4c5486c2ab80258ade6007c8895554e819b5e894b1b6933692b3eef79571b8b38493c3cebb915c6aa35c5cc543547400b81b6058a6450ac5a7a81e8adb26f9a8367da7bf8cd2496031016ac92fa7853708463911780fc536cd54f498f807a5d029a24bac5c1b300351367e09d1ce68e6af97406c74f5c7ff796f4ecc10227bcb4bbc27044c9c1e7404bc15985cfc2dc166088119989ee32789bcb95fd0103ad969fa164bb5cca5cd5c3e6fb65f989a118d6a2bed2b59121b5000f64fa9fbc723a1969b93ccb83b661ab1b25913bf2f6cb604e0218cec9c8eb2aff60c948864288ab6bf1aa1bc65b7894e1357173ab691630821d63b75380958ca91cc6a9785556e4b63b5920c0e3876646e6833e542a250399b16814236524f31a470ef05cfd2dc0e01ab2b4d5a9b70c4cc5832b72a632e2733829c9753ae5a928106267097bef54b47918aabfcf91c1a6b9ef3f1154f8a7f309babe4a75743409f7b155e6557807d6b428f720e0bf260c6bf3de22d70d55541a6240ba4023d046d7bf1c7158a3cbfb7b8bd2a552495311db5917a2234587c5969cc1ed10d51b0dcf8b3017143ebf31687930f3e2c610a4850"""), - xeh(""" -645008486a43ea6c461d7f98a471fd6227b43772ee680a0a0becaf2d2115b94b33ad85482d86bd3b2217f17b94bf38f229f4ebb984609a000a02eac5b2220aeffbb7c771672db10fb779f1823246961702d4e314c98f98b38055ca88090b51deeac33d4c899d57499863f9b1e02dfdc96750f923ce68fccdb9bc01631b3a5444fe45d6b6d347b4097f657a2e3bb7fbf48e9fa687291da77da8998d292776409912d8e44c6623a50be758c677404aabed063de84b4f96e641690dcc9184e6d1e13372eceea41873039bc8b7cc2aaf6eb00908967f8d6ed8a1e4aa087f3a81af329ced0eb5dbf8191994fcde14636c307992bc859cbef1f1807b8c1df4422f0a1863c4b47715149f466fecf32d4060c648d5bf90d3806e253df269d4c19be5e3b3455a7162c197f1ba307fa2969f5797a04ebe6412dec4ebaa507542f86eb2d28fc704bf5ac58965cfad57ac8f019de27f82c79cc2c232f0b3389917c3777722ddfa6801c14b3240e73c24a68a1d22e374241ecb8ebabde5c3c638f678227d34870facacd1696d011d2e387ee8fbf61f121a7cbebada4138c48309d8f0a9b0f5e0b71aba21c538e91f3f0dcb49ad2747ce9f9a99cd810d3a264e468082c000d4d3cf1136fe900e73eec013323ea8998fbef7d5ad3f62286571bc24f9b45f4c07a19037038045b5de6e69002f3c6361bf34fcde13ab18937ee0a7827ad14b705d6c6f4d2bd0a3aba60749f0f9212e64717d2a03cd0b1bc621202d91e46e44afc5db28559e2e37f13be40681694d5b431ec4430f4f737734c36d683f22b12240e727eae9f70955cb958b2dfb9e1b702040c1af17dd23db44bf71ea0f1a52313b3cc1c75036f668b7c19d7a9678fad74758b50942e85735b218491b85b1ed4d142d1a2081557f18753d6fb0d1807324fb4c7125b46b9bdaaeb414e302b347251a35fa6236e15fe1996cfc9827afc1d7a153c1f8a3f9a0ed306e5f3b2d0909f7316980572ca4cd2f304150c4150b5b14de007e9ec913a0ceb71c4dfe8d91d3fb211bce71aa501d469ef70649013650da608373f19753692418256879e6063c40a0d16139574ea818d49ae4d1174596bd33d71fb052fa08ce51483169974f8c298e5ec9fe87042927e899f22ce51ac22bded7a685dc8a1181a4f7b4a43c1df697577d73736306596ad7d475b484358251718dca8f3b4fb264ef960f14f0c25a2129c40aaa54bfe51018ba6df19024b7642641129b6b6d0486f8722803045fcf2447c0852e4476d93d3301da71b5f1ab1bb8b7e613d50e081198249bba6d8cc30cb70991163d3d4870285f949fbaa6152e356c0acf3212fce4d8524b97b1638938cc9cc63780b63766245402ba09f8f0fba311016dab14375d023178b42a7b59e72d7141a89c98f37cfb1e4868550d16c8c8fb3351ff6c12e5fcd8364330b8e0f049d8990bf2df53dc3b08d3db78f8d2885004a5e05a7ce25dd34ada644669937ce7b426a5f432c95fda3b004d453ea51806add6267f9cd1c1a645282dc5a069b9721166962004ada462a588c84f54d6bde421ed35d81b0ed6b864a9442876b5a71f4cb12d2c3af3e5523e08e1b2ac8a1bfd9174a708f106106384fd644beb561d6e4a544e14cec57c897af99ba7925c25bb256a092314c5081c156154d3a7bf4bf8209246919cbe90ca4471cd65b93d4ae28595aab093c788d4feac9844287dd1307775ed3a86a27febcdbde0581a4a90b53ac8f9d6e680727973b3ae8a2b3bfe261536a878c7ed9922a3daba30c826c6e2790c88c07dc7bc4e9e716bfe509c4b8b98330b9ad6952d542b8a512f7eeb6dfba79237262babd8226c64e76c8ae04783bc4b494ec5c8f82b30e2ca87147fa4c2b32beb2214d80de46add116748027533cc7fa4ad0448c3b482c80807514a4b1f9252798dc53b83fef7cf9561532435ae15dc19abc799f43729ac98a11c786556e3bfede9220a4966356815bb16f887bd462bab989527b02beb9f9e8a9fc548eb9022d187b66835df6b22edc93829306ff84977303505c3c13336c8d558651a5b2bd0e1653effff06bf7bfdf78f9abdecc6c66c232fb9ab6e8b7a89bfbfe55795c27fa596866d308ada3856adf93a9661cbdf61486e9c2b255e689de3cd28f327f059c353b30441197ed3f04bacb6a27710c231e2cd0e159642518a5a50df24f1191faa68c570abfa808616911e0058f7ac1d""") - ), - new DecapsulateTestCase( - xeh(""" -19a1c59df3428e937d18d8571a5b12540a27073275dc343dd0c862a9e150f57b768a4059a3441716d0401e6a92499948ca2b84d2fc687b08a929476fd3905fb1a207dd357275b03307a2295ee619ed04acde08722da7a4dc86be267400b5f7103b6a613a067dfc406b311b42dd699acb022decdb3b6d37793275c945dac6387323d0b6a3d06044969770b2a7ab47165c983267f5d515d3758f6097a2e6a8405a4222b2f92cef4b0d28316c69ac4f4e275812e6caa1284dbfa490a1ba0bdd1b2b9cf9aa8641a34de7816690b3d4317d5c899ea95b61570139bddc86eb83863c0a88e59b3fcce28084c3b8decb9050a657c7e7637acb49d9ecb7542224f82a9938880744652f361a9b39ecc5bffa6193e79db43ab89b681a10d69e1ab26bf2ca7e665193da9c6a6a558654314f7bb8c8a555b133235f50965026c080725391c2e75870fb3ad5668e2274690b076cce04a657eb7bd763c40cc418dab5c278032a7d1225eee448fbb849e847096a58064cfab6f3830f7f286b2fcb0e82902a9a0b052fd49afd3134557510686123e7c5ac88605910b94131a61c39008c3181cecfb2679a187ae809c03f9a02c856709a24a4355c7f0dfc3465401c15332fa0a7073c05bc4a23b7666b83881556445caae0d2be25672fb6134385c41d4e187630b67a96e35658760d261a4ea71bb5485b4fdcf74c0e739258441f2f50a08762b13d965f4fd12252123901e4cbde1a2ad47601b1a685eed55efbc78bac0b06bf803e6dd585f11259ab3b4c17286c1502c47419979b37852ec2661cd827dc97629b4104a59ac162e24f0e4c1dda2923af8c624c0653e479a46fa80418bbb9f1f29ab0faa0135c57cbdc09e4955a4df04f540845012056951315c3854a16ba69ba092cd2b6016b74a3dfaa94d43767ef2050166b146ab1bf48d0a61bf39ace177d1f061732fc4341637f60317a0a736fff931618a0733ec8115a3b5c0bea4b8f8b47906988543164bf0a1135901a057691829234db396b2d543b78fb5eed054791d29d0514170fbb9acad0670a058dcf264c0525c13f883bc69960ccc6888a2a7796753297e33799ca223f54400634b8eabac16c70b9757b91a03046378a6295203af5d787fda68323b11311bb8720ea21130b9684a0510973bf27304dbb86818b3c8952865f34d6288f64b2525358c77a503f95b2dd599d86c02794d1cd5d40285e587ee4a7880ed515c031a6296b7d3cb92cf0a1519fc14657f7c1290bc2e7148502822fed447cb1078b40118f257554ff4304da892bda891baca5a47536796bc55856c48982e7b02a719837ea43242ac246f04d69e06692565f97596d35ca49633abc0cd941ce84aae080934d671760b41d7c93972a9854e81372c4c979e2f4332a19b19606743c61a5ca456cb4baae8f2bbd35161f44ca4ea58c5c3d7cc395933e6584582a8994d6470848a9c127bb35ba3323053678f7909a95ac06e87c52cfdb84c8ec97b244a51f47c3255bc80469c85660510c2093c15bb138e0ba93f3a816d22ec6680a61257ebffc8a5f1a7b78e36c8ad46d34708a4ac730ba61878a357fc0079eca75c0e1f225d878b852a3a0e3cc06f0b7c5b553547b133ec5f1a26cb85203a94e53a24b91b89fb3027da3a7788eb0751e45be61ab03c234117e20c30bd3b064aa6134b59c2d6cb6d347640d715c92056e901984ead919e93a3630700e60830583191449734305293cdab0b69c266eb0b9b6c742a342472335b29adba00225678dbb6a3383c57be74c2c0832c003f3125785b7720c3ecd804aea15173b19b9825b5d7ec6a63d4447398549639a86ab241d1d400a608730d771abeba84d6a8894440585cf16a02e856ef13a8197b343922b40986b9f3a2873ff29816a682ed6e9753f392c3ffba79a116382197d71e39ec79c7aa9da19cba825f527c9eef3272c0129b9f281a0c574aac0b938776e6adb3bdd88ab3fb1a4f0913a2e4c53e76a7c03294b97b1bcc4276254c5ba27c7acd53c212a118801450fcd160e11c41364a5803bdcb277452a5c5193d0114f0e9247fc3abaa98acd43c9784a7c5eb3a508162c602091271926a52b01951dc4a5862767c863c7af6397c5a2b8953b4aead8480d520f111b85938b4de50a6a5724354844b3ffc12b2b420287a6798220905b42bbf7fa109a95c24b6a71902c2e2d806d1d2baeb0c2068ef710a989211b64636cf58bcf43a3eac1119f809a26f02a216341f4b60b3c7516a1cc40572c6855bc29d006737ce64739268d0bc59718b9aa34a82fc9834fb05b27593a708ac4756c28342a148b2173b4cd023fad458b0ec6807f421401991dae15cbd8b01181294f95e0a64446710c41671ae3b298202fc44045541ba5be8516c8e52e743c503c9cbf69d6007fe79c61255872d312e1b9843300a6b436a96403bc33f6577bd4ade56bba41ebc964028ae6684c65e0c348c7ac445bc6b3021529676d5c40a3255930f2118d2343a866a6c5f11c3a1c85a790f25c5096c816166d2d08cacb3bc503d83ca9d1ced3aa0372a3235e06ce21f3a8ce609621c954bc383c97b49f23e2329ce9b092037e661b361f9bb13a285cd77c02cbb6cba1e37cae8a6264448e07401ada6896baa3189a527071e52dca12211135b6c360158fc60ec2b692c119042565172ae9c7c5e15e1b1a0952e772d61b57e66680b8359cd4726421930562562913c0c30ee486b023c8e36926bbb00f1fcb4e89600bf7d79905794487ca1dc5d69264fc56872588faa81a755b3227d2532ef54f8b0a91b8a6ae66cb55d34197b7c71e69c7bd39f8276e35117e96775b6c6501034f81267222f54a3f7b94e4a7a3e3ca04948b4f17300b92330d43a41b3de69702c2bfb9272eff89868551beebe890cd002a86d8566ae5cf47a4ceea731ec574684533796162ae9f206dad42272e8a7f7e7c97f93334cc833396324a8654480e5193a8e0918b48015de487df1590b0f7627cea9fab8c3bc1cc31c52a7ae3e7173a7a8c420c7090cb0cfbb0b419d53af678b5db9244dc8b8645f6c093f1b14ba5b65e4c0b8a875d4d86266aba296e648670867b7af5ab2392c4193b9f83052425362c5ce4a45dfc3e5d9960ad3b392ef6348fc7a164b494f75476b78c3f2557cb898a70af6280b7053823727e18a7130fc777b7e81cb8952f23b9b27dc02447bab51dbb9c0dea135db473906987c5ba76b0424848bca4e09864db2cad5e97adbd00629219abf8978dacfb8370f2ac6057477cc7829b6c452d242299c0b314855c5a5c61ee4557555795286c904d08aebfd17edd57195f831321ea02d68493cc994dc8370e219152f5245560875a88c3b919f9ca9a745ee8b942e1316a177a9471cc84984c31b59b8190a9207e4ac1ba253093e7585621878a3004d21851f349805bd70573580f9a98c97d6a2e790c0305316040f64533a6bfdce19d9ab8658ed26dc39837fddc2be9c66012eb76bac7b8f2c05361ca1ea7e0a77ec18187565f3c4b43a6397da9a16a1987ac8c700996124a10789ac7e0932fb820f4f18a9a7675257c7cd08249f4185a1c7ab357470e8a35c688a236b4191ade41bb9271a3798380d4a2a643e302a53396fa8976d5b2096724ce85ca4cb36ba8f7bb470f534fb496a7104675a0367b05f090f4748145ca680a489fdf719612d52e610352462605c1a43d39945adbc42338424146c0707cb28b986888468b85f5347c8ccb6456dc442903baaee62f4bc1b56fb27dbb50c96d9b359894a823b812afeba2ba39b8af7227b8b58580a2603111a6fa511ba7e1c7ac4a037eb53a8caaa31eb551339212048865f4a5c8aa207ad8688c1e0626fee782fb6c0b97f5463d8830747b3eff7136a1a7a83d3c5cf5b32bc42b6bf06b4616055ba6b53fdf365b2c6209fc5239ad269263bc9458bcc2bf45cca868b4eda432d35a0caf361d9145a4200bc9a770b5571095eb18cdcdc407390099d43194fe096df8133a22753b7749c7b51c11b4b7a59427590f71091c969ea619601d494c91cacc34133e0cf75d1d34235a45b6977aa39847a01e1a5fe4e2c2a509a986249c482443cfa8cf3ff9358541757a776efbd7148383ac98289b4d68a579ac3fff02adbe7236e6d06c8416be80445de82619b065436468b0535906ecac1f563b5daa78b89c6ba5d4283b06795b4f88022be4b1b11ac075e8b571fc7af7d91f13334dc18a317ab4794ed69946c45a615c19209302cadc2f50c767840b397a9934bbc74d3d990a13e656d8a1347d4a46c6676402d563a0e860df9a5f0a911a7193be4b162428e0cb68b66b35146de6b2a57871bad3b166bf4a605bf3633912c31d0cb2e100c00ec9501d0be84468dabaf76fa2356a58155898e69a3c0e7d683cbecf451f22d5fbfe5c268257c663f42d4b0855590a07919c4363de5890b4d5b3df022c3c86b725c5f2b54196b7d68684b9fde93be78e38beaeef18195321f4e2"""), - xeh(""" -f1c15b3bf410c7218777a21f73ea71a361f62f85b7c47b2fc9c6f3c197cde8d13933da55d11496e10946e0e8a4dd59ec816afb6b28222cadb9f4a50591a4c3a9a8c8c4fe5819e1803f7190861d624757322be0fa7c8ce617d581136a4f939e0a5f4f1707fe493bf47a4b099f073fe10021f3690332f9cf77939e955a38f84271f4b260d90dc9195288d932e41edda41694b7772fc1f61bd5bb93ea9fe413b676b737dec76d94193982cd5fbcdc8986b107046755f1936b283768638b16a4dc16daa7f6c0b05fd11da8040cd0a25058fea49c576f6336a456584b0b5d9a38971d0e686b12a901c7daac4e2faa85160832582732b044f9360a8754c2d0a1dd5871b3d5048a3cd6e8eb5cef0739f1f6dadb83d3e65dcd3462b29c12abb026f5cc762466c25016129d0b92e0c10afbc70ddc6fcf33f434091798cd2ffabb10b8923dbcf890eba3faff2b2ec8e1dbf170c58768f8e37559e228660408be1ed5a93d7328a2ab1f48f9387056c5a51ee52f34178e2212bc85caa9312f50513878dbcb2ebb9e4479a8e9ac2abc42591c98e1b35ad5dd24da6d8c6c2fc0d7b964385f5b9596f6c76f5f681974ef8e5363f58cbf507fda58ceea9e3dced21dc95c75ba63c459b23cfb66bed7890c0b0aa078d77c7180ff9101d5762628e8140071ce861da0359db6b349c14a5399002486f54a77a6ccbaa01c1fef5c172e0737d19f9f68e7d20ec7ac9d211d81cae09a0a2f7086a4a8952e81dfc0c2ada2c9ee06d47421602fa9009bd221e02e33ccc0c47f670b5e05973236f3e74e768a0a84d890bbf908e835aa1644b418dd228bc3a9b06afc0e292f9d71fbfd5955b2765ce90df64ba9baac0cb5d5802b919cc0955c20bbbfdd624d5f6e0b0db3bdc01fc1dad5baa6482b71c247cc103f08db1064ca5144276b8062f31ad4e8adeb6543f85074a7aea53cfe360f71cdae05b99ab8d5acbb9312fd136920ca09a654d962e5623b7ffed22ee0773f3e4814bb232b112736b9a9fc66ba6e00b898a8b9258d2823022766c595ca5183be62be21c27b5abb0808eb0978d0541a66c294646ffea3ac2a480e8f9d3f0c58eee4d0bebd002c435d1f8802b854d953c3e9242495805ac0874d74837febffa135af5916702cbdec1d7b6f60880f85d6482302ef8c2fcdaea831d70e821055be0b5db3ec0797fcee74f652bcfb559416586bf09960662c408cadb7c41d36ce7ce803b9c9fc5ddb2d7274867eac6ae12ac08cd318735f2645c752c02dd74f2eb45293ef165d2bddfde7e5d235ca7480139554fe134577a430a5644a9704cb162cccff0550e738d79f8d01ac56edf07ce9561afa24294c7ea61f6e90ca071df601e83288acfb0bf69be559a2e788f7c18f25138584739dee13a307135d60df207ac6784f201826de1c7d48467cbeb721e711c7edae6443471f862b2867a8af1687aa2afde61a8c7d8431b2080b2a119b5d5c43e6743d1ada10027870d4ca0803646cfcb0712c692a6ea22a94b7fb5a455b6fb121c0afe8c176c8db060e200be7f59f9c075327a6f2e1e1b3a06df1684956a60332e86282872b18013898e004fe6dda04ecdd243fd45552cb2a705682f049383284ff382d6c68673987d6e880f0ede4c85b6f01ba89fee8b1fc2e9e091289438221079edaadca58b845da049475fff9dc5283f7db3c34c5816b87f83804f2acca031e06463cba06f97fbdba8e4d17040807b380ef7e87712f1124b43570b8f36be0818ffa1ae107964befe8f0568ee037d185cc6f6df9abb0f8547be4205d0778441ae56983272f4051165c9710c7bc2dce963717b3a9487a02bba79042ba5f255430202520134ca0f5276be9580174760b3aa4a7befc6efdac17f9d70f420a4c9106db961af42853c07c92f4ff6dc65a19b75228e34c43d70a44b61f6897fd6ad59817c919293af8c51b869666ce236e018edb3703452ce0c021aa1007d68fc575046eedb9e43c14e1d6202d0fb49cb40e7f6d78a062ec8cfe12e8936c928a8bf501c2362b62fd7a7d313c1343806736931d5dafff16471dfb637285286db906e3747ec089e29b0b4e15e3ef7a1ddce3996ecf7e7f834afbb004e59ec0fa83d6a0862b2838feb896cd83b5c4dc69077ec8641e9d5406aa683c68de2ee59ee254419b3a38719b40637349b6adf63a28a0b3893d661ff2589b5365e8ec9059081783cf3b4fa5abfb4d48be""") - ), - new DecapsulateTestCase( - xeh(""" -fcc4a70fd4395ea9728287b502e92bf9d77d3da38e0685858de5cbc8f286530cca0c683d13328aea540b77d41b806627139592d2672323c0b94be3cb9320454e334c4ffb6a12e12e63a96d1273cc8d4a6359263e91963ad472aa8cf2a96b3a62a079835535444541ca9e434348f3c6ed4a981ed70c59c33c27f25be9e407e6e7cb52a0274f1b7403f3bd3dc32de1f807b3317e7b5ca5e3864ea4739be575605f023273b17e2b9135f5b13bd09a00fec6283e0a744b784cf4595060c657abd8ab38270979606f7c0b1ee85b5cf1b2696db43e5eb21ac523bba172bab8223917508018d85b4afa10435bcdbd6405b9ac64f423adca6b7b9326adb5110809f12daea8270e48419d463c7bc264ed5b208880b8a515422ec9319b245f1331ae9ef80f46da776b4c83dc351622ec349b0b2e7be0c101b36c8bdca3573087d0960e7837579d451be25101cd45313b6b24c3630e18bc88407a75a16cacdf1664d19b56d9593fd2bc7bacd1cad8d96ad29c7c4d29c898220ec610479fe984da083863062b57b83b1a2b97c6789429a87b575365995223470c4d43c401cf27a910c31464f200b362434a8492b8126b965689b722c663342bee757f23112092a3486181047296328772b3a02b398d617cc69ba5bd252bb1879a7fe48ce8d47404f3414c79935c109e22d18790c9c07f606de7b69bca824ccba0a111059faaa36363052f811ac12fec42062820d88c4ccc787410d884d8e06812eb3fe676860ab0b069ac312ed332eae3059320956385ad2d502e11510cffec2fcf514180d46caff1044878ab667a56aba86be9e93957d929a15950fbf2a1333665a4525e6f592b1f9ba45df02843aa2541e233437522ad16383b991e0093c87c061df7127bca8275ab0234ee9bbf4986447c72cd65d657422a2b095c0703265bd129a019ea398152ba09ab9665e62163d862fc334c60d09894eb106be946fbd08f726a4fe01203ac34b560a1218543460d687c3b64929352456c65c55f52828677b99b412d07e250a969800ea7b5ec3053c99ab169cc913387933e29b52138a57214c99bb87be8c4ccf3337398c6cf3cd5c37df09bef147fcbc71829da53021c8b7ff04bace1c24b862e1b233b52985d11370842a89f9f33829c534f62828dcd91304966b045499c43046e822997d34105e1b31b49613682215a17ba2284d162b77996aee868ff3b25a7d5c5a740bc79771592f83570e682fedaab2528c3c427a04ac109576634e2846c1f43bbeb4226105713470b9b2556cd65b7c178f918d47b4307126578a81d02d99feaa5065bc0b492b4a9d08783af447827075b83890c6630619d9cc97daaae2bf91f7f021040858c99404dc6dc2e3c7a18a9345bc3308662f78032fa3a0328400a84982e86bb1cb08359f7455929863515343731c42c8a58ea3b0a5abc23cd7a8e8e029807fac289e3b9fa1a54e0f652b371c5e20839e84c9faf0685b4053b4e54741a916b76d398c76a26d572ccf2a4c83546c4ed8a6b88458db9523e65f676eaa1a74f731f74758c86a82662987fec79b287e02444dbc4a032a18c1ba4bd5a8c45dbac2f58a379649992056172c986361c0ea21935782756c4d00aeab17ac6ca938b063a27c00a4aea7e7e307145138fb68a697be49bb026a8b5c31700026d1026475ac98672554b0d8b2e9eec61ab891cb4911c19381b053b4a49b8559aac9791575c3b71154997ae5a65770e1b28ea601c2ed76a72974fea67a2e7f610442b749f8b3dbc725ba2528602978b05cc846ea634f625807b15a9100a1b743b6daef06d37479f9ce65accfb1de08c3d432a6403f06ebd423e6e357821150f448c6078d565068c8b343a2a5c609cad649945934bff443f19442e3eba04ed1227dc112e4ae670e2e20777f89c124cb3716a4465e84f0b86a78fa68ed83ab67841a76aa9b909f5a242d7c0ad499c81f5811ba94ee3a5c44d8818a0808522544f540106c89884da8890c6fb3b03887a62aa218537a18240789ed98acf313108884eefa00017fa4eab371d94e5410b118b095b2489448c55f45b511906d0c4caa9aa4ae20861ee3586a2da74e5098a50d543f1d16db01577f1525f649074adcacfb6283c69b41a73ca1ed97412c2002ee54192e34b71f95b0603d1858cf808b55584625ba1d4f6ab585b2b11fc091bb28a92ab2a5d061a3e4890ba687cf532201369883ff26ffaa019319b6914b8a2d76091aecb59e37a0916e5380f2143cb34176b6310771703be07305869bab8d98fd0532847446fa156446f2ab465499f7aa81f450b09df23ce66d0c0e6b82579425748da4a4cb1a13f711791300d21c0bf8a5191f3a0817ed4519931150e3161bc1b076383056db994a3775a27b61c0cec0e5c3584295b01e9855a188a184f78baff6a4ecbc5cc1b0227a5f12498d0b90ecc450d5a278d74807af78b3ae94bae64a3baec0c6b109a57800297918bf949b69c5c905f944ec8cb7e84865d67382c6e3546bb4c891da34eed09028bb3677ba624a9d5c967e94b65e24b380719517712c12aad85672f20c77b19e477490a411389b5ef63429b15a1a8d680b0082d586955cd67163ea7a7c8c26e661c52eaba8503b14b168c8c79fb7e73109b135c7ef5790afe65853509196b099aabe81a525a0d6b6b3cb2d5400a916416688d8f960d1607c777db22b3b2954cdb9e3932432e24805f02aebf672e8e6640d949221d3570d901acd9863566f439f5a4525367337b718536623b23c16950dc59c4eb9c00b76e0d11a942fa4e531a6152ababe6e54c101433b5b41c038907a548c69b1111aec34d64e084863c950c4903493b768b831a4acc04059083d6e7a25bd71b68dc1d10309f4edb246b7576acc70838034bc0e050ab40808a298ac7571d6a392bfbe57ce2570f18f35a109ac32fb9cb7e5a1da9748cfacc022b15abcdc469e79319bce47262012334478f301c1c42583ce84116a251a0e4d8aa38366561a22552eab180b1634442138a1c370d23a6acd393cdac517f59acedea7e620b4458b03585410d3edc5264f9375ceb6df9f870c8d7393dd0c2394882179c991933b8e474a85ccc6338124604727bab826553927d86541a4da61fea2581c5d15cb70b740e7b38b1787d0ea7acb6843fda6c5dff60ced980b80775501120c46f78cbc49a4ec63a98d324a9a177bbdd74ba0ee0108187ac0e245cfc7420a9294019573453763cd4b9c1bea9366d8cc7c996853c5c172f9b0d667caee2395b7a7c7fa036be9ce7b59b96663d260b69940a2a83624a62623e8906352939338c724a038337a59f59392f759c516cc417478cb7fd8c92ce868127e156ad4abcc714328ce67e2082cf2805c3df4b5be17b29a2446fbe26a50a54afbfc47bfa27855563b64e3846e934311f515f20c68860012c43195e6a45684eda2de3f9af70549d3f41c0b17519b02a7d29b076e49a3f80554c8bd7cfdf12a42d9b511c4ba187845b5b725b1a384febb470e3063312e9a05e846fe28b155dd00253a3afb9c2143ebb0683b03457c937efb1158fa93130058213176cd7888598e457d33cc6a600c2fd465b3629cfe84bc51cb3aa8bc4111626bb57858c00ab7b8b13c729a052bc222b06745b5181bf1c58341d239db92378a83b20a7e1299d407295fb94beb2c111f07c57401e522149f9c2b0a6d369b6f829b09970b660aa3dd6b0792b21797716de834286d662a3b03c38cc9ff1aa982dacc0d6892cf01492dfc506e7c37ecb8b82603c7d65843cd011172033203e294e6920b2007631f377cd003d8b9a4421614cc20e126d07f05205d0c1883910d9172aac4864ff7b7a8b1a1f5a8c773427aaea747db3191d312b4f4a82b7d9b4ba69313e6b7cb310507d03f47f8186a15d49030df21c144b639a7721357aa2fce77149507a7c5430d9611d0e7a5c93e54593314f3749ab0025603417173b13bfd7f32c6f854238e2675a948130ea2213a749da0c18001791f31755ccd829d76c5c62eb58554277f262427506cb17143557c919443922a09c1b735943c1a411e9db8a6b5c0dfc73a06d49c86e5b5fb03677f234bc97a2931af2ac804c0a9d721ac2468058a037e53346175981c879be43400a1c0760ec3096a56c0b2f11c9b97a87bf388058424faba04abf8b4d7f5069a4f26b14e39917b7858465761fd802c7c8cc2ce11cbdd04a519bbed86261f3b3b3b07174c26008b4d71311a951e0584100ea7d97881da990ca3cbc1d9f596a798cb0b1f79353413871e5a4f093b4825a47833a99994848af3378849b089b3843c7b153e4dc10896b4a6aa9848c17cfd3e0a0c491b90587cd2611908fa04bda829f0b494b045f938e08a7bcf1212fd194fac918ead125d88e6c4463a046899d659644d8f67504e278e1ecc03c50e807ee0dfa346aedb596d90d0dbaf82f24d69702e666f4086d18d3da173a6d0b44bbebfac8edad421aab72b823fc63d600"""), - xeh(""" -683607bb0aaaefc605290b064fb9b57f641f6303e7f36b8af42a63985f1c3b202fb40733ef308bc517dace0777b0c5ca164a8a1adac8dc44a320a4d81f924cea669ac48fb2d8ed8fd357e86e8c1c8dbd1fd3087f5287d24a78dbb9dfaac25abde3144d7c5f686afb07d4e407007363d2bd1e5477df4a49c4f6334a687f8a16964df2bc6e368de4b979d7491bc070292335dcbe09af01a54a759679f019d97b73eebba8aac0e8d10efe4855b54d5a74afbc70650ebb26370ae701c7647e4d5efb29697e31be934f4713bcfaa7969d9aac9bb021e73d5894819379bd03f05e8a724049a3e66fd5a0daea65448778121c41dda31d8dc805674bb44538970b2348858b2a0e323a1801d16eef04d97b4cdc8736b645fa242d333ebfb0b61c279d0efc19fb7f928e63c36a1c05746a3d29ec7d7abf8f3f5d3dc394bdda5708ad7757d79c29a40569e79791612a3cfa514b05b355051d7fddf24a0bde67e76dbd0884ceb3226fb61d48219f032909f979365cd2d33452dabac242fa9474bcd86d41738a1e23b373e85f1eaa6470c9ad08e84f212c71d49381bc6f29e813882cc5ed33148a40f9044f5b713460c21896c4ec5fc5edb5eb19da83212e01469f560d468817b5d4fd4af0665d2a47aa2faa618dc43abea75d0051a087b4ac513d8327e5a747a8c8ca0c6baa5cd6e8f0179bca470764795f42c48b5027e9506685c030c1ed45a197b566eb658fc1d3cbf27f585ac28f70fe942e2074403ebcf5d06065c6ba22b16e11bc2fef932c32ff316c95989054926ca812967e0447980a24ed6496e3930ec307de1785a72feb21664ed88bac3993f5e0845f53514963409e5ea751757b2c91b8d797fb7e2be34ba545ffcfc2191ea909265f2f056383b8f974096fb60eb01535718e60af1db55a8ac8cf8d2b753e9366521bc78cf6e9857391dde51021c7eab027e05999f570a68c851b8bbf3fa1e9ad605c07f9287506d456f2e8f25c8d391c3d6db6b12a8a306a1e642ebbb1a6ac481a5f844ac4aa3bf797b784e8d21d105fbaf699b342d37bf713e06384fe473a46f2eca96b09a64e3a05b46b24d0c795cbf2dad7e5ea935d414d162a8b74a3c47447a4c39bbce215fe864547dc4f647e0a8f29cbc6d29a2319ac497dbdda3a7b1b9f6154edb773cea671c353fe76ca6f4a5e160e01a2c82e2d5788628d17c077be6bd131c07a2011b5d40bd8caf784f456960de5d757cce1f0fd7cd3e1e1bbe08f00e20b4bbbb8b09c717036009b749bb8881938c3e0c49eed2949a93d3025e350a2aa2b2ba1cc55a60c13e63f614eb2e7861ea1afb2ca493ab36a6fa62ba85c7b737b061a465d8a719a16c68471c66fad823652b676d8a86350bfe4798f948dd794156d0461552b2e9726e3dc01ccbf1d805249c0eb46af62c2456109b57bbd75289062251b760ed80f1d5ffbb8a2b93923bda87bf5619fb8025c4128e7b3a4e4c2c5643b149fa9b1d0a4c06b7575f893d5f144104d313c47fe8e4275c4cd9caff44e0f234f970834f168bc7dd9a82f173d2a65c3f4ddbb1058ce70b37af74c7ee763d4398c777c38e111770de22bf654f44de171c6a49b405400b280e639f66b6376bf3b18dd9818302cad3d22fc2911246d89b82dca8a155790d3da8a6b12d65b3158494c8a84deeffccf53bba29d9fb83a62fd0666fcec097a75aaa7f6aca01a909b2f0865ad37652c90e339207bcd6a1ac7c7676fa26c7cd809cb4d1606172d40d2508ec259050ac3cf23210c6f977c52d121a5a1b4c26c597f8e6ba7fdaf9d4d83a2f605b1548bf58ba62c8e57f6e93629d01c3dc8420cfc5b2f8c5c193edfcdd3e3cb696aefbe19de337176994c6a7c4926d4579f9bb228b28f1b5ce23def5c67232d79023b91ac2a6f46fb6eeb47894c2b7cc46c8c14e3b3800a20760724004e20b9d5e17dba258528572bd2ba5013fda9ad0c5368d38252327fbd1340f0475382cd4cbb608605deebc5df36483a37e71a7544eb4bf861641b1704eb976fbeceeb295bb955e11cafa9b781eaa8dee2eaa9cec3643088d6e15b7dda593550f1197a1d08fc1084c30465a95701fb59b39aba26252131c2725788eae129c553789112108c433dc5cce3a5067ccf7802acf4c98b2951bf3e41f24abb2d840295fda825b1cea22248a71950411389ead7e2d55282d90491d9669519f4c0a8955826cc1351de731b2c4a8d2bd8""") - ), - new DecapsulateTestCase( - xeh(""" -dcfa84201ba9bf3915847c6755f8868b513fb5abc116920451f113e2c481d599129c1439e36bb5f0470e44f09a581c46cfb63d935ccfbdb26da9977ed53c6c56717805caca6056b007db45c261932b62a7d0c09ad99317b5ec82d7c61b2d3b13f0480d65abc07376a2552c21317a4426e868925829bdb661cae4ad4dd111f8080f05018f7dd976725941d5aac3ae00c9e0f15681e8bfa3db983a29390c108059d2696c3118c3a4ca0d970c5c603bad8c109563b58e0a1291868e2283447017938a3acd4442008f7b13536c75b3353918469933588602ba5b856aab04e2a7735786f5bc0f30a616369cb405c35250644ec9687488c781179b42dc9801793b80af048ee1e9488b7c755a985b27b55b71761cb5c101692362c1dcc1f86b147e1c708df38acf9179248551927a49dd0a333237b0705b0311a632acb5990b674ef55427bf64c86ed90089c5b6ccb12dea12565979c6492a0ac8106cef2b432ba6654c65c9fb40913727ba261c82aedcce19369d479aac4c403f45584fa71a238207a332b8b9b7685ded0661844911bb4a052678810ab6c879279e3442cf92f26b1041cc2f6c30c1f1b8c394271f19309c26270d9bc59d81628998575788ca4fd59a09a54c1c78cfc4260e1b149c9c7a00953029fd62064f74cc56765ef9c01596692b12b144d20b97ae050c7a2b51aa16a1a037939e91a8253acf29218b1a760dca0ba5143bc59154bbb86c36bf161794966f42c8b50a4a51f9b6939970c16a846fc728aa8d6064e9e8a57ce5647288cba6339eaacba7d1e56073aa17b629344dd87799e28e97245d92235abccbbe490a55b0f02b4c95642dfa0c674118031c457027cf37435c586918e5480cc20542af3a47adc66f216b5f2fb29d63d874967814f85738e76b7a2fb04bfbfb3ade632d4aba4b435102f4b07def648351bab8c329c957eb7d423964ee61cc8245c963ca666331c10c1ca922a4595d962647271c34753434b06ac9bb2e0a3c84b89604e90b24fd366d65616be48b953a657fde9a87e0e0a59e770194644af2018a3cec7a3cf902261538ba8b6f96545112331b335926dbc1b9d89007c2ca32f21955a739995db6a7ec2300fea40317905eec95ad690592d8c8c2d4012703b0c99c571c9ed859e9a040787c00a1b055ef8cb5ab7a15b10064d550b27e076752ea8fea36496afb6951827d2ec90e07875fe0bbb2e1ac4498619272705db8232423473e90d9a61e23ac5aba208b984fc5f5779052a7f14a39106cc718c9178fe2159c824e59045b4246c9309318456735f1434c6c78c41ba09d04833a37540afc77a55bb39e6450aa65c3305160a18e7c84f095b2a34699a8303cdcf75394032e0e8474268602f56a8ce12026f4d73d4d02bdbf1699acc65ff289cd45b0c3e958ad85327869385b58c9a19a1a119755480c0a72f12c6587bc00ed8a9c0224773a0a892053722a58509e746422f6a3f21a5d6c199c583c302ef2a07096b90f10821ee036cd26b45445afce6c12ff935615ba1c77921457f119645021f880806969533e06a044695feb4857e94016010b4b7724849303c48ba2ba64e17d2738cac6711fe79b049c740869993d8b158295f42fa2a37f808022e698764b476d81aaa63971586f84a5ebcb0b578caf2f6a80dd384050cba2663c90b9a713fce515d7058494d5a82a160750f5825e5a907b1c523131a6494bc03954886c10c520fccf48e97f90f04346f7c3890338dc30688d93a350db4bf9a31244ba7d4ed1510a381f13180856a188036526f7c10bafb11284e87656f736a9764a67b963db67ba284cc13b734a6eb1a9094c2a5d342c2e504d87781f87c8320f21057dd21f884186c014ced432242d618b09c4237bf50b720a97b2d86934213bf5d044d25673c26068150228b19219f4f6a6de8729d10c04a7055d7bd3a5b3716f702c6db5f8c93b1536739535e8c83da1d03eb01c514b330592656a81077fc64b9682a5877006b5d7464867ec27c7238e0ee7761c8183a6fc468098917a620161ca01ad34c54da2bf82ac01bf32c14589b188cb338b7294527a34c971826111a6160793fab4772e264779f29ee2bbc6cf822dcdd5cc0b76c8c2fa8234724856f89108e79bd23a1a2ba163d1c988ff98c4980842126889b92681c523358d22adbbf41352fb8040963385438d80125b7b78a7bb42515971c90c01323d9b3e75697ee3729f7521301d11518b92154436843987531887631819167405c36c35bc3be88d957053237bcbe1fc59fde76f1fb1c0bb4ab166ba098e6c4b58d26ba606589c568601c507a6fb149e30a9ddf126a4491812813ed0ac12854b3bde1b683cd23c588082066303931941aa5856bb94a0c932c85f9b9a4796b9152172647221d3e611b94b667e0985bac481f69ca20fa04dd57c42adb71ddb51933ff36dff38bb580b9bb0a666e80372c8e2b8c29a711f484d11c1ce58025c17d053196b50ed28342fba9b24b8093b7c286a4c1712346cf886454868ba79d53fa445733af9582113c85408c2e8473a3bc358af200cdeea56e44086e1179ed300204dd6b39815616dda5923dbbacff091970a57166b0ab5f1b25e1c1d2cc495151b97dd1aa87903204cd3b3b19830ff010d4df31ac3c7623ab64d951c9fd502ba14f4c884661d65d249c33b2f8d225c81f99f3bd88fc5a71f40722849b6b838c754a11a3b8bc8673cf900dc92b6f4f66b139c76a420abb5a2be9592ae1f3045a8da088871b45ab66610b64b163b38f641beee8a9a8f13a30996c262b2b9231241b34b5abef4830dfa922ed98a75f61cdd59666e3c728cbc8a6132a343a458beeb0702fc962439b2afe7b971ec62aa593cbe874b8a8c923f963060d1ad64bb6ad1dac893cc3ab5188e7943cf184b7b18ab26133ba4109a57207147f5e25e15302da5e82069aa721f77557c39c760d28cf37715f7a943de605193e29a6a94ae821675eb2b3f08ec4d7f0a99c5e71cb01292b327c107b61e6bf99066d74a9c8b47e99a05d8f2b9a1a5b12723c101220c57b509a42c5b28e853dd75251185661b61499ef978bd1ab9b92864ce013ce2123515ca5aad6b108660b4ff1492bb124f5bfaac592107c2678c5f04c2b658bd31cccb7a09028f48a245e638e8bcad19bbb2dfb6ba3bc10c487359b3b0421eaacdbe033b6d7a8d5d2311bcec5148226d4dec2061265c25b0746af8c63cf99f687a04c237739d648de7919cdb59973ba35d85187d20212ea537cecdd9c68de59345fa0dedd31ac6b21a7053adee561851b7be01770e07daaf903c2738dc835cccb05f5a931e2c4d2541a8328983d26b20de5bca159973bc01301d0541a8e311ef7046ee9b51a0f67d5202d0ea8c8217226a622b32b684066f2a000ae22cb1e29b47176e7973b3e9d4c18f22919a89a6573147129a43998886e8d95c804c15a01084f3d81d7f0288cfb34276536389344ed7c09eb47b9d20300abfea2a0b2878090819477a640e39cb7aa1643d4a59bc6488494a0ec3073dad9706b752c30b123fff3a1e66a8b575587e3b119d83e1b833893056b696ed49a399d11278f23f456b5192fa324fc4222dd247acb005dd50c918893819545f59b8b5550bd0a3d97ec24a5c22d4b8fb12290ce4cc96528893f772dce5c52dc0114f19c6ed026928f1092349475a020739aba5f5a45b8843157a76945dc84e7284572395345e695090b37edd895b22870b39ec07b36867b5dacff5392bede2680d74cc2272713be24ed37a22e33c36a84ca9643a46c68112a9d12aeaf67bc3160080113bea680d9b1bcfdf75be1c18c9f2e44781b18b59a090be8aa957c366a4b24a33b9b6d055674593470f37caf456b367fba266f34160d4cea1605d6140be110a93b2a57e06dc811b67572510549889002ae53dbdcc758fa1aa2e4bce4d6ba0dbd09ff3f736ce630c7b454096d6415ea32b797404f598c4b02a3dd6c98332b7440735a71124178a0622194993b442c5596bca2caaac46d77f6713a547980399c18e5685cd9dc879194cab66b99de4e2888952808b15c1bab5b712ab3e0c781b209162818cb3985b77f4e915e86779ecc5b2096104f512cbf1162b9aeba6a3546397e608d23861fa3aa5847a4cbea7229f5338ac4161b9765d74b175a4e95a68a6cebfd6ce796214163ac5b314c0deb2a3463b1f7e56b6ada724a2827f60647a92ea4f33d36d7683402fb12543f73a2804abd00371073306f06aab9705819091c9afab226514bed5c46f8c3c8046787602501d9d4561582164baf07497d09beaf06cb2a49627663e04cabf05e5bd55f9c0f75ca0a93678ffe69d7f8034b4f0898ce5ca9a26f52b3bae41398ef444b73decfdace24a6d62657cfe717bfbb904ea4bde70180c895d3559ae762a856ae7a8fb57e1ea35ba8d4386aac7d50bee0032580858865f638c38f0852d2d712a708ffbd7d96f0df21071d8bfec74c2302ea4c5adba"""), - xeh(""" -744266fc2795dae658efa879de343d6831d4d4d778afb0f064fda23d22d976434ad41868ba11ac4e73588ff2398b2985150eed716b430f34daff5d1f7365d3f28777e2cba704d43963e2a906a197af491e192d8308401b5cbe38a6b48053a62308e54593935665e78e70636146fb726096e90c796e88c0462827cfee8462b9e6e0762b061aa685261aa38bb6364ca84e14e07c81d0d02cc65a14e49683095573e628d54938bfb4997381461a3801306a2fcffcfc54cb834a98efd328fb516d04c6f8334b839a7f0fcf340874cd94060cd926c24a201e98901890c4fcdf8e55c8a485e245a37a618ca074097dffd436b1caa2b900538a8b35096a9fda5c98ed5031bb25d8ba86f5285a003a7aad4470bdf7dceafbdb46450020723bcbe8a44babd45faaf3ab416acdcf0564c0b513203c8b3bdae283145063b8de3bb045e2595d2e72eb324fa2c4ee7d7bf5685684dbd69ab1ff5aa2a91f22a9177c053e5a9b30aaf7334425fa01f223b8dd846435615dd7434053397cf0b9e4ad650365b847298672b80950a9cb89b4258a10b9e44248f2d06a6921c7b87441f72caa127e741958fbe42565770eae9b2198370c2d422e7c3baffa8fc1139d2da25e3693648da40dfb8f18eeb84c70276c198a31a0ad3372285d50aad40d7355985c574694abd8452231ad2b862545bb3a620e477ec23dd592ab6ab2e91d1ad0b185f8c918484a4b44b2351d8292f00a025c23f758fec9be75398e83df275f52b8be0d9dacf3d2aa57e0055e67cfa0f872d60bab9b6c3904906547d5a610e7b0f1be8f6d081b608edd81ec0b0c6c45f625c9da548a4a1a119f3d9b2793112a4d7f77c9c7ae4ae7e48678a1e536658ef5584bcf8a7ae9f9af9629f697fcc932d365c7d238834c633a703c5b29e9a8e4fbe1ec1c42ff5ecbb9eaaa70903c92b9f66dc6660eeff2b4e8a563d5b39cb355e8df23b017eb7d38e422288c11e4a03803b0ed6526148b25c847968f554ede044c91ee8bdb9a1717fa253e65f2e5387eb19e84a6ccc5929e1366b4bf1e1af72a60ed2e674e54d256da46772b474dc8858967edbaf79c6780a839b2a20e44a02f06d1981b03229af586ed809da1b34d154e2ca64a1460f3d14bad117c39438922fb300398cb9a17dc266ccfde46da47f4dcc6cf54ed01374d3d16284eec4f5ceffad0ddd92b4b7cc0cabe0992b076e1f06ad2d746917ec8c0915c73121a57217a425dbb672de08414c22a38753d6a0738f9609bd15f26be584290829650025e2bd61a121dce852ed9ba96ef487b1cfe28d682e01e375753059a78e6dfdc3f9a703c02e8ce4565cc9cc3086ce2f0a692b4a791c622f73a8dac791440a1dd625f64f7ee8af1e4a9cd8aca89bb697d0295c40489be97453e46e1648998aea2bc2a53c053b6f89e33c9dbee8d5ee607b3d9b212322c5d6c1573612179964f316131b0a1f3cc7f107a03ace199b1033b64b6a36b456f17028a53699b729a663ca99e30c72d35dd277509adb62646647c2e4f2b4d31a7ae3e83b9d82ab3c0785ece85c765a2a1473af5bac7cffb1a790c73161221b45acc0b1dac261959b1e2ae2a18dc4bab57ac5e793c4d58661ef836fdcde7d8a187345cdb357e5cc9d32fa16a194873fe32a03fa31c8c194f7b63cd9640398518a1b12ca69ec6ef28c4a1547883277a94ffba92416aab83b240b034ea3597c8dab9fc0859f8c5fcef50eb00705a5b21a015939a9319929729bc43b43f36032b17781cc062b46b23a1533c981e4bbefa2ab32a81b30a4ff5655070f765af27022b4a7352189e52ba9e7e7a2c1f5eb1d5238814677802356a8f7ca849402430bc2a5e6c7323a9a2b23401876f4c5e4cfe56214fd667622a2b5e1eb054552fe10fb96788be387a68564e1516d9be5b99a76cd0431f65cdf85de40a45491d5b25071efbafc7c385902b913105b9ae0ef20c67006d72dacd4097df75e5d378fc174099079cd126729e6981c0f9a82314debdd86bf5041eae98aeb754999db6e426dc8e3a6fc5b17cede84d4b1b65ac1ef519a325dc5abe2f4ccb32b5cbfe457c7441b156f39dd4181743a4378361681fbbd186479b7e958472fcef7a0f6ab47afc8a858a5fc2e5c64d55a916c9484978b5e747cf885bfc9d2426443e38cd3cf13d57bd18e0d0c5478a86e20b1db35856388c4963fa1586175765cc8293fe5379cc7193d19e97e6bd34""") - ), - new DecapsulateTestCase( - xeh(""" -c58540ef1a9e5dc496f0a413f8001e0731abc1b169a1f0ab030564ce03bb10d75a621bb8410b2a6186c6ca081944463aeeba6a45494fe1f1c9db2c48cf089cfb928d3de1cc6d02556ac7607af731cce7cceb00627e9a55a85c6eaa430dcdc068d79a8bcc8b4820f61cdc7214c64caae4a096d71390b95ca1bf243f4b3598b800a38804ac2ba7c2484b0a9d2790c3b91df06a40f5eccd52a36dd524b1a2831e915643063103961a01192a1fafa56c48e90828c359944857226a62f93b053bf550d5247077643171100b01309a3d344995b85fd1238fb14a73f2f03b4e201cd736c4f73c5ff3206c6c89a878178d4010a94963c025f090f2d32db71252a06acc88d7657d1a811b5052240ace860a217597a29d5041868a6bc5b278f0b04726414383807617b81bf7623186e44ef0695b97291827e0bc9fd92acb014714e151162a7b4e1ba04d5221bda5b2faf2ab4657853daa21f2b726f54a9bc35ba271d917a2bc1ec357957c094dbc683f03a5710344bba6242fc678809cc71d9a2a76a2a64bb0b8c5f66212a5a35c5e309b61c264cdf418bc27635d7751771cc875318c9f1b0df70073019a89a6e124c349a279f431f14b431ff11b0cb17ec3eab1a2a4a5bac45415825c4ec76016ca5f25581c89083f43a863c08092a8849d45f512be71870be0c25416be17c02e20e75cd519a3c43a419a3ab6d0c55752702612e298489559effc83f244510c987b247009b7d74e43fa56ee0179e5949a050b2a961c6a74819451058f1a624e9dcb47bee04411cc3bef260efd21acc3485d99d87f48a04512e9642eb37ab5d21cdbb21cfbb15df320cf887a9befc60a366a331e3b3be06a96ce46cf0fe559a6205677c62e30b964c53b669ac82a1e900c13364552c50c9da3a8355a0bfb97ac13695dfea28abec17016d381ccfa785e070a2f5568d1fabae0b6128d820cee749300bc482988b735e10a6629408f4242796925fe5a64d2d47b46db6e7c078c294aa6b0f87271a80f2b4015967564f30378768553f290b3df99a0c7008e99f1c026f7796ffbbd43b092c009821b58cbdee8670a1894f47192b4587429d3a99efa95bc176af901558db0280e0c62fea04474ac084ee960fb6604327b391c2ab2fce53eb5345966d8bdda98a107a210cde574b91012ea51b5860bb86c136b2389cb0565ba0e29871ba1b8b733755a3aae23e330a2a3b98af8204537aaae670fbb087e38767961641718c469eb7ab99616c402c8abc8544c47f733374661eaf0b6025084b2407fd4680a1fb57b17681d65ea7bab457eb2858e41fb9863646f30c2aca073b894f4723f727ff2b52c59e33987c4508696caac603f37dc854c3c6c98da6b69e5b20f917537a7ac2f37bc941303d9b4c38662174ea7c4af651d751684fdaa12cc6b6e0deabbbcb868165a28584410dcc33db62b446d23917a503daa2b633dda7eea324926c773140355a0571cb24117ec433aa1f2425d90081c45a47dba89106ba82d1060661a681b26c899766b13a000e6d9c0fcb588ceea0cdcd703b9600adf105819608cf4b81bc8c8c14ad38ec3b0b7def92f67f5adcfea5dd85a058a87151573075fc5916dba1208724202316ea14104570aba447339280c5d6a580137378390ec4439251f93326c423c1b84c4abefb78ccfc0783856b3793c23ee401da23c5eaed04302395b672316719429d8b66b7b33198792af7257b3d8ab9077d13a055c40fcd1874b8a8aa8201dfb76a396b534a1b2aef9824107f04a81dbb87984433b4c8e1e7799e2f7c8a284b02780704ca3218333894c1571c96671e2e0195d3a01aab22739c8917409c794072c83ec90ca1a78b7b1c6ccf48340dac772f46c33c524dd6a58e9e281249111fa772b1781cbeb1653876122f0146448d81c63f1279510a7ec528f78328605a21a7f8a0844d30b96a118c775832cb6b281cc3e965924cc4c6847651d3dfb434f100b509c0c3d66537d47219a77ba9922a15e5c97550bd0fe561b9109bbf89c555c4637daabc2a9620fac81ab69dab4de54529a957b8f0184c790403a379793704135b357cd8155517254255c254c982dcab7a05647ad73e1184e1aba78fa5c8ee24ef5183e873105a89c54b085c7f8404278697f212678fd3948d423707f957880b54611d04e05965db36a6f80ebac6014cff91b17321b0fa32c4d1eccc3dec3707cd34c7bc63e62d2b57ec0314b659dff4263c0f2c5fae2a37a84b0dd415275b3452894904ef146f5728a76a56c9447988767390a693ff7e91fa6e36f3e5a5b42b97f1205704218379231169340c416f4737e06364b935186e79a6bc0912938ac1ef818d57878ee872af70c7f31e8a5da0746ff4137e8f9b6bd7b4b32b47e12660b239c77115c72741c74b8dab0fcd07180c35e0adcbd2d58b726e3775d288a6312aa158620022b623bb29e141c33e0532e5dfa67da9476f49a6f4e6b001597a54371be84d70d04340c2f403db373a1afb102780b5050c841d98b10af489a39f8c2e473c23f202f05a20dfc4844cf1126c562cc9610a98b0a2d5407169db917969b1aa5c314ccc96290d2c27743b1efdc410802c78543ae40686cff6b3dca439e243c867d70bb957086abb6a91b49c7a39bc2dd107f65c7bba534c1216857d2b1a7ee99ca0556b3405b25da0a0941f403d0e34677e49d1ca84f267bc86ff0154614ce5b3526aec88f95285c316175e15b4fb92bb3d2a99d70a0259ed295eb87b90b5b2f5e2a757692262866c70a9cb8d843490e563594344e05a4051b3155fb8817ed53431d5c0318146cc31b0c524b6410d53aa0612a51f1c763941c4cd42628f212c04cae54b6ca05a5afdab8ba54f5666a13396006afe7005f612180002d1005795c468cca3d778938e187b00bc29220266047b22df76b18040160a48e6378c99fc5afa4020fb2b135ca913c78c73363d93d10677bd6764a27221ef2a2600f5b867b52c375cca78846880ac448f1086ff678220b7a238675b740c21bfec76559d573a6a84190c750cb502d9c7663d50987876b607f548ef76b764d03b704781d3b324ed2d7c1ad285a3e1ab1e5d6c7ff49495825b1b41a5ac2f524bf27c2e875aab1023c5f058f1a7881c3e60ab9fb56d15562b6fcb8c8c04a272c8ee6c807baf6227330071e6c49c8c805b89b6acb2025b13c08fd9916cf40191b9520409a6cfbac821fe8951c027f84a11dce4c54db98be7427b724331c64169aec4304cd71128448473f599eeb8239b1463cbd43c0836755170c19b3108dbe42bcc290cf23619a303230f9b0982c3b7307734e940807245bc097649d2eb9ae2b0695fb56b16cf90eecec1a50c5157d48098a063b53158855c9a1f1db9ea92b7bdc2488bdd28c095ac4e3374311c2754cc56dc8e511a5bb4cd486cce605527d594ec1dc1356b9bc938c0488b6b6d53243f2443223ba200b0c32c6f49322545ffa8a2b1bab914a72918a658b6a053d91249fe0c20360116eb3090015c161d4480d492bc7644762a48b3f6b558eb1f9b34cc39398cb266be91c414a3ba790c9c92129e5d40ddbd3150a5c002f763484546519c3a2ed327192bcc80f4710e8690a8d30a36059b12df6c107d1a73d9bc57796ba08fa01fc0c2a4f8b7a63074786729e0596615ff4b7c957959ffb1c5537508b191507e16d33d1bee9eb2148618bc8b279f0e92072b8c037565251992e87db4c0de8775d151ad13b2c375a46688518e5a2c409e32b9f314e3b177d72a908f3fa0010c87724aa2a94ba6a2728824719c6a1b0a2e07c7a364a0a62cc2730966ccdc96eed27341f77389a854fd12b9aefc0aa4c59a8aba457c57222e7065be09b593dea82279c8f67971a46878bf557b8dc095a9a0241d3b64ebe02137ab14eecd7410bc70efd3c08c1d6220f597eeabcaeb4a7b129ca73fd96872077577e44c804bb55d02607234961816b85944913dd83c5c835b1c0cc94f871a29073b8912973dd430246f84780d51ab9e163cfec5bc3472e02377bc9a2760ef5529568a4497c556e9a5f71526396aacc3e86158ea4189906b8ac277a90e383e298c8a1b98623cc909f18c894daa83338bc3f3b57152cc472889ba297a533d0554a3186229a8514c9c4826725249c61e4411963329eb99a37a4337e24c2257e5354ec5c2e4cd85bdea15c4e16cffcc628dad7c3ed9066287b587cbab64f0ab3aceb69494a333d240074c989cde4932d291f8edb065577985f68421d312e429a15cb21b31576c8d0b470c2177cf7369d45ac839c5c191acb40e62a115364c8875883ac507e5dc90a6cdbc6a540b396b422e488bc7d25c8287b79efc32085758d593b33882f218e758a3186d9cf309538fc57b81edc3ad0d228aeef39b32aef07a4054c55a1b8e412d907ce76b043fc9b10de7a9d3005a20d9c70d011dbad1e53a7637a741a60c9f1715c42a5a9e67b4e69e5f128372002a6c4f54ae5869500171e2541"""), - xeh(""" -0ddcfac2dca44756fc1b11c740a2d9f197a04eb49fb236e8a72761c343e2cf6c0a15ece304fbceba5619f1eebf2ec4285dca695fdf201ec2e89ff040a0983603abc1ca303ffd8ffea696953ecba82d866e9299cf793de3be15122de05aad7f939c382305d89c25dfe2f056f788c7911d44926d15b80052249e76de754d408cd05f5a8e067a38ce8d37174a7b90c393d1f72cad0834a97659b08917d07c363fe2efbd2fe95b1f717b7283aa8963bb3bfc22d2de515494882d9e1b76ef5d29ac625e2f0c0f67be70fc406302c0002ca7ba7cfbe08c308a11a6543df01235697fd05f94feb7c9f9f7bca1fc216214bb4e96f4e9f265cc2b4f411a4393607c39b6e6113a354b3c3b93090d13824c05813c8b4b353f5accac0062d9927a3dc3ded66c35567bf0b21fa0933af66369beed10f17c08f1bf96dd65da973608ce1ceff65a8e6e6b65f7f335b9593752bc4bac179b8d6594a93cdcfedb26c010769d75744d4c8e422dde126c698df3d791b51ec526cd2e4e58a0d6727e0df79db80c876ca598d5e3ae73313b91764bae84e76556883e6f4f82206f367b041e5b53753316cc54dccb87189bda18a31e76b6c1579a90fa2d54bb901c82257b608ed3b79eadb9aa2cc6a96e107cfed0fd1cf906cef7abc6519bb674f5a0eabfd10efa47cbd6c13b21185085ea8efa498732e1a19c1d3fa85856f4f4704f65a920889cf96a7b52fefc3e2d926c5eeb9139ac247a8c0b73667e3b0e438da939ffe8bbf849c112aead11d8354d04201d34319f4c65c3e4a1125b018a22e2e246c1aba3943dbf5db4797b97daf73451a6067a669941c06d19531ad8b74d523e2bc7ee512cc9bb749ad4d2ed87357d0dba42098b5533d95419aa18ac3965b87ef2b41dcec80e9661a10ff077a098cb55a604d1f9059c8260b6b1a388d8ca3a83288cb956d2ebb0a5076132fefad9c8eba00eeed61a8a8b7d59bc342f56f6df694b5d85dc28ef87da73e8d5e9a29af336cb5996c9b1485c93a1f8a1a3cfcd17842d17635a15fc5b63cca2ad560824210aaa27ad7bb8aa3e16cad96be489fdc43d8245cfc3fa439d4b473992dbd1d3b913282756e2c60ee2fb125663f5837c4e12da4232ea51b75710da1436fce145ff43637f166b3227c1ed590d2bca27bf14a028940c81de99487a6b501a9106255eb81ee939ce7f9e2bbd6be754aad73bc287ad27430625e171bc3239575353f3782be69cf21d829c0ddafb8bd96614aaa1f9fd5ba1b0429e379d32cb76119da0b3f9fd76dc1b92b25057fa695be31fa5fdb50464d6ba4a71d6726be84382b84bbf63f538b5a2cc9d91eb449841afb18ab8279b4eb9e80155cf1eaa11a2d4a421d880c85d037995cb9303a3f5d071a226ca55031334fc1c4a1f2be30f7a4268441a987cee3233651e988abd40e3b1306f492cf412a207d644fb66243efbac5eaa2e6ac045283889888a59ad47bde45a7262c0b9470d427ae8aab1a1c589653bfc20c17dbe7e6306ef97c0f6c925f1a38b146cde1f6216deeba31ffd5cf6276e82a5c69f5c6e4b69899505e03a528f23483d0bf414ac0031fc329cb9971b33ce94bd2dcdf42b88a084725a98eb9565bc90f34fde114514d5b81f7916294745b42c2c81b8cfede599200ecf50c2a8f369713cf2a3ab69e8c8a1f0c967112500790e905d958457a04e046bae97b5f14ef782eeebd4454a4a4114ed46debc56e4c3d4beccda4a9e5ed3127a9e53f2906e3755e4a75ad6c387aba579a19493a089b0e75c7bbf906f73fc017272e3f739b6ddd46e027ada7b86b91ebdd70a5ebfdec11d1ef9434d305be66e2a6889028382e39536405137dee759636f437f5a2da8bc5f883ffeacc1d8ff9bde31010906add2a5d06bfae7c9921cba9e67725c17870998257afc64409481f562a04d4f3acac8d6b65d6c7db7422792207ae376e6b6a5f80d417c4cf08ac90a0518b8d852a8f4e6c6cc28c975e0080d911d24b06cb05952035f7ce53cf1a14c7079b52bfdca9bae9accd71175031cc28d359d89067ebc2ff1b5d6ee6249e64a42227599f54f36a278a73bb416f5d136cd370b77b432b57c7ed9b69f34d5e14b2f0f8b008e0ef5d9afab188a532a5b63ded634e8821adcae833ef5c5ebbb166bf0d0db45612f6bb5fc498b9478f903e305479c878cd8bef22c248336cb457601d5129d818e9a06074577c9c151087aacaa1f24""") - ) - }; -} diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java index 0977d2bc462..59e995765e2 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/AESBench.java @@ -25,9 +25,6 @@ import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.infra.Blackhole; -import java.security.GeneralSecurityException; -import org.openjdk.jmh.annotations.Fork; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -39,10 +36,9 @@ import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidParameterSpecException; -@Fork(jvmArgs = {"-Xms20g", "-Xmx20g", "-XX:+UseZGC"}) public class AESBench extends CryptoBase { - public static final int SET_SIZE = 8; + public static final int SET_SIZE = 128; @Param({"AES/ECB/NoPadding", "AES/ECB/PKCS5Padding", "AES/CBC/NoPadding", "AES/CBC/PKCS5Padding"}) private String algorithm; @@ -55,9 +51,8 @@ public class AESBench extends CryptoBase { byte[][] data; byte[][] encryptedData; - private Cipher encryptCipher; - private Cipher decryptCipher; - private byte[] outBuffer; + Cipher encryptCipher; + Cipher decryptCipher; int index = 0; @Setup @@ -71,7 +66,6 @@ public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, Inv decryptCipher.init(Cipher.DECRYPT_MODE, ks, encryptCipher.getParameters()); data = fillRandom(new byte[SET_SIZE][dataSize]); encryptedData = fillEncrypted(data, encryptCipher); - outBuffer = new byte[dataSize + 128]; // extra space for tag, etc } @Benchmark @@ -81,25 +75,10 @@ public byte[] encrypt() throws BadPaddingException, IllegalBlockSizeException { return encryptCipher.doFinal(d); } - @Benchmark - public void encrypt2(Blackhole bh) throws GeneralSecurityException { - byte[] d = data[index]; - index = (index +1) % SET_SIZE; - bh.consume(encryptCipher.doFinal(d, 0, d.length, outBuffer)); - } - @Benchmark public byte[] decrypt() throws BadPaddingException, IllegalBlockSizeException { byte[] e = encryptedData[index]; index = (index +1) % SET_SIZE; return decryptCipher.doFinal(e); } - - @Benchmark - public void decrypt2(Blackhole bh) throws GeneralSecurityException { - byte[] e = encryptedData[index]; - index = (index +1) % SET_SIZE; - bh.consume(decryptCipher.doFinal(e, 0, e.length, outBuffer)); - } - } diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/AESExtraBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/AESExtraBench.java new file mode 100644 index 00000000000..a78237f0c83 --- /dev/null +++ b/test/micro/org/openjdk/bench/javax/crypto/full/AESExtraBench.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.javax.crypto.full; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.infra.Blackhole; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.SecretKeySpec; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidParameterSpecException; + +public class AESExtraBench extends AESBench { + + public static final int SET_SIZE = 8; + + @Param({"AES/CBC/NoPadding"}) + private String algorithm; + + @Param({"128", "192", "256"}) + private int keyLength; + + @Param({"" + 16 * 1024}) + private int dataSize; + + private byte[] outBuffer; + int index = 0; + + @Setup + public void setup() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidParameterSpecException { + super.setup(); + outBuffer = new byte[dataSize + 128]; // extra space for tag, etc + } + + @Benchmark + public int encrypt2() throws GeneralSecurityException { + byte[] d = data[index]; + index = (index +1) % SET_SIZE; + return encryptCipher.doFinal(d, 0, d.length, outBuffer); + } + + @Benchmark + public int decrypt2() throws GeneralSecurityException { + byte[] e = encryptedData[index]; + index = (index +1) % SET_SIZE; + return decryptCipher.doFinal(e, 0, e.length, outBuffer); + } + +} diff --git a/test/micro/org/openjdk/bench/java/security/HSS.java b/test/micro/org/openjdk/bench/javax/crypto/full/HSSBench.java similarity index 92% rename from test/micro/org/openjdk/bench/java/security/HSS.java rename to test/micro/org/openjdk/bench/javax/crypto/full/HSSBench.java index 6d0cf694f4a..13cc9a25113 100644 --- a/test/micro/org/openjdk/bench/java/security/HSS.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/HSSBench.java @@ -21,12 +21,11 @@ * questions. */ -package org.openjdk.bench.java.security; +package org.openjdk.bench.javax.crypto.full; 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; @@ -35,29 +34,27 @@ import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; +import sun.security.util.RawKeySpec; -import java.io.IOException; -import java.util.HexFormat; -import java.security.ProviderException; -import java.security.PublicKey; -import java.security.Security; -import java.security.Provider; import java.security.KeyFactory; +import java.security.Security; import java.security.Signature; +import java.util.HexFormat; import java.util.concurrent.TimeUnit; -import sun.security.util.RawKeySpec; - /** * Benchmark measuring HSS/LMS */ -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.MICROSECONDS) -@Warmup(iterations = 5, time = 1) -@Measurement(iterations = 5, time = 1) -@Fork(value = 3, jvmArgs = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) +@Warmup(iterations = 3, time = 3) +@Measurement(iterations = 8, time = 2) +@Fork(value = 5, jvmArgs = {"-XX:+AlwaysPreTouch", "--add-exports", "java.base/sun.security.util=ALL-UNNAMED"}) +@OutputTimeUnit(TimeUnit.SECONDS) +@State(Scope.Thread) +@BenchmarkMode(Mode.Throughput) +public class HSSBench { -public class HSS { + @Param({"HSS/LMS"}) + private String algorithm; // do not change. Added for visibility static byte[] decode(String s) { return HexFormat.of().parseHex(s @@ -74,7 +71,7 @@ public static Signature getVerifier(byte[] pk) throws Exception { return vv; } - public static void verify(Signature v, byte[] pk, byte[] msg, byte[] sig) + public static void verify(Signature v, byte[] msg, byte[] sig) throws Exception { v.update(msg); if (!v.verify(sig)) { @@ -82,30 +79,20 @@ public static void verify(Signature v, byte[] pk, byte[] msg, byte[] sig) } } - @State(Scope.Benchmark) - public static class test01 { - byte[] pk; - byte[] msg; - byte[] sig; - - @Param({"Test 1"}) - private String test; - - @Setup - public void setup() throws Exception { - pk = decode(""" + public static class TestData01 { + static final byte[] pk = decode(""" 00000002 00000005 00000004 0e975b10a6b33473d01baa138c155e81d7b7156b389b2a6a09d49f42c1ac4984 2d977e65fceb6bc80e06eace38ce0116 """); - msg = decode(""" + static final byte[] msg = decode(""" 312e20546869732069732061207465737420666f72204853532f4c4d53207768 6963682069732076657279206c6f6e6720616e64206e6f74206d65616e742074 6f207265616420627920612068756d616e206265696e672e """); - sig = decode(""" + static final byte[] sig = decode(""" 00000001 00000005 00000004 @@ -198,33 +185,22 @@ public void setup() throws Exception { 85f294d491c47fb90d3ce9046d2f05da6a723ac342a32154d1c18b465b49308f 41ca2f0475adf5ed46413766a6057bc810aeb6dd593691b84752b883c8a1a422 """); - } } - @State(Scope.Benchmark) - public static class test02 { - byte[] pk; - byte[] msg; - byte[] sig; - - @Param({"Test 2"}) - private String test; - - @Setup - public void setup() throws Exception { - pk = decode(""" + public static class TestData02 { + static final byte[] pk = decode(""" 00000002 00000006 00000003 ff466afe664c2581845b2c6af92aeb6e5c4dd15affc86c82ef4e807ad3c648a6 4561666c975fd9cb150d6c7acd6e577f """); - msg = decode(""" + static final byte[] msg = decode(""" 322e20546869732069732061207465737420666f72204853532f4c4d53207768 6963682069732076657279206c6f6e6720616e64206e6f74206d65616e742074 6f207265616420627920612068756d616e206265696e672e """); - sig = decode(""" + static final byte[] sig = decode(""" 00000001 00000003 00000003 @@ -355,34 +331,33 @@ public void setup() throws Exception { b4a0bb3b72197d2d5b2111da8647be1675983e8ed1c0d8ec7cada282dc698656 95f1e8806c7892b65fc17103ee3b5366b3fe31e57e653336be283962f488eaa5 """); - } } @State(Scope.Thread) - public static class verifier01 { + public static class Verifier01 { Signature v; @Setup - public void setup(test01 test) throws Exception { - v = getVerifier(test.pk); + public void setup() throws Exception { + v = getVerifier(TestData01.pk); } } @State(Scope.Thread) - public static class verifier02 { + public static class Verifier02 { Signature v; @Setup - public void setup(test02 test) throws Exception { - v = getVerifier(test.pk); + public void setup() throws Exception { + v = getVerifier(TestData02.pk); } } @Benchmark - public void verify01(test01 test, verifier01 v) throws Exception { - HSS.verify(v.v, test.pk, test.msg, test.sig); + public void verify01(Verifier01 v) throws Exception { + verify(v.v, TestData01.msg, TestData01.sig); } @Benchmark - public void verify02(test02 test, verifier02 v) throws Exception { - HSS.verify(v.v, test.pk, test.msg, test.sig); + public void verify02(Verifier02 v) throws Exception { + verify(v.v, TestData02.msg, TestData02.sig); } } diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java new file mode 100644 index 00000000000..3386039c62e --- /dev/null +++ b/test/micro/org/openjdk/bench/javax/crypto/full/KEMBench.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.javax.crypto.full; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.infra.Blackhole; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEM; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; + +public class KEMBench extends CryptoBase { + + public static final int SET_SIZE = 128; + + @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024" }) + private String algorithm; + + private KeyPair[] keys; + private byte[][] messages; + + private KEM kem; + + @Setup + public void setup() throws NoSuchAlgorithmException, InvalidKeyException { + kem = (prov == null) ? KEM.getInstance(algorithm) : KEM.getInstance(algorithm, prov); + KeyPairGenerator generator = (prov == null) ? KeyPairGenerator.getInstance(algorithm) : KeyPairGenerator.getInstance(algorithm, prov); + keys = new KeyPair[SET_SIZE]; + for (int i = 0; i < keys.length; i++) { + keys[i] = generator.generateKeyPair(); + } + messages = new byte[SET_SIZE][]; + for (int i = 0; i < messages.length; i++) { + KEM.Encapsulator enc = kem.newEncapsulator(keys[i].getPublic()); + KEM.Encapsulated encap = enc.encapsulate(); + messages[i] = encap.encapsulation(); + } + } + + @Benchmark + @OperationsPerInvocation(SET_SIZE) + public void encapsulate(Blackhole bh) throws InvalidKeyException { + for (KeyPair kp : keys) { + bh.consume(kem.newEncapsulator(kp.getPublic()).encapsulate().encapsulation()); + } + } + + @Benchmark + @OperationsPerInvocation(SET_SIZE) + public void decapsulate(Blackhole bh) throws InvalidKeyException, DecapsulateException { + for (int i = 0; i < messages.length; i++) { + bh.consume(kem.newDecapsulator(keys[i].getPrivate()).decapsulate(messages[i])); + } + } + +} diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java index 6d681604de3..58daff28d88 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/KeyPairGeneratorBench.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,9 @@ public void setup() throws NoSuchAlgorithmException { setupProvider(); generator = (prov == null) ? KeyPairGenerator.getInstance(algorithm) : KeyPairGenerator.getInstance(algorithm, prov); - generator.initialize(keyLength); + if (keyLength > 0) { // not all key pair generators allow the use of key length + generator.initialize(keyLength); + } } @Benchmark @@ -97,4 +99,23 @@ public static class XDH extends KeyPairGeneratorBench { @Param({"255", "448"}) private int keyLength; } + + public static class MLDSA extends KeyPairGeneratorBench { + + @Param({"ML-DSA-44", "ML-DSA-65", "ML-DSA-87" }) + private String algorithm; + + @Param({"0"}) // ML-DSA key length is not supported + private int keyLength; + } + + public static class MLKEM extends KeyPairGeneratorBench { + + @Param({"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024" }) + private String algorithm; + + @Param({"0"}) // ML-KEM key length is not supported + private int keyLength; + } + } diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/SignatureBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/SignatureBench.java index b94ebbfe6be..f47ce4e4814 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/SignatureBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/SignatureBench.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,9 @@ private String getKeyPairGeneratorName() { public void setup() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { setupProvider(); KeyPairGenerator kpg = KeyPairGenerator.getInstance(getKeyPairGeneratorName()); - kpg.initialize(keyLength); + if (keyLength > 0) { // not all key pair generators allow the use of key length + kpg.initialize(keyLength); + } KeyPair keys = kpg.generateKeyPair(); this.privateKey = keys.getPrivate(); this.publicKey = keys.getPublic(); @@ -136,4 +138,13 @@ public static class EdDSA extends SignatureBench { } + public static class MLDSA extends SignatureBench { + + @Param({"ML-DSA-44", "ML-DSA-65", "ML-DSA-87" }) + private String algorithm; + + @Param({"0"}) // ML-DSA key length is not supported + private int keyLength; + } + } diff --git a/test/micro/org/openjdk/bench/javax/crypto/small/HSSBench.java b/test/micro/org/openjdk/bench/javax/crypto/small/HSSBench.java new file mode 100644 index 00000000000..581f009591c --- /dev/null +++ b/test/micro/org/openjdk/bench/javax/crypto/small/HSSBench.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.javax.crypto.small; + +public class HSSBench extends org.openjdk.bench.javax.crypto.full.HSSBench { + +} diff --git a/test/micro/org/openjdk/bench/javax/crypto/small/KEMBench.java b/test/micro/org/openjdk/bench/javax/crypto/small/KEMBench.java new file mode 100644 index 00000000000..98796aabf2a --- /dev/null +++ b/test/micro/org/openjdk/bench/javax/crypto/small/KEMBench.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.javax.crypto.small; + +import org.openjdk.jmh.annotations.Param; + +public class KEMBench extends org.openjdk.bench.javax.crypto.full.KEMBench { + + @Param({"ML-KEM-768"}) + private String algorithm; + +} diff --git a/test/micro/org/openjdk/bench/javax/crypto/small/KeyPairGeneratorBench.java b/test/micro/org/openjdk/bench/javax/crypto/small/KeyPairGeneratorBench.java index 20313b2da97..5ac511637e6 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/small/KeyPairGeneratorBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/small/KeyPairGeneratorBench.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,4 +32,22 @@ public class KeyPairGeneratorBench extends org.openjdk.bench.javax.crypto.full.K @Param({"2048"}) private int keyLength; + public static class MLDSA extends KeyPairGeneratorBench { + + @Param({"ML-DSA-65"}) + private String algorithm; + + @Param({"0"}) // ML_DSA key length is not supported + private int keyLength; + } + + public static class MLKEM extends KeyPairGeneratorBench { + + @Param({"ML-KEM-768"}) + private String algorithm; + + @Param({"0"}) // ML-KEM key length is not supported + private int keyLength; + } + } diff --git a/test/micro/org/openjdk/bench/javax/crypto/small/SignatureBench.java b/test/micro/org/openjdk/bench/javax/crypto/small/SignatureBench.java index 3b49410d4d4..51e9d990573 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/small/SignatureBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/small/SignatureBench.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,4 +52,17 @@ public static class DSA extends SignatureBench { } + public static class MLDSA extends SignatureBench { + + @Param({"ML-DSA-65" }) + private String algorithm; + + @Param({"1024"}) + int dataSize; + + @Param({"0"}) // ML-DSA key length is not supported + private int keyLength; + } + + } diff --git a/test/micro/org/openjdk/bench/vm/compiler/ArrayFill.java b/test/micro/org/openjdk/bench/vm/compiler/ArrayFill.java index c86894a6ee5..90508ec79a9 100644 --- a/test/micro/org/openjdk/bench/vm/compiler/ArrayFill.java +++ b/test/micro/org/openjdk/bench/vm/compiler/ArrayFill.java @@ -46,7 +46,7 @@ @Measurement(iterations = 4, time = 2, timeUnit = TimeUnit.SECONDS) @Fork(value = 3) public class ArrayFill { - @Param("65536") private int size; + @Param({"7", "15", "65536"}) private int size; private byte[] ba; private short[] sa; diff --git a/test/micro/org/openjdk/bench/vm/compiler/DMBCheck.java b/test/micro/org/openjdk/bench/vm/compiler/DMBCheck.java new file mode 100644 index 00000000000..0552e52fb02 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/DMBCheck.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.vm.compiler; + +import java.util.concurrent.TimeUnit; +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.Group; +import org.openjdk.jmh.annotations.GroupThreads; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OperationsPerInvocation; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.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.infra.Blackhole; + +@BenchmarkMode(Mode.Throughput) +@State(Scope.Benchmark) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Warmup(iterations = 8, time = 4) +@Measurement(iterations = 6, time = 3) +public class DMBCheck { + + // The allocations of DoubleDMB$A and DoubleDMB$C + // will cause aarch64 dmb barrier instructions. + // The different latency of the dmb ish/ishst/ishld modes + // may make a noticeable difference in the benchmark results. + // These modes may be set by cpu defaults or XX options. + + class A { + + final String b = new String("Hi there"); + } + + class C { + + private A a; + + public A getA() { + if (a == null) { + a = new A(); + } + return a; + } + } + + static C c = null; + + @Setup + public void setup() { + c = new C(); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + void action(Blackhole b) throws Exception { + c = new C(); + + if (c.getA().b == null) { + throw new Exception("a should not be null"); + } + b.consume(c); + } + + @Benchmark + @Fork(value = 1, jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", "-XX:+AlwaysMergeDMB", "-XX:+IgnoreUnrecognizedVMOptions"}) + public void plusAlwaysMergeDMB(Blackhole b) throws Exception { + + action(b); + } + + @Benchmark + @Fork(value = 1, jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", "-XX:-AlwaysMergeDMB", "-XX:+IgnoreUnrecognizedVMOptions"}) + public void minusAlwaysMergeDMB(Blackhole b) throws Exception { + + action(b); + } + +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAutoAlignment.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAutoAlignment.java new file mode 100644 index 00000000000..ca02736424d --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAutoAlignment.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import java.lang.invoke.*; +import java.lang.foreign.*; + +import java.util.concurrent.TimeUnit; + +/** + * The purpose of this benchmark is to see the effect of automatic alignment in auto vectorization. + * + * Note: If you are interested in a nice visualization of load and store misalignment, please look + * at the benchmark {@link VectorAutoAlignmentVisualization}. + */ + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +@Fork(value = 1) +public abstract class VectorAutoAlignment { + @Param({"1024", "1152", "1280", "1408", "1536", "1664", "1792", "1920", "1984", "2048", "2114", + "2176", "2304", "2432", "2560", "2688", "2816", "2944", "3072", "3200", "3328", "3456", + "3584", "3712", "3840", "3968", "4096", "4224", "4352", "4480"}) + public int SIZE; + + private MemorySegment ms; + + @Setup + public void init() throws Throwable { + long totalSize = 4L * SIZE + 4L * SIZE; + long alignment = 4 * 1024; // 4k = page size + ms = Arena.ofAuto().allocate(totalSize, alignment); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void kernel1L1S(int offset_load, int offset_store) { + for (int i = 0; i < SIZE - /* slack for offset */ 32; i++) { + int v = ms.get(ValueLayout.JAVA_INT_UNALIGNED, 4L * i + 4L * offset_load + 4L * SIZE); + ms.set(ValueLayout.JAVA_INT_UNALIGNED, 4L * i + 4L * offset_store, v); + } + } + + @Benchmark + public void bench1L1S() throws Throwable { + // Go over all possible offsets, to get an average performance. + for (int offset_load = 0; offset_load < 32; offset_load++) { + for (int offset_store = 0; offset_store < 32; offset_store++) { + kernel1L1S(offset_load, offset_store); + } + } + } + + @Fork(value = 1, jvmArgs = { + "-XX:-UseSuperWord" + }) + public static class NoVectorization extends VectorAutoAlignment {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", "-XX:SuperWordAutomaticAlignment=0" + }) + public static class NoAutoAlign extends VectorAutoAlignment {} + + @Fork(value = 1, jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", "-XX:SuperWordAutomaticAlignment=1" + }) + public static class AlignStore extends VectorAutoAlignment {} + + + @Fork(value = 1, jvmArgs = { + "-XX:+UnlockDiagnosticVMOptions", "-XX:SuperWordAutomaticAlignment=2" + }) + public static class AlignLoad extends VectorAutoAlignment {} +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorAutoAlignmentVisualization.java b/test/micro/org/openjdk/bench/vm/compiler/VectorAutoAlignmentVisualization.java new file mode 100644 index 00000000000..04d04959d65 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorAutoAlignmentVisualization.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import java.lang.invoke.*; +import java.lang.foreign.*; + +import java.util.concurrent.TimeUnit; + +/* + + The purpose of this benchmark is to see the effect of automatic alignment in auto vectorization. + It is recommended to view the differing results when using SuperWordAutomaticAlignment. + + Without automatic alignment, i.e. SuperWordAutomaticAlignment=0, we may get a plot like below, for bench1L1S: + + OFFSET_STORE + ^ + | ###############|X + | ---------------0- <--- store aligned + | ##############X|# + | #############X#|# + | ############X##|# + | ###########X###|# + | ##########X####|# + | #########X#####|# + | ########X######|# + | #######X#######|# + | ######X########|# + | #####X#########|# + | ####X##########|# + | ###X###########|# + | ##X############|# + | #X#############|# + | X##############|# + ---OFFSET_LOAD ----> + + ^ + loads aligned | + + #: lowest performance, both misaligned and also relatively misaligned. + X: low performance, both misaligned but relatively aligned. + |: medium performance, load aligned, store misaligned. + -: good performance, load misaligned, store aligned. + 0: extreme performance, load and store aligned. + + Why is case "-" better than "|"? I.e. why are misaligned stores worse than misaligned loads? + Misalignment means that a load or store goes over a cache line, and is split into two loads + or stores. Most CPU's can execute 2 loads and 1 store per cycle, that is at least a partial + explanation why we are more limited on stores than loads. + No splitting, full alignment -> 1 load and 1 store + Split load, store aligned -> 2 loads and 1 store + Split store, load aligned -> 1 load and 2 stores + + The warmup and measurement time is relatively short, but the benchmark already takes 25 min + to go over the whole grid. This leads to some noise, but the pattern is very visible visually. + Hence: this benchmark is more for visualization than for regression testing. + For regression testing, please look at the related VectorAutoAlignment benchmark. + + If you want to turn the JMH results into a table, then you may use this Java code. + + import java.io.*; + import java.util.ArrayList; + + public class Extract { + record Cell(int x, int y, float t) {} + + public static void main(String[] args) throws Exception { + String fileName = args[0]; + System.out.println("Loading from file: " + fileName); + + ArrayList cells = new ArrayList<>(); + + try(BufferedReader br = new BufferedReader(new FileReader(fileName))) { + for(String line; (line = br.readLine()) != null; ) { + System.out.println(line); + String[] parts = line.split("[ ]+"); + if (parts.length != 11) { continue; } + System.out.println(String.join(" ", parts)); + int x = Integer.parseInt(parts[2]); + int y = Integer.parseInt(parts[3]); + float t = Float.parseFloat(parts[7]); + System.out.println("x=" + x + ", y=" + y + ", t=" + t); + cells.add(new Cell(x, y, t)); + } + } + + int maxX = cells.stream().mapToInt(c -> c.x).max().getAsInt(); + int maxY = cells.stream().mapToInt(c -> c.y).max().getAsInt(); + float[][] grid = new float[maxX + 1][maxY + 1]; + + for (Cell c : cells) { + grid[c.x][c.y] = c.t; + } + + for (int x = maxY; x >= 0; x--) { + for (int y = 0; y <= maxY; y++) { + System.out.print(String.format("%.5f ", grid[x][y])); + } + System.out.println(); + } + System.out.println("x-axis (->) LOAD_OFFSET"); + System.out.println("y-axis (up) STORE_OFFSET"); + } + } + + */ + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 2, time = 200, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 3, time = 200, timeUnit = TimeUnit.MILLISECONDS) +@Fork(value = 1) +public class VectorAutoAlignmentVisualization { + @Param({"2560"}) + public int SIZE; + + @Param({ "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", "26", "27", "28", "29", + "30", "31"}) + public int OFFSET_LOAD; + + @Param({ "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", "26", "27", "28", "29", + "30", "31"}) + public int OFFSET_STORE; + + @Param({"2000"}) + public int DISTANCE; + + // To get compile-time constants for OFFSET_LOAD, OFFSET_STORE, and DISTANCE + static final MutableCallSite MUTABLE_CONSTANT_OFFSET_LOAD = new MutableCallSite(MethodType.methodType(int.class)); + static final MethodHandle MUTABLE_CONSTANT_OFFSET_LOAD_HANDLE = MUTABLE_CONSTANT_OFFSET_LOAD.dynamicInvoker(); + static final MutableCallSite MUTABLE_CONSTANT_OFFSET_STORE = new MutableCallSite(MethodType.methodType(int.class)); + static final MethodHandle MUTABLE_CONSTANT_OFFSET_STORE_HANDLE = MUTABLE_CONSTANT_OFFSET_STORE.dynamicInvoker(); + static final MutableCallSite MUTABLE_CONSTANT_DISTANCE = new MutableCallSite(MethodType.methodType(int.class)); + static final MethodHandle MUTABLE_CONSTANT_DISTANCE_HANDLE = MUTABLE_CONSTANT_DISTANCE.dynamicInvoker(); + + private MemorySegment ms; + + @Setup + public void init() throws Throwable { + long totalSize = 4L * SIZE + 4L * DISTANCE; + long alignment = 4 * 1024; // 4k = page size + ms = Arena.ofAuto().allocate(totalSize, alignment); + + MethodHandle offset_load_con = MethodHandles.constant(int.class, OFFSET_LOAD); + MUTABLE_CONSTANT_OFFSET_LOAD.setTarget(offset_load_con); + MethodHandle offset_store_con = MethodHandles.constant(int.class, OFFSET_STORE); + MUTABLE_CONSTANT_OFFSET_STORE.setTarget(offset_store_con); + MethodHandle distance_con = MethodHandles.constant(int.class, DISTANCE); + MUTABLE_CONSTANT_DISTANCE.setTarget(distance_con); + } + + @CompilerControl(CompilerControl.Mode.INLINE) + private int offset_load_con() throws Throwable { + return (int) MUTABLE_CONSTANT_OFFSET_LOAD_HANDLE.invokeExact(); + } + + @CompilerControl(CompilerControl.Mode.INLINE) + private int offset_store_con() throws Throwable { + return (int) MUTABLE_CONSTANT_OFFSET_STORE_HANDLE.invokeExact(); + } + + @CompilerControl(CompilerControl.Mode.INLINE) + private int distance_con() throws Throwable { + return (int) MUTABLE_CONSTANT_DISTANCE_HANDLE.invokeExact(); + } + + @Benchmark + public void bench1L1S() throws Throwable { + int offset_load = offset_load_con(); + int offset_store = offset_store_con(); + int distance = distance_con(); + // Note: the offsets and distance are compile-time constants, which means + // we can already prove non-aliasing of loads and stores at compile + // time, which allows vectorization even without any aliasing runtime + // checks. + for (int i = 0; i < SIZE - /* slack for offset */ 32; i++) { + int v = ms.get(ValueLayout.JAVA_INT_UNALIGNED, 4L * i + 4L * offset_load + 4L * distance); + ms.set(ValueLayout.JAVA_INT_UNALIGNED, 4L * i + 4L * offset_store, v); + } + } +} diff --git a/test/setup_aot/TestSetupAOT.java b/test/setup_aot/TestSetupAOT.java index 89a6dd30c72..a46bd6e66c7 100644 --- a/test/setup_aot/TestSetupAOT.java +++ b/test/setup_aot/TestSetupAOT.java @@ -23,12 +23,17 @@ * questions. */ +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.spi.ToolProvider; import java.util.stream.Stream; import static java.util.stream.Collectors.*; @@ -36,7 +41,12 @@ // This program is executed by make/RunTests.gmk to support running HotSpot tests // in the "AOT mode", for example: // -// make test JTREG=AOT_JDK=true TEST=open/test/hotspot/jtreg/runtime/invokedynamic +// make test JTREG=AOT_JDK=onestep TEST=open/test/hotspot/jtreg/runtime/invokedynamic +// make test JTREG=AOT_JDK=twostep TEST=open/test/hotspot/jtreg/runtime/invokedynamic +// +// The onestep and twostep options specify whether the AOT cache is created with +// a single JVM command (java -XX:AOTMode=record -XX:AOTCacheOutput=jdk.aotcache ...) or +// two JVM commands (java -XX:AOTMode=record ...; java -XX:AOTMode=create -XX:AOTCache=jdk.aotcache ...) // // All JDK classes touched by this program will be stored into a customized AOT cache. // This is a larger set of classes than those stored in the JDK's default CDS archive. @@ -60,6 +70,42 @@ public static void main(String[] args) throws Throwable { LOGGER.log(Level.FINE, "Done"); } + static class ToolOutput { + ByteArrayOutputStream baos; + PrintStream ps; + String output; + + ToolOutput() throws Exception { + baos = new ByteArrayOutputStream(); + ps = new PrintStream(baos, true, StandardCharsets.UTF_8.name()); + } + void finish() throws Exception { + output = baos.toString(StandardCharsets.UTF_8.name()); + System.out.println(output); + } + + ToolOutput shouldContain(String... substrings) { + for (String s : substrings) { + if (!output.contains(s)) { + throw new RuntimeException("\"" + s + "\" missing from tool output"); + } + } + + return this; + } + + ToolOutput shouldMatch(String... regexps) { + for (String regexp : regexps) { + Pattern pattern = Pattern.compile(regexp, Pattern.MULTILINE); + if (!pattern.matcher(output).find()) { + throw new RuntimeException("Pattern \"" + regexp + "\" missing from tool output"); + } + } + + return this; + } + } + static void runJDKTools(String[] args) throws Throwable { String tmpDir = args[0]; System.out.println("Working Directory = " + System.getProperty("user.dir")); @@ -68,26 +114,33 @@ static void runJDKTools(String[] args) throws Throwable { // ------------------------------ // javac - execTool("javac", "--help"); + execTool("javac", "--help") + .shouldContain("Usage: javac "); JavacBenchApp.main(new String[] {"5"}); // ------------------------------ // javap - execTool("javap", "--help"); + execTool("javap", "--help") + .shouldContain("Show package/protected/public classes"); execTool("javap", "-c", "-private", "-v", "-verify", "java.lang.System", "java/util/stream/IntStream", - "jdk.internal.module.ModuleBootstrap"); + "jdk.internal.module.ModuleBootstrap") + .shouldContain("Compiled from \"System.java\"", + "public static java.io.Console console()"); // ------------------------------ // jlink String jlinkOutput = tmpDir + File.separator + "jlinkOutput"; - execTool("jlink", "--help"); - execTool("jlink", "--list-plugins"); + execTool("jlink", "--help") + .shouldContain("Compression to use in compressing resources"); + execTool("jlink", "--list-plugins") + .shouldContain("List of available plugins", + "--generate-cds-archive "); deleteAll(jlinkOutput); execTool("jlink", "--add-modules", "java.base", "--strip-debug", "--output", jlinkOutput); @@ -98,20 +151,27 @@ static void runJDKTools(String[] args) throws Throwable { String jarOutput = tmpDir + File.separator + "tmp.jar"; - execTool("jar", "--help"); + execTool("jar", "--help") + .shouldContain("--main-class=CLASSNAME"); deleteAll(jarOutput); - execTool("jar", "cvf", jarOutput, "TestSetupAOT.class"); - execTool("jar", "uvf", jarOutput, "TestSetupAOT.class"); - execTool("jar", "tvf", jarOutput); - execTool("jar", "--describe-module", "--file=" + jarOutput); + execTool("jar", "cvf", jarOutput, "TestSetupAOT.class") + .shouldContain("adding: TestSetupAOT.class"); + execTool("jar", "uvf", jarOutput, "TestSetupAOT.class") + .shouldContain("adding: TestSetupAOT.class"); + execTool("jar", "tvf", jarOutput) + .shouldContain("META-INF/MANIFEST.MF"); + execTool("jar", "--describe-module", "--file=" + jarOutput) + .shouldMatch("Unable to derive module descriptor for: .*tmp.jar"); deleteAll(jarOutput); // ------------------------------ // jdeps - execTool("jdeps", "--help"); - execTool("jdeps", "-v", "TestSetupAOT.class"); + execTool("jdeps", "--help") + .shouldContain("--ignore-missing-deps"); + execTool("jdeps", "-v", "TestSetupAOT.class") + .shouldContain("-> JavacBenchApp"); } static void deleteAll(String f) { @@ -129,7 +189,7 @@ static void deleteAll(File f) { f.delete(); } - static void execTool(String tool, String... args) throws Throwable { + static ToolOutput execTool(String tool, String... args) throws Throwable { System.out.println("== Running tool ======================================================"); System.out.print(tool); for (String s : args) { @@ -138,9 +198,13 @@ static void execTool(String tool, String... args) throws Throwable { System.out.println(); System.out.println("======================================================================"); + ToolOutput output = new ToolOutput(); ToolProvider t = ToolProvider.findFirst(tool) .orElseThrow(() -> new RuntimeException(tool + " not found")); - t.run(System.out, System.out, args); + t.run(output.ps, output.ps, args); + + output.finish(); + return output; }